]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/helpers/BlocklistHelper.kt
104d15c215c186fed91452062c4e6b99dd3a3cf6
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / helpers / BlocklistHelper.kt
1 /*
2  * Copyright © 2018-2019,2021-2022 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
5  *
6  * Privacy Browser Android is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser Android is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser Android.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacybrowser.helpers
21
22 import android.content.res.AssetManager
23
24 import java.io.BufferedReader
25 import java.io.IOException
26 import java.io.InputStreamReader
27 import java.util.ArrayList
28 import java.util.regex.Pattern
29
30 class BlocklistHelper {
31     companion object {
32         // Describe the schema of the string array in each entry of the resource requests array list.
33         const val REQUEST_DISPOSITION = 0
34         const val REQUEST_URL = 1
35         const val REQUEST_BLOCKLIST = 2
36         const val REQUEST_SUBLIST = 3
37         const val REQUEST_BLOCKLIST_ENTRIES = 4
38         const val REQUEST_BLOCKLIST_ORIGINAL_ENTRY = 5
39
40         // The request disposition options.
41         const val REQUEST_DEFAULT = "0"
42         const val REQUEST_ALLOWED = "1"
43         const val REQUEST_THIRD_PARTY = "2"
44         const val REQUEST_BLOCKED = "3"
45
46         // The whitelists.
47         const val MAIN_WHITELIST = "1"
48         const val FINAL_WHITELIST = "2"
49         const val DOMAIN_WHITELIST = "3"
50         const val DOMAIN_INITIAL_WHITELIST = "4"
51         const val DOMAIN_FINAL_WHITELIST = "5"
52         const val THIRD_PARTY_WHITELIST = "6"
53         const val THIRD_PARTY_DOMAIN_WHITELIST = "7"
54         const val THIRD_PARTY_DOMAIN_INITIAL_WHITELIST = "8"
55
56         // The blacklists.
57         const val MAIN_BLACKLIST = "9"
58         const val INITIAL_BLACKLIST = "10"
59         const val FINAL_BLACKLIST = "11"
60         const val DOMAIN_BLACKLIST = "12"
61         const val DOMAIN_INITIAL_BLACKLIST = "13"
62         const val DOMAIN_FINAL_BLACKLIST = "14"
63         const val DOMAIN_REGULAR_EXPRESSION_BLACKLIST = "15"
64         const val THIRD_PARTY_BLACKLIST = "16"
65         const val THIRD_PARTY_INITIAL_BLACKLIST = "17"
66         const val THIRD_PARTY_DOMAIN_BLACKLIST = "18"
67         const val THIRD_PARTY_DOMAIN_INITIAL_BLACKLIST = "19"
68         const val THIRD_PARTY_REGULAR_EXPRESSION_BLACKLIST = "20"
69         const val THIRD_PARTY_DOMAIN_REGULAR_EXPRESSION_BLACKLIST = "21"
70         const val REGULAR_EXPRESSION_BLACKLIST = "22"
71     }
72
73     fun parseBlocklist(assetManager: AssetManager, blocklistName: String): ArrayList<List<Array<String>>> {
74         // Initialize the header list.
75         val headers: MutableList<Array<String>> = ArrayList()  // 0.
76
77         // Initialize the whitelists.
78         val mainWhitelist: MutableList<Array<String>> = ArrayList()  // 1.
79         val finalWhitelist: MutableList<Array<String>> = ArrayList()  // 2.
80         val domainWhitelist: MutableList<Array<String>> = ArrayList()  // 3.
81         val domainInitialWhitelist: MutableList<Array<String>> = ArrayList()  // 4.
82         val domainFinalWhitelist: MutableList<Array<String>> = ArrayList()  // 5.
83         val thirdPartyWhitelist: MutableList<Array<String>> = ArrayList()  // 6.
84         val thirdPartyDomainWhitelist: MutableList<Array<String>> = ArrayList()  // 7.
85         val thirdPartyDomainInitialWhitelist: MutableList<Array<String>> = ArrayList()  // 8.
86
87         // Initialize the blacklists.
88         val mainBlacklist: MutableList<Array<String>> = ArrayList()  // 9.
89         val initialBlacklist: MutableList<Array<String>> = ArrayList()  // 10.
90         val finalBlacklist: MutableList<Array<String>> = ArrayList()  // 11.
91         val domainBlacklist: MutableList<Array<String>> = ArrayList()  // 12.
92         val domainInitialBlacklist: MutableList<Array<String>> = ArrayList()  // 13.
93         val domainFinalBlacklist: MutableList<Array<String>> = ArrayList()  // 14.
94         val domainRegularExpressionBlacklist: MutableList<Array<String>> = ArrayList()  // 15.
95         val thirdPartyBlacklist: MutableList<Array<String>> = ArrayList()  // 16.
96         val thirdPartyInitialBlacklist: MutableList<Array<String>> = ArrayList()  // 17.
97         val thirdPartyDomainBlacklist: MutableList<Array<String>> = ArrayList()  // 18.
98         val thirdPartyDomainInitialBlacklist: MutableList<Array<String>> = ArrayList()  // 19.
99         val regularExpressionBlacklist: MutableList<Array<String>> = ArrayList()  // 20.
100         val thirdPartyRegularExpressionBlacklist: MutableList<Array<String>> = ArrayList()  // 21.
101         val thirdPartyDomainRegularExpressionBlacklist: MutableList<Array<String>> = ArrayList()  // 22.
102
103         // Populate the blocklists.  The `try` is required by input stream reader.
104         try {
105             // Load the blocklist into a buffered reader.
106             val bufferedReader = BufferedReader(InputStreamReader(assetManager.open(blocklistName)))
107
108             // Create strings for storing the block list entries.
109             var blocklistEntry: String
110             var originalBlocklistEntry: String
111
112             // Parse the block list.
113             bufferedReader.forEachLine {
114                 // Store the original block list entry.
115                 originalBlocklistEntry = it
116
117                 // Remove any `^` from the block list entry.  Privacy Browser does not process them in the interest of efficiency.
118                 blocklistEntry = it.replace("^", "")
119
120                 // Parse the entry.
121                 if (blocklistEntry.contains("##") || blocklistEntry.contains("#?#") || blocklistEntry.contains("#@#") || blocklistEntry.startsWith("[")) {
122                     // Entries that contain `##`, `#?#`, and `#@#` are for hiding elements in the main page's HTML.  Entries that start with `[` describe the AdBlock compatibility level.
123                     // Do nothing.  Privacy Browser does not currently use these entries.
124
125                     //Log.i("Blocklists", "Not added: " + blocklistEntry);
126                 } else if (blocklistEntry.contains("\$csp=script-src")) {  // Ignore entries that contain `$csp=script-src`.
127                     // Do nothing.  It is uncertain what this directive is even supposed to mean, and it is blocking entire websites like androidcentral.com.  https://redmine.stoutner.com/issues/306.
128
129                     //Log.i("Blocklists", headers.get(1)[0] + " not added: " + originalBlocklistEntry);
130                 } else if (blocklistEntry.contains("\$websocket") || blocklistEntry.contains("\$third-party,websocket") || blocklistEntry.contains("\$script,websocket")) {
131                     // Ignore entries with `websocket`.
132                     // Do nothing.  Privacy Browser does not differentiate between websocket requests and other requests and these entries cause a lot of false positives.
133
134                     //Log.i("Blocklists", headers.get(1)[0] + " not added: " + originalBlocklistEntry);
135                 } else if (blocklistEntry.startsWith("!")) {  //  Comment entries.
136                     if (blocklistEntry.startsWith("! Version:")) {
137                         // Get the list version number.
138                         val listVersion = arrayOf(blocklistEntry.substring(11))
139
140                         // Store the list version in the headers list.
141                         headers.add(listVersion)
142                     }
143
144                     if (blocklistEntry.startsWith("! Title:")) {
145                         // Get the list title.
146                         val listTitle = arrayOf(blocklistEntry.substring(9))
147
148                         // Store the list title in the headers list.
149                         headers.add(listTitle)
150                     }
151
152                     //Log.i("Blocklists", "Not added: " + blocklistEntry);
153                 } else if (blocklistEntry.startsWith("@@")) {  // Entries that begin with `@@` are whitelists.
154                     // Remove the `@@`
155                     blocklistEntry = blocklistEntry.substring(2)
156
157                     // Strip out any initial `||`.  Privacy Browser doesn't differentiate items that only match against the end of the domain name.
158                     if (blocklistEntry.startsWith("||")) {
159                         blocklistEntry = blocklistEntry.substring(2)
160                     }
161
162                     if (blocklistEntry.contains("$")) {  // Filter entries.
163                         if (blocklistEntry.contains("~third-party")) {  // Ignore entries that contain `~third-party`.
164                             // Do nothing.
165
166                             //Log.i("Blocklists", headers.get(1)[0] + " not added: " + originalBlocklistEntry);
167                         } else if (blocklistEntry.contains("third-party")) {  // Third-party whitelist entries.
168                             if (blocklistEntry.contains("domain=")) {  // Third-party domain whitelist entries.
169                                 // Parse the entry.
170                                 var entry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
171                                 val filters = blocklistEntry.substring(blocklistEntry.indexOf("$") + 1)
172                                 var domains = filters.substring(filters.indexOf("domain=") + 7)
173
174                                 if (domains.contains("~")) {  // It is uncertain what a `~` domain means inside an `@@` entry.
175                                     // Do Nothing
176
177                                     //Log.i("Blocklists", headers.get(1)[0] + " not added: " + originalBlocklistEntry);
178                                 } else if (blocklistEntry.startsWith("|")) {  // Third-party domain initial whitelist entries.
179                                     // Strip out the initial `|`.
180                                     entry = entry.substring(1)
181
182                                     if (entry == "http://" || entry == "https://") {  // Ignore generic entries.
183                                         // Do nothing.  These entries are designed for filter options that Privacy Browser does not use.
184
185                                         //Log.i("Blocklists", headers.get(1)[0] + " not added: " + originalBlocklistEntry);
186                                     } else {  // Process third-party domain initial whitelist entries.
187                                         // Process each domain.
188                                         do {
189                                             // Create a string to keep track of the current domain.
190                                             var domain: String
191
192                                             if (domains.contains("|")) {  // There is more than one domain in the list.
193                                                 // Get the first domain from the list.
194                                                 domain = domains.substring(0, domains.indexOf("|"))
195
196                                                 // Remove the first domain from the list.
197                                                 domains = domains.substring(domains.indexOf("|") + 1)
198                                             } else {  // There is only one domain in the list.
199                                                 domain = domains
200                                             }
201
202                                             if (entry.contains("*")) {  // Process a third-party domain initial whitelist double entry.
203                                                 // Get the index of the wildcard.
204                                                 val wildcardIndex = entry.indexOf("*")
205
206                                                 // Split the entry into components.
207                                                 val firstEntry = entry.substring(0, wildcardIndex)
208                                                 val secondEntry = entry.substring(wildcardIndex + 1)
209
210                                                 // Create an entry string array.
211                                                 val domainDoubleEntry = arrayOf(domain, firstEntry, secondEntry, originalBlocklistEntry)
212
213                                                 // Add the entry to the whitelist.
214                                                 thirdPartyDomainInitialWhitelist.add(domainDoubleEntry)
215
216                                                 //Log.i("Blocklists", headers.get(1)[0] + " third-party domain initial whitelist added: " + domain + " , " + firstEntry + " , " + secondEntry +
217                                                 //        "  -  " + originalBlocklistEntry);
218                                             } else {  // Process a third-party domain initial whitelist single entry.
219                                                 // Create a domain entry string array.
220                                                 val domainEntry = arrayOf(domain, entry, originalBlocklistEntry)
221
222                                                 // Add the entry to the third party domain initial whitelist.
223                                                 thirdPartyDomainInitialWhitelist.add(domainEntry)
224
225                                                 //Log.i("Blocklists", headers.get(1)[0] + " third-party domain initial whitelist added: " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
226                                             }
227                                         } while (domains.contains("|"))
228                                     }
229                                 } else {  // Third-party domain entries.
230                                     // Process each domain.
231                                     do {
232                                         // Create a string to keep track of the current domain.
233                                         var domain: String
234
235                                         if (domains.contains("|")) {  // three is more than one domain in the list.
236                                             // Get the first domain from the list.
237                                             domain = domains.substring(0, domains.indexOf("|"))
238
239                                             // Remove the first domain from the list.
240                                             domains = domains.substring(domains.indexOf("|") + 1)
241                                         } else {  // There is only one domain in the list.
242                                             domain = domains
243                                         }
244
245                                         // Remove any trailing `*` from the entry.
246                                         if (entry.endsWith("*")) {
247                                             entry = entry.substring(0, entry.length - 1)
248                                         }
249
250                                         if (entry.contains("*")) {  // Process a third-party domain double entry.
251                                             // Get the index of the wildcard.
252                                             val wildcardIndex = entry.indexOf("*")
253
254                                             // Split the entry into components.
255                                             val firstEntry = entry.substring(0, wildcardIndex)
256                                             val secondEntry = entry.substring(wildcardIndex + 1)
257
258                                             // Create an entry string array.
259                                             val domainDoubleEntry = arrayOf(domain, firstEntry, secondEntry, originalBlocklistEntry)
260
261                                             // Add the entry to the whitelist.
262                                             thirdPartyDomainWhitelist.add(domainDoubleEntry)
263
264                                             //Log.i("Blocklists", headers.get(1)[0] + " third-party domain whitelist added: " + domain + " , " + firstEntry + " , " + secondEntry + "  -  " +
265                                             //        originalBlocklistEntry);
266                                         } else {  // Process a third-party domain single entry.
267                                             // Create an entry string array.
268                                             val domainEntry = arrayOf(domain, entry, originalBlocklistEntry)
269
270                                             // Add the entry to the whitelist.
271                                             thirdPartyDomainWhitelist.add(domainEntry)
272
273                                             //Log.i("Blocklists", headers.get(1)[0] + " third-party domain whitelist added: " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
274                                         }
275                                     } while (domains.contains("|"))
276                                 }
277                             } else {  // Process third-party whitelist entries.
278                                 // Parse the entry
279                                 val entry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
280
281                                 if (entry.contains("*")) {  // There are two or more entries.
282                                     // Get the index of the wildcard.
283                                     val wildcardIndex = entry.indexOf("*")
284
285                                     // Split the entry into components.
286                                     val firstEntry = entry.substring(0, wildcardIndex)
287                                     val secondEntry = entry.substring(wildcardIndex + 1)
288
289                                     if (secondEntry.contains("*")) {  // There are three or more entries.
290                                         // Get the index of the wildcard.
291                                         val secondWildcardIndex = secondEntry.indexOf("*")
292
293                                         // Split the entry into components.
294                                         val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
295                                         val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
296
297                                         if (thirdEntry.contains("*")) {  // There are four or more entries.
298                                             // Get the index of the wildcard.
299                                             val thirdWildcardIndex = thirdEntry.indexOf("*")
300
301                                             // Split the entry into components.
302                                             val realThirdEntry = thirdEntry.substring(0, thirdWildcardIndex)
303                                             val fourthEntry = thirdEntry.substring(thirdWildcardIndex + 1)
304
305                                             if (fourthEntry.contains("*")) {  // Process a third-party whitelist quintuple entry.
306                                                 // Get the index of the wildcard.
307                                                 val fourthWildcardIndex = fourthEntry.indexOf("*")
308
309                                                 // Split the entry into components.
310                                                 val realFourthEntry = fourthEntry.substring(0, fourthWildcardIndex)
311                                                 val fifthEntry = fourthEntry.substring(fourthWildcardIndex + 1)
312
313                                                 // Create an entry string array.
314                                                 val quintupleEntry = arrayOf(firstEntry, realSecondEntry, realThirdEntry, realFourthEntry, fifthEntry, originalBlocklistEntry)
315
316                                                 // Add the entry to the whitelist.
317                                                 thirdPartyWhitelist.add(quintupleEntry)
318
319                                                 //Log.i("Blocklists", headers.get(1)[0] + " third-party whitelist added: " + firstEntry + " , " + realSecondEntry + " , " + realThirdEntry + " , " +
320                                                 //        realFourthEntry + " , " + fifthEntry + "  -  " + originalBlocklistEntry);
321                                             } else {  // Process a third-party whitelist quadruple entry.
322                                                 // Create an entry string array.
323                                                 val quadrupleEntry = arrayOf(firstEntry, realSecondEntry, realThirdEntry, fourthEntry, originalBlocklistEntry)
324
325                                                 // Add the entry to the whitelist.
326                                                 thirdPartyWhitelist.add(quadrupleEntry)
327
328                                                 //Log.i("Blocklists", headers.get(1)[0] + " third-party whitelist added: " + firstEntry + " , " + realSecondEntry + " , " + realThirdEntry + " , " +
329                                                 //        fourthEntry + "  -  " + originalBlocklistEntry);
330                                             }
331                                         } else {  // Process a third-party whitelist triple entry.
332                                             // Create an entry string array.
333                                             val tripleEntry = arrayOf(firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
334
335                                             // Add the entry to the whitelist.
336                                             thirdPartyWhitelist.add(tripleEntry)
337
338                                             //Log.i("Blocklists", headers.get(1)[0] + " third-party whitelist added: " + firstEntry + " , " + realSecondEntry + " , " + thirdEntry + "  -  " +
339                                             //        originalBlocklistEntry);
340                                         }
341                                     } else {  // Process a third-party whitelist double entry.
342                                         // Create an entry string array.
343                                         val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
344
345                                         // Add the entry to the whitelist.
346                                         thirdPartyWhitelist.add(doubleEntry)
347
348                                         //Log.i("Blocklists", headers.get(1)[0] + " third-party whitelist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
349                                     }
350                                 } else {  // Process a third-party whitelist single entry.
351                                     // Create an entry string array.
352                                     val singleEntry = arrayOf(entry, originalBlocklistEntry)
353
354                                     // Add the entry to the whitelist.
355                                     thirdPartyWhitelist.add(singleEntry)
356
357                                     //Log.i("Blocklists", headers.get(1)[0] + " third-party domain whitelist added: " + entry + "  -  " + originalBlocklistEntry);
358                                 }
359                             }
360                         } else if (blocklistEntry.contains("domain=")) {  // Process domain whitelist entries.
361                             // Parse the entry
362                             var entry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
363                             val filters = blocklistEntry.substring(blocklistEntry.indexOf("$") + 1)
364                             var domains = filters.substring(filters.indexOf("domain=") + 7)
365
366                             if (entry.startsWith("|")) {  // Initial domain whitelist entries.
367                                 // Strip the initial `|`.
368                                 entry = entry.substring(1)
369
370                                 if (entry == "http://" || entry == "https://") {  // Ignore generic entries.
371                                     // Do nothing.  These entries are designed for filter options that Privacy Browser does not use.
372
373                                     //Log.i("Blocklists", headers.get(1)[0] + " not added: " + originalBlocklistEntry);
374                                 } else {  // Initial domain whitelist entry.
375                                     // Process each domain.
376                                     do {
377                                         // Create a string to keep track of the current domain.
378                                         var domain: String
379
380                                         if (domains.contains("|")) {  // There is more than one domain in the list.
381                                             // Get the first domain from the list.
382                                             domain = domains.substring(0, domains.indexOf("|"))
383
384                                             // Remove the first domain from the list.
385                                             domains = domains.substring(domains.indexOf("|") + 1)
386                                         } else {  // There is only one domain in the list.
387                                             domain = domains
388                                         }
389
390                                         if (entry.contains("*")) {  // There are two or more entries.
391                                             // Get the index of the wildcard.
392                                             val wildcardIndex = entry.indexOf("*")
393
394                                             // Split the entry into components.
395                                             val firstEntry = entry.substring(0, wildcardIndex)
396                                             val secondEntry = entry.substring(wildcardIndex + 1)
397
398                                             if (secondEntry.contains("*")) {  // Process a domain initial triple entry.
399                                                 // Get the index of the wildcard.
400                                                 val secondWildcardIndex = secondEntry.indexOf("*")
401
402                                                 // Split the entry into components.
403                                                 val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
404                                                 val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
405
406                                                 // Create an entry string array.
407                                                 val domainTripleEntry = arrayOf(domain, firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
408
409                                                 // Add the entry to the whitelist.
410                                                 domainInitialWhitelist.add(domainTripleEntry)
411
412                                                 //Log.i("Blocklists", headers.get(1)[0] + " domain initial whitelist entry added: " + domain + " , " + firstEntry + " , " + realSecondEntry + " , " +
413                                                 //        thirdEntry + "  -  " + originalBlocklistEntry);
414                                             } else {  // Process a domain initial double entry.
415                                                 // Create an entry string array.
416                                                 val domainDoubleEntry = arrayOf(domain, firstEntry, secondEntry, originalBlocklistEntry)
417
418                                                 // Add the entry to the whitelist.
419                                                 domainInitialWhitelist.add(domainDoubleEntry)
420
421                                                 //Log.i("Blocklists", headers.get(1)[0] + " domain initial whitelist entry added: " + domain + " , " + firstEntry + " , " + secondEntry + "  -  " +
422                                                 //        originalBlocklistEntry);
423                                             }
424                                         } else {  // Process a domain initial single entry.
425                                             // Create an entry string array.
426                                             val domainEntry = arrayOf(domain, entry, originalBlocklistEntry)
427
428                                             // Add the entry to the whitelist.
429                                             domainInitialWhitelist.add(domainEntry)
430
431                                             //Log.i("Blocklists", headers.get(1)[0] + " domain initial whitelist entry added: " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
432                                         }
433                                     } while (domains.contains("|"))
434                                 }
435                             } else if (entry.endsWith("|")) {  // Final domain whitelist entries.
436                                 // Strip the `|` from the end of the entry.
437                                 entry = entry.substring(0, entry.length - 1)
438
439                                 // Process each domain.
440                                 do {
441                                     // Create a string to keep track of the current domain.
442                                     var domain: String
443
444                                     if (domains.contains("|")) {  // There is more than one domain in the list.
445                                         // Get the first domain from the list.
446                                         domain = domains.substring(0, domains.indexOf("|"))
447
448                                         // Remove the first domain from the list.
449                                         domains = domains.substring(domains.indexOf("|") + 1)
450                                     } else {  // There is only one domain in the list.
451                                         domain = domains
452                                     }
453
454                                     if (entry.contains("*")) {  // Process a domain final whitelist double entry.
455                                         // Get the index of the wildcard.
456                                         val wildcardIndex = entry.indexOf("*")
457
458                                         // Split the entry into components.
459                                         val firstEntry = entry.substring(0, wildcardIndex)
460                                         val secondEntry = entry.substring(wildcardIndex + 1)
461
462                                         // Create an entry string array.
463                                         val domainDoubleEntry = arrayOf(domain, firstEntry, secondEntry, originalBlocklistEntry)
464
465                                         // Add the entry to the whitelist.
466                                         domainFinalWhitelist.add(domainDoubleEntry)
467
468                                         //Log.i("Blocklists", headers.get(1)[0] + " domain final whitelist added: " + domain + " , " + firstEntry + " , " + secondEntry + "  -  " +
469                                         //        originalBlocklistEntry);
470                                     } else {  // Process a domain final whitelist single entry.
471                                         // create an entry string array.
472                                         val domainEntry = arrayOf(domain, entry, originalBlocklistEntry)
473
474                                         // Add the entry to the whitelist.
475                                         domainFinalWhitelist.add(domainEntry)
476
477                                         //Log.i("Blocklists", headers.get(1)[0] + " domain final whitelist added: " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
478                                     }
479                                 } while (domains.contains("|"))
480                             } else {  // Standard domain whitelist entries with filters.
481                                 if (domains.contains("~")) {  // It is uncertain what a `~` domain means inside an `@@` entry.
482                                     // Do Nothing
483
484                                     //Log.i("Blocklists", headers.get(1)[0] + " not added: " + originalBlocklistEntry);
485                                 } else {
486                                     // Process each domain.
487                                     do {
488                                         // Create a string to keep track of the current domain.
489                                         var domain: String
490
491                                         if (domains.contains("|")) {  // There is more than one domain in the list.
492                                             // Get the first domain from the list.
493                                             domain = domains.substring(0, domains.indexOf("|"))
494
495                                             // Remove the first domain from the list.
496                                             domains = domains.substring(domains.indexOf("|") + 1)
497                                         } else {  // There is only one domain in the list.
498                                             domain = domains
499                                         }
500
501                                         if (entry.contains("*")) {  // There are two or more entries.
502                                             // Get the index of the wildcard.
503                                             val wildcardIndex = entry.indexOf("*")
504
505                                             // Split the entry into components.
506                                             val firstEntry = entry.substring(0, wildcardIndex)
507                                             val secondEntry = entry.substring(wildcardIndex + 1)
508
509                                             if (secondEntry.contains("*")) {  // There are three or more entries.
510                                                 // Get the index of the wildcard.
511                                                 val secondWildcardIndex = secondEntry.indexOf("*")
512
513                                                 // Split the entry into components.
514                                                 val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
515                                                 val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
516
517                                                 if (thirdEntry.contains("*")) {  // Process a domain whitelist quadruple entry.
518                                                     // Get the index of the wildcard.
519                                                     val thirdWildcardIndex = thirdEntry.indexOf("*")
520
521                                                     // Split the entry into components.
522                                                     val realThirdEntry = thirdEntry.substring(0, thirdWildcardIndex)
523                                                     val fourthEntry = thirdEntry.substring(thirdWildcardIndex + 1)
524
525                                                     // Create an entry string array.
526                                                     val domainQuadrupleEntry = arrayOf(domain, firstEntry, realSecondEntry, realThirdEntry, fourthEntry, originalBlocklistEntry)
527
528                                                     // Add the entry to the whitelist.
529                                                     domainWhitelist.add(domainQuadrupleEntry)
530
531                                                     //Log.i("Blocklists", headers.get(1)[0] + " domain whitelist added : " + domain + " , " + firstEntry + " , " + realSecondEntry + " , " +
532                                                     //        realThirdEntry + " , " + fourthEntry + "  -  " + originalBlocklistEntry);
533                                                 } else {  // Process a domain whitelist triple entry.
534                                                     // Create an entry string array.
535                                                     val domainTripleEntry = arrayOf(domain, firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
536
537                                                     // Add the entry to the whitelist.
538                                                     domainWhitelist.add(domainTripleEntry)
539
540                                                     //Log.i("Blocklists", headers.get(1)[0] + " domain whitelist added : " + domain + " , " + firstEntry + " , " + realSecondEntry + " , " +
541                                                     //        thirdEntry + "  -  " + originalBlocklistEntry);
542                                                 }
543                                             } else {  // Process a domain whitelist double entry.
544                                                 // Create an entry string array.
545                                                 val domainDoubleEntry = arrayOf(domain, firstEntry, secondEntry, originalBlocklistEntry)
546
547                                                 // Add the entry to the whitelist.
548                                                 domainWhitelist.add(domainDoubleEntry)
549
550                                                 //Log.i("Blocklists", headers.get(1)[0] + " domain whitelist added : " + domain + " , " + firstEntry + " , " + secondEntry + "  -  " +
551                                                 //        originalBlocklistEntry);
552                                             }
553                                         } else {  // Process a domain whitelist single entry.
554                                             // Create an entry string array.
555                                             val domainEntry = arrayOf(domain, entry, originalBlocklistEntry)
556
557                                             // Add the entry to the whitelist.
558                                             domainWhitelist.add(domainEntry)
559
560                                             //Log.i("Blocklists", headers.get(1)[0] + " domain whitelist added : " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
561                                         }
562                                     } while (domains.contains("|"))
563                                 }
564                             }
565                         }  // Ignore all other filter entries.
566                     } else if (blocklistEntry.endsWith("|")) {  // Final whitelist entries.
567                         // Remove the final `|` from the entry.
568                         val entry = blocklistEntry.substring(0, blocklistEntry.length - 1)
569
570                         if (entry.contains("*")) {  // Process a final whitelist double entry
571                             // Get the index of the wildcard.
572                             val wildcardIndex = entry.indexOf("*")
573
574                             // split the entry into components.
575                             val firstEntry = entry.substring(0, wildcardIndex)
576                             val secondEntry = entry.substring(wildcardIndex + 1)
577
578                             // Create an entry string array.
579                             val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
580
581                             // Add the entry to the whitelist.
582                             finalWhitelist.add(doubleEntry)
583
584                             //Log.i("Blocklists", headers.get(1)[0] + " final whitelist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
585                         } else {  // Process a final whitelist single entry.
586                             // Create an entry string array.
587                             val singleEntry = arrayOf(entry, originalBlocklistEntry)
588
589                             // Add the entry to the whitelist.
590                             finalWhitelist.add(singleEntry)
591
592                             //Log.i("Blocklists", headers.get(1)[0] + " final whitelist added: " + entry + "  -  " + originalBlocklistEntry);
593                         }
594                     } else {  // Main whitelist entries.
595                         if (blocklistEntry.contains("*")) {  // There are two or more entries.
596                             // Get the index of the wildcard.
597                             val wildcardIndex = blocklistEntry.indexOf("*")
598
599                             // Split the entry into components.
600                             val firstEntry = blocklistEntry.substring(0, wildcardIndex)
601                             val secondEntry = blocklistEntry.substring(wildcardIndex + 1)
602
603                             if (secondEntry.contains("*")) {  // Process a main whitelist triple entry.
604                                 // Get the index of the wildcard.
605                                 val secondWildcardIndex = secondEntry.indexOf("*")
606
607                                 // Split the entry into components.
608                                 val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
609                                 val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
610
611                                 // Create an entry string array.
612                                 val tripleEntry = arrayOf(firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
613
614                                 // Add the entry to the whitelist.
615                                 mainWhitelist.add(tripleEntry)
616
617                                 //Log.i("Blocklists", headers.get(1)[0] + " main whitelist added: " + firstEntry + " , " + realSecondEntry + " , " + thirdEntry + "  -  " + originalBlocklistEntry);
618                             } else {  // Process a main whitelist double entry.
619                                 // Create an entry string array.
620                                 val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
621
622                                 // Add the entry to the whitelist.
623                                 mainWhitelist.add(doubleEntry)
624
625                                 //Log.i("Blocklists", headers.get(1)[0] + " main whitelist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
626                             }
627                         } else {  // Process a main whitelist single entry.
628                             // Create an entry string array.
629                             val singleEntry = arrayOf(blocklistEntry, originalBlocklistEntry)
630
631                             // Add the entry to the whitelist.
632                             mainWhitelist.add(singleEntry)
633
634                             //Log.i("Blocklists", headers.get(1)[0] + " main whitelist added: " + blocklistEntry + "  -  " + originalBlocklistEntry);
635                         }
636                     }
637                 } else if (blocklistEntry.endsWith("|")) {  // Final blacklist entries.
638                     // Strip out the final "|"
639                     var entry = blocklistEntry.substring(0, blocklistEntry.length - 1)
640
641                     // Strip out any initial `||`.  They are redundant in this case because the blocklist entry is being matched against the end of the URL.
642                     if (entry.startsWith("||")) {
643                         entry = entry.substring(2)
644                     }
645
646                     if (entry.contains("*")) {  // Process a final blacklist double entry.
647                         // Get the index of the wildcard.
648                         val wildcardIndex = entry.indexOf("*")
649
650                         // Split the entry into components.
651                         val firstEntry = entry.substring(0, wildcardIndex)
652                         val secondEntry = entry.substring(wildcardIndex + 1)
653
654                         // Create an entry string array.
655                         val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
656
657                         // Add the entry to the blacklist.
658                         finalBlacklist.add(doubleEntry)
659
660                         //Log.i("Blocklists", headers.get(1)[0] + " final blacklist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
661                     } else {  // Process a final blacklist single entry.
662                         // create an entry string array.
663                         val singleEntry = arrayOf(entry, originalBlocklistEntry)
664
665                         // Add the entry to the blacklist.
666                         finalBlacklist.add(singleEntry)
667
668                         //Log.i("Blocklists", headers.get(1)[0] + " final blacklist added: " + entry + "  -  " + originalBlocklistEntry);
669                     }
670                 } else if (blocklistEntry.contains("$")) {  // Entries with filter options.
671                     // Strip out any initial `||`.  These will be treated like any other entry.
672                     if (blocklistEntry.startsWith("||")) {
673                         blocklistEntry = blocklistEntry.substring(2)
674                     }
675
676                     if (blocklistEntry.contains("third-party")) {  // Third-party entries.
677                         if (blocklistEntry.contains("~third-party")) {  // Third-party filter whitelist entries.
678                             // Do not process these whitelist entries.  They are designed to combine with block filters that Privacy Browser doesn't use, like `subdocument` and `xmlhttprequest`.
679
680                             //Log.i("Blocklists", headers.get(1)[0] + " not added: " + originalBlocklistEntry);
681                         } else if (blocklistEntry.contains("domain=")) {  // Third-party domain entries.
682                             if (blocklistEntry.startsWith("|")) {  // Third-party domain initial entries.
683                                 // Strip the initial `|`.
684                                 blocklistEntry = blocklistEntry.substring(1)
685
686                                 // Parse the entry
687                                 val entry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
688                                 val filters = blocklistEntry.substring(blocklistEntry.indexOf("$") + 1)
689                                 var domains = filters.substring(filters.indexOf("domain=") + 7)
690
691                                 if (entry == "http:" || entry == "https:" || entry == "http://" || entry == "https://") {  // Ignore generic entries.
692                                     // Do nothing.  These entries will almost entirely disable the website.
693                                     // Often the original entry blocks filter options like `$script`, which Privacy Browser does not differentiate.
694
695                                     //Log.i("Blocklists", headers.get(1)[0] + " not added: " + originalBlocklistEntry);
696                                 } else {  // Third-party domain initial entries.
697                                     // Process each domain.
698                                     do {
699                                         // Create a string to keep track of the current domain.
700                                         var domain: String
701
702                                         if (domains.contains("|")) {  // There is more than one domain in the list.
703                                             // Get the first domain from the list.
704                                             domain = domains.substring(0, domains.indexOf("|"))
705
706                                             // Remove the first domain from the list.
707                                             domains = domains.substring(domains.indexOf("|") + 1)
708                                         } else {  // There is only one domain in the list.
709                                             domain = domains
710                                         }
711
712                                         if (entry.contains("*")) {  // Three are two or more entries.
713                                             // Get the index of the wildcard.
714                                             val wildcardIndex = entry.indexOf("*")
715
716                                             // Split the entry into components.
717                                             val firstEntry = entry.substring(0, wildcardIndex)
718                                             val secondEntry = entry.substring(wildcardIndex + 1)
719
720                                             if (secondEntry.contains("*")) {  // Process a third-party domain initial blacklist triple entry.
721                                                 // Get the index of the wildcard.
722                                                 val secondWildcardIndex = secondEntry.indexOf("*")
723
724                                                 // Split the entry into components.
725                                                 val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
726                                                 val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
727
728                                                 // Create an entry string array.
729                                                 val tripleDomainEntry = arrayOf(domain, firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
730
731                                                 // Add the entry to the blacklist.
732                                                 thirdPartyDomainInitialBlacklist.add(tripleDomainEntry)
733
734                                                 //Log.i("Blocklists", headers.get(1)[0] + " third-party domain initial blacklist added: " + domain + " , " + firstEntry + " , " + realSecondEntry +
735                                                 //        " , " + thirdEntry + "  -  " + originalBlocklistEntry);
736                                             } else {  // Process a third-party domain initial blacklist double entry.
737                                                 // Create an entry string array.
738                                                 val doubleDomainEntry = arrayOf(domain, firstEntry, secondEntry, originalBlocklistEntry)
739
740                                                 // Add the entry to the blacklist.
741                                                 thirdPartyDomainInitialBlacklist.add(doubleDomainEntry)
742
743                                                 //Log.i("Blocklists", headers.get(1)[0] + " third-party domain initial blacklist added: " + domain + " , " + firstEntry + " , " + secondEntry +
744                                                 //        "  -  " + originalBlocklistEntry);
745                                             }
746                                         } else {  // Process a third-party domain initial blacklist single entry.
747                                             // Create an entry string array.
748                                             val singleEntry = arrayOf(domain, entry, originalBlocklistEntry)
749
750                                             // Add the entry to the blacklist.
751                                             thirdPartyDomainInitialBlacklist.add(singleEntry)
752
753                                             //Log.i("Blocklists", headers.get(1)[0] + " third-party domain initial blacklist added: " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
754                                         }
755                                     } while (domains.contains("|"))
756                                 }
757                             } else if (blocklistEntry.contains("\\")) {  // Process a third-party domain blacklist regular expression.
758                                 // Parse the entry.  At least one regular expression in this entry contains `$`, so the parser uses `/$`.
759                                 val entry = blocklistEntry.substring(0, blocklistEntry.indexOf("/$") + 1)
760                                 val filters = blocklistEntry.substring(blocklistEntry.indexOf("/$") + 2)
761                                 var domains = filters.substring(filters.indexOf("domain=") + 7)
762
763                                 // Process each domain.
764                                 do {
765                                     // Create a string to keep track of the current domain.
766                                     var domain: String
767
768                                     if (domains.contains("|")) {  // There is more than one domain in the list.
769                                         // Get the first domain from the list.
770                                         domain = domains.substring(0, domains.indexOf("|"))
771
772                                         // Remove the first domain from the list.
773                                         domains = domains.substring(domains.indexOf("|") + 1)
774                                     } else {  // There is only one domain in the list.
775                                         domain = domains
776                                     }
777
778                                     // Create an entry string array.
779                                     val domainEntry = arrayOf(domain, entry, originalBlocklistEntry)
780
781                                     // Add the entry to the blacklist.
782                                     thirdPartyDomainRegularExpressionBlacklist.add(domainEntry)
783
784                                     //Log.i("Blocklists", headers.get(1)[0] + " third-party domain regular expression blacklist added: " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
785                                 } while (domains.contains("|"))
786                             } else {  // Third-party domain entries.
787                                 // Parse the entry
788                                 var entry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
789                                 val filters = blocklistEntry.substring(blocklistEntry.indexOf("$") + 1)
790                                 var domains = filters.substring(filters.indexOf("domain=") + 7)
791
792                                 // Strip any trailing "*" from the entry.
793                                 if (entry.endsWith("*")) {
794                                     entry = entry.substring(0, entry.length - 1)
795                                 }
796
797                                 // Track if any third-party whitelist filters are applied.
798                                 var whitelistDomain = false
799
800                                 // Process each domain.
801                                 do {
802                                     // Create a string to keep track of the current domain.
803                                     var domain: String
804
805                                     if (domains.contains("|")) {  // There is more than one domain in the list.
806                                         // Get the first domain from the list.
807                                         domain = domains.substring(0, domains.indexOf("|"))
808
809                                         // Remove the first domain from the list.
810                                         domains = domains.substring(domains.indexOf("|") + 1)
811                                     } else {  // The is only one domain in the list.
812                                         domain = domains
813                                     }
814
815                                     // Differentiate between blocklist domains and whitelist domains.
816                                     if (domain.startsWith("~")) {  // Whitelist third-party domain entry.
817                                         // Strip the initial `~`.
818                                         domain = domain.substring(1)
819
820                                         // Set the whitelist domain flag.
821                                         whitelistDomain = true
822
823                                         if (entry.contains("*")) {  // Process a third-party domain whitelist double entry.
824                                             // Get the index of the wildcard.
825                                             val wildcardIndex = entry.indexOf("*")
826
827                                             // Split the entry into components.
828                                             val firstEntry = entry.substring(0, wildcardIndex)
829                                             val secondEntry = entry.substring(wildcardIndex + 1)
830
831                                             // Create an entry string array.
832                                             val domainDoubleEntry = arrayOf(domain, firstEntry, secondEntry, originalBlocklistEntry)
833
834                                             // Add the entry to the whitelist.
835                                             thirdPartyDomainWhitelist.add(domainDoubleEntry)
836
837                                             //Log.i("Blocklists", headers.get(1)[0] + " third-party domain whitelist added: " + domain + " , " + firstEntry + " , " + secondEntry + "  -  " +
838                                             //        originalBlocklistEntry);
839                                         } else {  // Process a third-party domain whitelist single entry.
840                                             // Create an entry string array.
841                                             val domainEntry = arrayOf(domain, entry, originalBlocklistEntry)
842
843                                             // Add the entry to the whitelist.
844                                             thirdPartyDomainWhitelist.add(domainEntry)
845
846                                             //Log.i("Blocklists", headers.get(1)[0] + " third-party domain whitelist added: " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
847                                         }
848                                     } else {  // Third-party domain blacklist entries.
849                                         if (entry.contains("*")) {  // Process a third-party domain blacklist double entry.
850                                             // Get the index of the wildcard.
851                                             val wildcardIndex = entry.indexOf("*")
852
853                                             // Split the entry into components.
854                                             val firstEntry = entry.substring(0, wildcardIndex)
855                                             val secondEntry = entry.substring(wildcardIndex + 1)
856
857                                             // Create an entry string array.
858                                             val domainDoubleEntry = arrayOf(domain, firstEntry, secondEntry, originalBlocklistEntry)
859
860                                             // Add the entry to the blacklist
861                                             thirdPartyDomainBlacklist.add(domainDoubleEntry)
862
863                                             //Log.i("Blocklists", headers.get(1)[0] + " third-party domain blacklist added: " + domain + " , " + firstEntry + " , " + secondEntry + "  -  " +
864                                             //        originalBlocklistEntry);
865                                         } else {  // Process a third-party domain blacklist single entry.
866                                             // Create an entry string array.
867                                             val domainEntry = arrayOf(domain, entry, originalBlocklistEntry)
868
869                                             // Add the entry to the blacklist.
870                                             thirdPartyDomainBlacklist.add(domainEntry)
871
872                                             //Log.i("Blocklists", headers.get(1)[0] + " third-party domain blocklist added: " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
873                                         }
874                                     }
875                                 } while (domains.contains("|"))
876
877                                 // Add a third-party blacklist entry if a whitelist domain was processed.
878                                 if (whitelistDomain) {
879                                     if (entry.contains("*")) {  // Process a third-party blacklist double entry.
880                                         // Get the index of the wildcard.
881                                         val wildcardIndex = entry.indexOf("*")
882
883                                         // Split the entry into components.
884                                         val firstEntry = entry.substring(0, wildcardIndex)
885                                         val secondEntry = entry.substring(wildcardIndex + 1)
886
887                                         // Create an entry string array.
888                                         val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
889
890                                         // Add the entry to the blacklist.
891                                         thirdPartyBlacklist.add(doubleEntry)
892
893                                         //Log.i("Blocklists", headers.get(1)[0] + " third-party blacklist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
894                                     } else {  // Process a third-party blacklist single entry.
895                                         // Create an entry string array.
896                                         val singleEntry = arrayOf(entry, originalBlocklistEntry)
897
898                                         // Add an entry to the blacklist.
899                                         thirdPartyBlacklist.add(singleEntry)
900
901                                         //Log.i("Blocklists", headers.get(1)[0] + " third-party blacklist added: " + entry + "  -  " + originalBlocklistEntry);
902                                     }
903                                 }
904                             }
905                         } else if (blocklistEntry.startsWith("|")) {  // Third-party initial blacklist entries.
906                             // Strip the initial `|`.
907                             blocklistEntry = blocklistEntry.substring(1)
908
909                             // Get the entry.
910                             val entry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
911                             if (entry.contains("*")) {  // Process a third-party initial blacklist double entry.
912                                 // Get the index of the wildcard.
913                                 val wildcardIndex = entry.indexOf("*")
914
915                                 // Split the entry into components.
916                                 val firstEntry = entry.substring(0, wildcardIndex)
917                                 val secondEntry = entry.substring(wildcardIndex + 1)
918
919                                 // Create an entry string array.
920                                 val thirdPartyDoubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
921
922                                 // Add the entry to the blacklist.
923                                 thirdPartyInitialBlacklist.add(thirdPartyDoubleEntry)
924
925                                 //Log.i("Blocklists", headers.get(1)[0] + " third-party initial blacklist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
926                             } else {  // Process a third-party initial blacklist single entry.
927                                 // Create an entry string array.
928                                 val singleEntry = arrayOf(entry, originalBlocklistEntry)
929
930                                 // Add the entry to the blacklist.
931                                 thirdPartyInitialBlacklist.add(singleEntry)
932
933                                 //Log.i("Blocklists", headers.get(1)[0] + " third-party initial blacklist added: " + entry + "  -  " + originalBlocklistEntry);
934                             }
935                         } else if (blocklistEntry.contains("\\")) {  // Process a regular expression blacklist entry.
936                             // Prepare a string to hold the entry.
937
938                             // Get the entry.
939                             val entry: String = if (blocklistEntry.contains("$/$")) {  // The first `$` is part of the regular expression.
940                                 blocklistEntry.substring(0, blocklistEntry.indexOf("$/$") + 2)
941                             } else {  // The only `$` indicates the filter options.
942                                 blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
943                             }
944
945                             // Create an entry string array.
946                             val singleEntry = arrayOf(entry, originalBlocklistEntry)
947
948                             // Add the entry to the blacklist.
949                             thirdPartyRegularExpressionBlacklist.add(singleEntry)
950
951                             //Log.i("Blocklists", headers.get(1)[0] + " third-party regular expression blacklist added: " + entry + "  -  " + originalBlocklistEntry);
952                         } else if (blocklistEntry.contains("*")) {  // Third-party and regular expression blacklist entries.
953                             // Get the entry.
954                             var entry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
955
956                             if (entry.endsWith("*")) {  // Process a third-party blacklist single entry.
957                                 // Strip the final `*`.
958                                 entry = entry.substring(0, entry.length - 1)
959
960                                 // Create an entry string array.
961                                 val singleEntry = arrayOf(entry, originalBlocklistEntry)
962
963                                 // Add the entry to the blacklist.
964                                 thirdPartyBlacklist.add(singleEntry)
965
966                                 //Log.i("Blocklists", headers.get(1)[0] + " third party blacklist added: " + entry + "  -  " + originalBlocklistEntry);
967                             } else {  // There are two or more entries.
968                                 // Get the index of the wildcard.
969                                 val wildcardIndex = entry.indexOf("*")
970
971                                 // Split the entry into components.
972                                 val firstEntry = entry.substring(0, wildcardIndex)
973                                 val secondEntry = entry.substring(wildcardIndex + 1)
974
975                                 if (secondEntry.contains("*")) {  // There are three or more entries.
976                                     // Get the index of the wildcard.
977                                     val secondWildcardIndex = secondEntry.indexOf("*")
978
979                                     // Split the entry into components.
980                                     val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
981                                     val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
982
983                                     if (thirdEntry.contains("*")) {  // Process a third-party blacklist quadruple entry.
984                                         // Get the index of the wildcard.
985                                         val thirdWildcardIndex = thirdEntry.indexOf("*")
986
987                                         // Split the entry into components.
988                                         val realThirdEntry = thirdEntry.substring(0, thirdWildcardIndex)
989                                         val fourthEntry = thirdEntry.substring(thirdWildcardIndex + 1)
990
991                                         // Create an entry string array.
992                                         val quadrupleEntry = arrayOf(firstEntry, realSecondEntry, realThirdEntry, fourthEntry, originalBlocklistEntry)
993
994                                         // Add the entry to the blacklist.
995                                         thirdPartyBlacklist.add(quadrupleEntry)
996
997                                         //Log.i("Blocklists", headers.get(1)[0] + " third-party blacklist added: " + firstEntry + " , " + realSecondEntry + " , " + realThirdEntry + " , " +
998                                         //        fourthEntry + "  -  " + originalBlocklistEntry);
999                                     } else {  // Process a third-party blacklist triple entry.
1000                                         // Create an entry string array.
1001                                         val tripleEntry = arrayOf(firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
1002
1003                                         // Add the entry to the blacklist.
1004                                         thirdPartyBlacklist.add(tripleEntry)
1005
1006                                         //Log.i("Blocklists", headers.get(1)[0] + " third-party blacklist added: " + firstEntry + " , " + realSecondEntry + " , " + thirdEntry + "  -  " +
1007                                         //        originalBlocklistEntry);
1008                                     }
1009                                 } else {  // Process a third-party blacklist double entry.
1010                                     // Create an entry string array.
1011                                     val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
1012
1013                                     // Add the entry to the blacklist.
1014                                     thirdPartyBlacklist.add(doubleEntry)
1015
1016                                     //Log.i("Blocklists", headers.get(1)[0] + " third-party blacklist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
1017                                 }
1018                             }
1019                         } else {  // Process a third party blacklist single entry.
1020                             // Get the entry.
1021                             val entry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
1022
1023                             // Create an entry string array.
1024                             val singleEntry = arrayOf(entry, originalBlocklistEntry)
1025
1026                             // Add the entry to the blacklist.
1027                             thirdPartyBlacklist.add(singleEntry)
1028
1029                             //Log.i("Blocklists", headers.get(1)[0] + " third party blacklist added: " + entry + "  -  " + originalBlocklistEntry);
1030                         }
1031                     } else if (blocklistEntry.substring(blocklistEntry.indexOf("$")).contains("domain=")) {  // Domain entries.
1032                         if (blocklistEntry.contains("~")) {  // Domain whitelist entries.
1033                             // Separate the filters.
1034                             var entry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
1035                             val filters = blocklistEntry.substring(blocklistEntry.indexOf("$") + 1)
1036                             var domains = filters.substring(filters.indexOf("domain=") + 7)
1037
1038                             // Strip any final `*` from the entry.  They are redundant.
1039                             if (entry.endsWith("*")) {
1040                                 entry = entry.substring(0, entry.length - 1)
1041                             }
1042
1043                             // Process each domain.
1044                             do {
1045                                 // Create a string to keep track of the current domain.
1046                                 var domain: String
1047
1048                                 if (domains.contains("|")) {  // There is more than one domain in the list.
1049                                     // Get the first domain from the list.
1050                                     domain = domains.substring(0, domains.indexOf("|"))
1051
1052                                     // Remove the first domain from the list.
1053                                     domains = domains.substring(domains.indexOf("|") + 1)
1054                                 } else {  // There is only one domain in the list.
1055                                     domain = domains
1056                                 }
1057
1058                                 // Strip the initial `~`.
1059                                 domain = domain.substring(1)
1060                                 if (entry.contains("*")) {  // There are two or more entries.
1061                                     // Get the index of the wildcard.
1062                                     val wildcardIndex = entry.indexOf("*")
1063
1064                                     // Split the entry into components.
1065                                     val firstEntry = entry.substring(0, wildcardIndex)
1066                                     val secondEntry = entry.substring(wildcardIndex + 1)
1067
1068                                     if (secondEntry.contains("*")) {  // Process a domain whitelist triple entry.
1069                                         // Get the index of the wildcard.
1070                                         val secondWildcardIndex = secondEntry.indexOf("*")
1071
1072                                         // Split the entry into components.
1073                                         val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
1074                                         val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
1075
1076                                         // Create an entry string array.
1077                                         val domainTripleEntry = arrayOf(domain, firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
1078
1079                                         // Add the entry to the whitelist.
1080                                         domainWhitelist.add(domainTripleEntry)
1081
1082                                         //Log.i("Blocklists", headers.get(1)[0] + " domain whitelist added: " + domain + " , " + firstEntry + " , " + realSecondEntry + " , " + thirdEntry +
1083                                         //        "  -  " + originalBlocklistEntry);
1084                                     } else {  // Process a domain whitelist double entry.
1085                                         // Create an entry string array.
1086                                         val domainDoubleEntry = arrayOf(domain, firstEntry, secondEntry, originalBlocklistEntry)
1087
1088                                         // Add the entry to the whitelist.
1089                                         domainWhitelist.add(domainDoubleEntry)
1090
1091                                         //Log.i("Blocklists", headers.get(1)[0] + " domain whitelist added: " + domain + " , " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
1092                                     }
1093                                 } else {  // Process a domain whitelist single entry.
1094                                     // Create an entry string array.
1095                                     val domainEntry = arrayOf(domain, entry, originalBlocklistEntry)
1096
1097                                     // Add the entry to the whitelist.
1098                                     domainWhitelist.add(domainEntry)
1099
1100                                     //Log.i("Blocklists", headers.get(1)[0] + " domain whitelist added: " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
1101                                 }
1102                             } while (domains.contains("|"))
1103                         } else {  // Domain blacklist entries.
1104                             // Separate the filters.
1105                             val entry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
1106                             val filters = blocklistEntry.substring(blocklistEntry.indexOf("$") + 1)
1107                             var domains = filters.substring(filters.indexOf("domain=") + 7)
1108
1109                             // Only process the item if the entry is not null.  For example, some lines begin with `$websocket`, which create a null entry.
1110                             if (entry != "") {
1111                                 // Process each domain.
1112                                 do {
1113                                     // Create a string to keep track of the current domain.
1114                                     var domain: String
1115
1116                                     if (domains.contains("|")) {  // There is more than one domain in the list.
1117                                         // Get the first domain from the list.
1118                                         domain = domains.substring(0, domains.indexOf("|"))
1119
1120                                         // Remove the first domain from the list.
1121                                         domains = domains.substring(domains.indexOf("|") + 1)
1122                                     } else {  // There is only one domain in the list.
1123                                         domain = domains
1124                                     }
1125
1126                                     if (entry.startsWith("|")) {  // Domain initial blacklist entries.
1127                                         // Remove the initial `|`;
1128                                         val entryBase = entry.substring(1)
1129
1130                                         if (entryBase == "http://" || entryBase == "https://") {
1131                                             // Do nothing.  These entries will entirely block the website.
1132                                             // Often the original entry blocks `$script` but Privacy Browser does not currently differentiate between scripts and other entries.
1133
1134                                             //Log.i("Blocklists", headers.get(1)[0] + " not added: " + originalBlocklistEntry);
1135                                         } else {  // Process a domain initial blacklist entry
1136                                             // Create an entry string array.
1137                                             val domainEntry = arrayOf(domain, entryBase, originalBlocklistEntry)
1138
1139                                             // Add the entry to the blacklist.
1140                                             domainInitialBlacklist.add(domainEntry)
1141
1142                                             //Log.i("Blocklists", headers.get(1)[0] + " domain initial blacklist added: " + domain + " , " + entryBase + "  -  " + originalBlocklistEntry);
1143                                         }
1144                                     } else if (entry.endsWith("|")) {  // Domain final blacklist entries.
1145                                         // Remove the final `|`.
1146                                         val entryBase = entry.substring(0, entry.length - 1)
1147
1148                                         if (entryBase.contains("*")) {  // Process a domain final blacklist double entry.
1149                                             // Get the index of the wildcard.
1150                                             val wildcardIndex = entry.indexOf("*")
1151
1152                                             // Split the entry into components.
1153                                             val firstEntry = entryBase.substring(0, wildcardIndex)
1154                                             val secondEntry = entryBase.substring(wildcardIndex + 1)
1155
1156                                             // Create an entry string array.
1157                                             val domainDoubleEntry = arrayOf(domain, firstEntry, secondEntry, originalBlocklistEntry)
1158
1159                                             // Add the entry to the blacklist.
1160                                             domainFinalBlacklist.add(domainDoubleEntry)
1161
1162                                             //Log.i("Blocklists", headers.get(1)[0] + " domain final blacklist added: " + domain + " , " + firstEntry + " , " + secondEntry + "  -  " +
1163                                             //        originalBlocklistEntry);
1164                                         } else {  // Process a domain final blacklist single entry.
1165                                             // Create an entry string array.
1166                                             val domainEntry = arrayOf(domain, entryBase, originalBlocklistEntry)
1167
1168                                             // Add the entry to the blacklist.
1169                                             domainFinalBlacklist.add(domainEntry)
1170
1171                                             //Log.i("Blocklists", headers.get(1)[0] + " domain final blacklist added: " + domain + " , " + entryBase + "  -  " + originalBlocklistEntry);
1172                                         }
1173                                     } else if (entry.contains("\\")) {  // Process a domain regular expression blacklist entry.
1174                                         // Create an entry string array.
1175                                         val domainEntry = arrayOf(domain, entry, originalBlocklistEntry)
1176
1177                                         // Add the entry to the blacklist.
1178                                         domainRegularExpressionBlacklist.add(domainEntry)
1179
1180                                         //Log.i("Blocklists", headers.get(1)[0] + " domain regular expression blacklist added: " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
1181                                     } else if (entry.contains("*")) {  // There are two or more entries.
1182                                         // Get the index of the wildcard.
1183                                         val wildcardIndex = entry.indexOf("*")
1184
1185                                         // Split the entry into components.
1186                                         val firstEntry = entry.substring(0, wildcardIndex)
1187                                         val secondEntry = entry.substring(wildcardIndex + 1)
1188
1189                                         if (secondEntry.contains("*")) {  // Process a domain blacklist triple entry.
1190                                             // Get the index of the wildcard.
1191                                             val secondWildcardIndex = secondEntry.indexOf("*")
1192
1193                                             // Split the entry into components.
1194                                             val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
1195                                             val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
1196
1197                                             // Create an entry string array.
1198                                             val domainTripleEntry = arrayOf(domain, firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
1199
1200                                             // Add the entry to the blacklist.
1201                                             domainBlacklist.add(domainTripleEntry)
1202
1203                                             //Log.i("Blocklists", headers.get(1)[0] + " domain blacklist added: " + domain + " , " + firstEntry + " , " + realSecondEntry + " , " + thirdEntry +
1204                                             //        "  -  " + originalBlocklistEntry);
1205                                         } else {  // Process a domain blacklist double entry.
1206                                             // Create an entry string array.
1207                                             val domainDoubleEntry = arrayOf(domain, firstEntry, secondEntry, originalBlocklistEntry)
1208
1209                                             // Add the entry to the blacklist.
1210                                             domainBlacklist.add(domainDoubleEntry)
1211
1212                                             //Log.i("Blocklists", headers.get(1)[0] + " domain blacklist added: " + domain + " , " + firstEntry + " , " + secondEntry + "  -  " +
1213                                             //        originalBlocklistEntry);
1214                                         }
1215                                     } else {  // Process a domain blacklist single entry.
1216                                         // Create an entry string array.
1217                                         val domainEntry = arrayOf(domain, entry, originalBlocklistEntry)
1218
1219                                         // Add the entry to the blacklist.
1220                                         domainBlacklist.add(domainEntry)
1221
1222                                         //Log.i("Blocklists", headers.get(1)[0] + " domain blacklist added: " + domain + " , " + entry + "  -  " + originalBlocklistEntry);
1223                                     }
1224                                 } while (domains.contains("|"))
1225                             }
1226                         }
1227                     } else if (blocklistEntry.contains("~")) {  // Whitelist entries.  Privacy Browser does not differentiate against these filter options, so they are just generally whitelisted.
1228                         // Remove the filter options.
1229                         blocklistEntry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
1230
1231                         // Strip any trailing `*`.
1232                         if (blocklistEntry.endsWith("*")) {
1233                             blocklistEntry = blocklistEntry.substring(0, blocklistEntry.length - 1)
1234                         }
1235
1236                         if (blocklistEntry.contains("*")) {  // Process a whitelist double entry.
1237                             // Get the index of the wildcard.
1238                             val wildcardIndex = blocklistEntry.indexOf("*")
1239
1240                             // Split the entry into components.
1241                             val firstEntry = blocklistEntry.substring(0, wildcardIndex)
1242                             val secondEntry = blocklistEntry.substring(wildcardIndex + 1)
1243
1244                             // Create an entry string array.
1245                             val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
1246
1247                             // Add the entry to the whitelist.
1248                             mainWhitelist.add(doubleEntry)
1249
1250                             //Log.i("Blocklists", headers.get(1)[0] + " main whitelist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
1251                         } else {  // Process a whitelist single entry.
1252                             // Create an entry string array.
1253                             val singleEntry = arrayOf(blocklistEntry, originalBlocklistEntry)
1254
1255                             // Add the entry to the whitelist.
1256                             mainWhitelist.add(singleEntry)
1257
1258                             //Log.i("Blocklists", headers.get(1)[0] + " main whitelist added: " + blocklistEntry + "  -  + " + originalBlocklistEntry);
1259                         }
1260                     } else if (blocklistEntry.contains("\\")) {  // Process a regular expression blacklist entry.
1261                         // Remove the filter options.
1262                         blocklistEntry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
1263
1264                         // Create an entry string array.
1265                         val singleEntry = arrayOf(blocklistEntry, originalBlocklistEntry)
1266
1267                         // Add the entry to the blacklist.
1268                         regularExpressionBlacklist.add(singleEntry)
1269
1270                         //Log.i("Blocklists", headers.get(1)[0] + " regular expression blacklist added: " + blocklistEntry + "  -  " + originalBlocklistEntry);
1271                     } else {  // Blacklist entries.
1272                         // Remove the filter options.
1273                         if (!blocklistEntry.contains("\$file")) {  // EasyPrivacy contains an entry with `$file` that does not have filter options.
1274                             blocklistEntry = blocklistEntry.substring(0, blocklistEntry.indexOf("$"))
1275                         }
1276
1277                         // Strip any trailing `*`.  These are redundant.
1278                         if (blocklistEntry.endsWith("*")) {
1279                             blocklistEntry = blocklistEntry.substring(0, blocklistEntry.length - 1)
1280                         }
1281
1282                         if (blocklistEntry.startsWith("|")) {  // Initial blacklist entries.
1283                             // Strip the initial `|`.
1284                             val entry = blocklistEntry.substring(1)
1285
1286                             if (entry.contains("*")) {  // Process an initial blacklist double entry.
1287                                 // Get the index of the wildcard.
1288                                 val wildcardIndex = entry.indexOf("*")
1289
1290                                 // Split the entry into components.
1291                                 val firstEntry = entry.substring(0, wildcardIndex)
1292                                 val secondEntry = entry.substring(wildcardIndex + 1)
1293
1294                                 // Create an entry string array.
1295                                 val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
1296
1297                                 // Add the entry to the blacklist.
1298                                 initialBlacklist.add(doubleEntry)
1299
1300                                 //Log.i("Blocklists", headers.get(1)[0] + " initial blacklist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
1301                             } else {  // Process an initial blacklist single entry.
1302                                 // Create an entry string array.
1303                                 val singleEntry = arrayOf(entry, originalBlocklistEntry)
1304
1305                                 // Add the entry to the blacklist.
1306                                 initialBlacklist.add(singleEntry)
1307
1308                                 //Log.i("Blocklists", headers.get(1)[0] + " initial blacklist added: " + entry + "  -  " + originalBlocklistEntry);
1309                             }
1310                         } else if (blocklistEntry.endsWith("|")) {  // Final blacklist entries.
1311                             // Ignore entries with `object` filters.  They can block entire websites and don't have any meaning in the context of Privacy Browser.
1312                             if (!originalBlocklistEntry.contains("\$object")) {
1313                                 // Strip the final `|`.
1314                                 val entry = blocklistEntry.substring(0, blocklistEntry.length - 1)
1315
1316                                 if (entry.contains("*")) {  // There are two or more entries.
1317                                     // Get the index of the wildcard.
1318                                     val wildcardIndex = entry.indexOf("*")
1319
1320                                     // Split the entry into components.
1321                                     val firstEntry = entry.substring(0, wildcardIndex)
1322                                     val secondEntry = entry.substring(wildcardIndex + 1)
1323
1324                                     if (secondEntry.contains("*")) {  // Process a final blacklist triple entry.
1325                                         // Get the index of the wildcard.
1326                                         val secondWildcardIndex = secondEntry.indexOf("*")
1327
1328                                         // Split the entry into components.
1329                                         val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
1330                                         val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
1331
1332                                         // Create an entry string array.
1333                                         val tripleEntry = arrayOf(firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
1334
1335                                         // Add the entry to the blacklist.
1336                                         finalBlacklist.add(tripleEntry)
1337
1338                                         //Log.i("Blocklists", headers.get(1)[0] + " final blacklist added: " + firstEntry + " , " + realSecondEntry + " , " + thirdEntry + "  -  " +
1339                                         //        originalBlocklistEntry);
1340                                     } else {  // Process a final blacklist double entry.
1341                                         // Create an entry string array.
1342                                         val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
1343
1344                                         // Add the entry to the blacklist.
1345                                         finalBlacklist.add(doubleEntry)
1346
1347                                         //Log.i("Blocklists", headers.get(1)[0] + " final blacklist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
1348                                     }
1349                                 } else {  // Process a final blacklist single entry.
1350                                     // Create an entry sting array.
1351                                     val singleEntry = arrayOf(entry, originalBlocklistEntry)
1352
1353                                     // Add the entry to the blacklist.
1354                                     finalBlacklist.add(singleEntry)
1355
1356                                     //Log.i("Blocklists", headers.get(1)[0] + " final blacklist added: " + entry + "  -  " + originalBlocklistEntry);
1357                                 }
1358                             }
1359                         } else if (blocklistEntry.contains("*")) {  // There are two or more entries.
1360                             // Get the index of the wildcard.
1361                             val wildcardIndex = blocklistEntry.indexOf("*")
1362
1363                             // Split the entry into components.
1364                             val firstEntry = blocklistEntry.substring(0, wildcardIndex)
1365                             val secondEntry = blocklistEntry.substring(wildcardIndex + 1)
1366
1367                             if (secondEntry.contains("*")) {  // Process a main blacklist triple entry.
1368                                 // Get the index of the wildcard.
1369                                 val secondWildcardIndex = secondEntry.indexOf("*")
1370
1371                                 // Split the entry into components.
1372                                 val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
1373                                 val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
1374
1375                                 // Create an entry string array.
1376                                 val tripleEntry = arrayOf(firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
1377
1378                                 // Add the entry to the blacklist.
1379                                 mainBlacklist.add(tripleEntry)
1380
1381                                 //Log.i("Blocklists", headers.get(1)[0] + " main blacklist added: " + firstEntry + " , " + realSecondEntry + " , " + thirdEntry + "  -  " + originalBlocklistEntry);
1382                             } else {  // Process a main blacklist double entry.
1383                                 // Create an entry string array.
1384                                 val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
1385
1386                                 // Add the entry to the blacklist.
1387                                 mainBlacklist.add(doubleEntry)
1388
1389                                 //Log.i("Blocklists", headers.get(1)[0] + " main blacklist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
1390                             }
1391                         } else {  // Process a main blacklist single entry.
1392                             // Create an entry string array.
1393                             val singleEntry = arrayOf(blocklistEntry, originalBlocklistEntry)
1394
1395                             // Add the entry to the blacklist.
1396                             mainBlacklist.add(singleEntry)
1397
1398                             //Log.i("Blocklists", headers.get(1)[0] + " main blacklist added: " + blocklistEntry + "  -  " + originalBlocklistEntry);
1399                         }
1400                     }
1401                 } else {  // Main blacklist entries
1402                     // Strip out any initial `||`.  These will be treated like any other entry.
1403                     if (blocklistEntry.startsWith("||")) {
1404                         blocklistEntry = blocklistEntry.substring(2)
1405                     }
1406
1407                     // Strip out any initial `*`.
1408                     if (blocklistEntry.startsWith("*")) {
1409                         blocklistEntry = blocklistEntry.substring(1)
1410                     }
1411
1412                     // Strip out any trailing `*`.
1413                     if (blocklistEntry.endsWith("*")) {
1414                         blocklistEntry = blocklistEntry.substring(0, blocklistEntry.length - 1)
1415                     }
1416
1417                     if (blocklistEntry.startsWith("|")) {  // Initial blacklist entries.
1418                         // Strip the initial `|`.
1419                         val entry = blocklistEntry.substring(1)
1420
1421                         if (entry.contains("*")) {  // Process an initial blacklist double entry.
1422                             // Get the index of the wildcard.
1423                             val wildcardIndex = entry.indexOf("*")
1424
1425                             // Split the entry into components.
1426                             val firstEntry = entry.substring(0, wildcardIndex)
1427                             val secondEntry = entry.substring(wildcardIndex + 1)
1428
1429                             // Create an entry string array.
1430                             val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
1431
1432                             // Add the entry to the blacklist.
1433                             initialBlacklist.add(doubleEntry)
1434
1435                             //Log.i("Blocklists", headers.get(1)[0] + " initial blacklist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
1436                         } else {  // Process an initial blacklist single entry.
1437                             // Create an entry string array.
1438                             val singleEntry = arrayOf(entry, originalBlocklistEntry)
1439
1440                             // Add the entry to the blacklist.
1441                             initialBlacklist.add(singleEntry)
1442
1443                             //Log.i("Blocklists", headers.get(1)[0] + " initial blacklist added: " + entry + "  -  " + originalBlocklistEntry);
1444                         }
1445                     } else if (blocklistEntry.endsWith("|")) {  // Final blacklist entries.
1446                         // Strip the final `|`.
1447                         val entry = blocklistEntry.substring(0, blocklistEntry.length - 1)
1448
1449                         if (entry.contains("*")) {  // There are two or more entries.
1450                             // Get the index of the wildcard.
1451                             val wildcardIndex = entry.indexOf("*")
1452
1453                             // Split the entry into components.
1454                             val firstEntry = entry.substring(0, wildcardIndex)
1455                             val secondEntry = entry.substring(wildcardIndex + 1)
1456
1457                             if (secondEntry.contains("*")) {  // Process a final blacklist triple entry.
1458                                 // Get the index of the wildcard.
1459                                 val secondWildcardIndex = secondEntry.indexOf("*")
1460
1461                                 // Split the entry into components.
1462                                 val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
1463                                 val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
1464
1465                                 // Create an entry string array.
1466                                 val tripleEntry = arrayOf(firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
1467
1468                                 // Add the entry to the blacklist.
1469                                 finalBlacklist.add(tripleEntry)
1470
1471                                 //Log.i("Blocklists", headers.get(1)[0] + " final blacklist added: " + firstEntry + " , " + realSecondEntry + " , " + thirdEntry + "  -  " + originalBlocklistEntry);
1472                             } else {  // Process a final blacklist double entry.
1473                                 // Create an entry string array.
1474                                 val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
1475
1476                                 // Add the entry to the blacklist.
1477                                 finalBlacklist.add(doubleEntry)
1478
1479                                 //Log.i("Blocklists", headers.get(1)[0] + " final blacklist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
1480                             }
1481                         } else {  // Process a final blacklist single entry.
1482                             // Create an entry string array.
1483                             val singleEntry = arrayOf(entry, originalBlocklistEntry)
1484
1485                             // Add the entry to the blacklist.
1486                             finalBlacklist.add(singleEntry)
1487
1488                             //Log.i("Blocklists", headers.get(1)[0] + " final blacklist added: " + entry + "  -  " + originalBlocklistEntry);
1489                         }
1490                     } else {  // Main blacklist entries.
1491                         if (blocklistEntry.contains("*")) {  // There are two or more entries.
1492                             // Get the index of the wildcard.
1493                             val wildcardIndex = blocklistEntry.indexOf("*")
1494
1495                             // Split the entry into components.
1496                             val firstEntry = blocklistEntry.substring(0, wildcardIndex)
1497                             val secondEntry = blocklistEntry.substring(wildcardIndex + 1)
1498
1499                             if (secondEntry.contains("*")) {  // There are three or more entries.
1500                                 // Get the index of the wildcard.
1501                                 val secondWildcardIndex = secondEntry.indexOf("*")
1502
1503                                 // Split the entry into components.
1504                                 val realSecondEntry = secondEntry.substring(0, secondWildcardIndex)
1505                                 val thirdEntry = secondEntry.substring(secondWildcardIndex + 1)
1506
1507                                 if (thirdEntry.contains("*")) {  // There are four or more entries.
1508                                     // Get the index of the wildcard.
1509                                     val thirdWildcardIndex = thirdEntry.indexOf("*")
1510
1511                                     // Split the entry into components.
1512                                     val realThirdEntry = thirdEntry.substring(0, thirdWildcardIndex)
1513                                     val fourthEntry = thirdEntry.substring(thirdWildcardIndex + 1)
1514
1515                                     if (fourthEntry.contains("*")) {  // Process a main blacklist quintuple entry.
1516                                         // Get the index of the wildcard.
1517                                         val fourthWildcardIndex = fourthEntry.indexOf("*")
1518
1519                                         // Split the entry into components.
1520                                         val realFourthEntry = fourthEntry.substring(0, fourthWildcardIndex)
1521                                         val fifthEntry = fourthEntry.substring(fourthWildcardIndex + 1)
1522
1523                                         // Create an entry string array.
1524                                         val quintupleEntry = arrayOf(firstEntry, realSecondEntry, realThirdEntry, realFourthEntry, fifthEntry, originalBlocklistEntry)
1525
1526                                         // Add the entry to the blacklist.
1527                                         mainBlacklist.add(quintupleEntry)
1528
1529                                         //Log.i("Blocklists", headers.get(1)[0] + " main blacklist added: " + firstEntry + " , " + realSecondEntry + " , " + realThirdEntry + " , " + realFourthEntry + " , " +
1530                                         //      fifthEntry + "  -  " + originalBlocklistEntry);
1531                                     } else {  // Process a main blacklist quadruple entry.
1532                                         // Create an entry string array.
1533                                         val quadrupleEntry = arrayOf(firstEntry, realSecondEntry, realThirdEntry, fourthEntry, originalBlocklistEntry)
1534
1535                                         // Add the entry to the blacklist.
1536                                         mainBlacklist.add(quadrupleEntry)
1537
1538                                         //Log.i("Blocklists", headers.get(1)[0] + " main blacklist added: " + firstEntry + " , " + realSecondEntry + " , " + realThirdEntry + " , " + fourthEntry + "  -  " +
1539                                         //      originalBlocklistEntry);
1540                                     }
1541                                 } else {  // Process a main blacklist triple entry.
1542                                     // Create an entry string array.
1543                                     val tripleEntry = arrayOf(firstEntry, realSecondEntry, thirdEntry, originalBlocklistEntry)
1544
1545                                     // Add the entry to the blacklist.
1546                                     mainBlacklist.add(tripleEntry)
1547
1548                                     //Log.i("Blocklists", headers.get(1)[0] + " main blacklist added: " + firstEntry + " , " + realSecondEntry + " , " + thirdEntry + "  -  " + originalBlocklistEntry);
1549                                 }
1550                             } else {  // Process a main blacklist double entry.
1551                                 // Create an entry string array.
1552                                 val doubleEntry = arrayOf(firstEntry, secondEntry, originalBlocklistEntry)
1553
1554                                 // Add the entry to the blacklist.
1555                                 mainBlacklist.add(doubleEntry)
1556
1557                                 //Log.i("Blocklists", headers.get(1)[0] + " main blacklist added: " + firstEntry + " , " + secondEntry + "  -  " + originalBlocklistEntry);
1558                             }
1559                         } else {  // Process a main blacklist single entry.
1560                             // Create an entry string array.
1561                             val singleEntry = arrayOf(blocklistEntry, originalBlocklistEntry)
1562
1563                             // Add the entry to the blacklist.
1564                             mainBlacklist.add(singleEntry)
1565
1566                             //Log.i("Blocklists", headers.get(1)[0] + " main blacklist added: " + blocklistEntry + "  -  " + originalBlocklistEntry);
1567                         }
1568                     }
1569                 }
1570             }
1571             // Close `bufferedReader`.
1572             bufferedReader.close()
1573         } catch (e: IOException) {
1574             // The asset exists, so the `IOException` will never be thrown.
1575         }
1576
1577         // Initialize the combined list.
1578         val combinedLists = ArrayList<List<Array<String>>>()
1579
1580         // Add the headers (0).
1581         combinedLists.add(headers) // 0.
1582
1583         // Add the whitelists (1-8).
1584         combinedLists.add(mainWhitelist) // 1.
1585         combinedLists.add(finalWhitelist) // 2.
1586         combinedLists.add(domainWhitelist) // 3.
1587         combinedLists.add(domainInitialWhitelist) // 4.
1588         combinedLists.add(domainFinalWhitelist) // 5.
1589         combinedLists.add(thirdPartyWhitelist) // 6.
1590         combinedLists.add(thirdPartyDomainWhitelist) // 7.
1591         combinedLists.add(thirdPartyDomainInitialWhitelist) // 8.
1592
1593         // Add the blacklists (9-22).
1594         combinedLists.add(mainBlacklist) // 9.
1595         combinedLists.add(initialBlacklist) // 10.
1596         combinedLists.add(finalBlacklist) // 11.
1597         combinedLists.add(domainBlacklist) //  12.
1598         combinedLists.add(domainInitialBlacklist) // 13.
1599         combinedLists.add(domainFinalBlacklist) // 14.
1600         combinedLists.add(domainRegularExpressionBlacklist) // 15.
1601         combinedLists.add(thirdPartyBlacklist) // 16.
1602         combinedLists.add(thirdPartyInitialBlacklist) // 17.
1603         combinedLists.add(thirdPartyDomainBlacklist) // 18.
1604         combinedLists.add(thirdPartyDomainInitialBlacklist) // 19.
1605         combinedLists.add(thirdPartyRegularExpressionBlacklist) // 20.
1606         combinedLists.add(thirdPartyDomainRegularExpressionBlacklist) // 21.
1607         combinedLists.add(regularExpressionBlacklist) // 22.
1608
1609         // Return the combined lists.
1610         return combinedLists
1611     }
1612
1613     fun checkBlocklist(currentDomain: String?, resourceUrl: String, isThirdPartyRequest: Boolean, blocklist: ArrayList<List<Array<String>>>): Array<String> {
1614         // Get the blocklist name.
1615         val blocklistName = blocklist[0][1][0]
1616
1617         // Process the whitelists.
1618         // Main whitelist.
1619         for (whitelistEntry in blocklist[MAIN_WHITELIST.toInt()]) {
1620             when (whitelistEntry.size) {
1621                 // There is one entry.
1622                 2 -> if (resourceUrl.contains(whitelistEntry[0])) {
1623                     // Return a whitelist match request allowed.
1624                     return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, MAIN_WHITELIST, whitelistEntry[0], whitelistEntry[1])
1625                 }
1626
1627                 // There are two entries.
1628                 3 -> if (resourceUrl.contains(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1])) {
1629                     // Return a whitelist match request allowed.
1630                     return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, MAIN_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}", whitelistEntry[2]
1631                     )
1632                 }
1633
1634                 // There are three entries.
1635                 4 -> if (resourceUrl.contains(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1]) && resourceUrl.contains(whitelistEntry[2])) {
1636                     // Return a whitelist match request allowed.
1637                     return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, MAIN_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}", whitelistEntry[3])
1638                 }
1639             }
1640         }
1641
1642         // Final whitelist.
1643         for (whitelistEntry in blocklist[FINAL_WHITELIST.toInt()]) {
1644             when (whitelistEntry.size) {
1645                 // There is one entry.
1646                 2 -> if (resourceUrl.contains(whitelistEntry[0])) {
1647                     // Return a whitelist match request allowed.
1648                     return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, FINAL_WHITELIST, whitelistEntry[0], whitelistEntry[1])
1649                 }
1650
1651                 // There are two entries.
1652                 3 -> if (resourceUrl.contains(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1])) {
1653                     // Return a whitelist match request allowed.
1654                     return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, FINAL_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}", whitelistEntry[2])
1655                 }
1656             }
1657         }
1658
1659         // Only check the domain lists if the current domain is not null (like `about:blank`).
1660         if (currentDomain != null) {
1661             // Domain whitelist.
1662             for (whitelistEntry in blocklist[DOMAIN_WHITELIST.toInt()]) {
1663                 when (whitelistEntry.size) {
1664                     // There is one entry.
1665                     3 -> if (currentDomain.endsWith(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1])) {
1666                         // Return a whitelist match request allowed.
1667                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, DOMAIN_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}", whitelistEntry[2])
1668                     }
1669
1670                     // There are two entries.
1671                     4 -> if (currentDomain.endsWith(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1]) && resourceUrl.contains(whitelistEntry[2])) {
1672                         // Return a whitelist match request allowed.
1673                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, DOMAIN_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}", whitelistEntry[3])
1674                     }
1675
1676                     // There are three entries.
1677                     5 -> if (currentDomain.endsWith(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1]) && resourceUrl.contains(whitelistEntry[2]) && resourceUrl.contains(whitelistEntry[3])) {
1678                         // Return a whitelist match request allowed.
1679                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, DOMAIN_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}\n${whitelistEntry[3]}", whitelistEntry[4])
1680                     }
1681
1682                     // There are four entries.
1683                     6 -> if (currentDomain.endsWith(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1]) && resourceUrl.contains(whitelistEntry[2]) && resourceUrl.contains(whitelistEntry[3]) &&
1684                         resourceUrl.contains(whitelistEntry[4])) {
1685                         // Return a whitelist match request allowed.
1686                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, DOMAIN_WHITELIST,
1687                             "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}\n${whitelistEntry[3]}\n${whitelistEntry[4]}", whitelistEntry[5])
1688                     }
1689                 }
1690             }
1691
1692             // Domain initial whitelist.
1693             for (whitelistEntry in blocklist[DOMAIN_INITIAL_WHITELIST.toInt()]) {
1694                 when (whitelistEntry.size) {
1695                     // There is one entry.
1696                     3 -> if (currentDomain.endsWith(whitelistEntry[0]) && resourceUrl.startsWith(whitelistEntry[1])) {
1697                         // Return a whitelist match request allowed.
1698                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, DOMAIN_INITIAL_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}".trimIndent(), whitelistEntry[2])
1699                     }
1700
1701                     // There are two entries.
1702                     4 -> if (currentDomain.endsWith(whitelistEntry[0]) && resourceUrl.startsWith(whitelistEntry[1]) && resourceUrl.contains(whitelistEntry[2])) {
1703                         // Return a whitelist match request allowed.
1704                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, DOMAIN_INITIAL_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}", whitelistEntry[3])
1705                     }
1706
1707                     // There are three entries.
1708                     5 -> if (currentDomain.endsWith(whitelistEntry[0]) && resourceUrl.startsWith(whitelistEntry[1]) && resourceUrl.contains(whitelistEntry[2]) && resourceUrl.startsWith(whitelistEntry[3])) {
1709                         // Return a whitelist match request allowed.
1710                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, DOMAIN_INITIAL_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}\n${whitelistEntry[3]}",
1711                             whitelistEntry[4])
1712                     }
1713                 }
1714             }
1715
1716             // Domain final whitelist.
1717             for (whitelistEntry in blocklist[DOMAIN_FINAL_WHITELIST.toInt()]) {
1718                 when (whitelistEntry.size) {
1719                     // There is one entry.
1720                     3 -> if (currentDomain.endsWith(whitelistEntry[0]) && resourceUrl.endsWith(whitelistEntry[1])) {
1721                         // Return a whitelist match request allowed.
1722                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, DOMAIN_FINAL_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}", whitelistEntry[2])
1723                     }
1724
1725                     // There are two entries.
1726                     4 -> if (currentDomain.endsWith(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1]) && resourceUrl.endsWith(whitelistEntry[2])) {
1727                         // Return a whitelist match request allowed.
1728                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, DOMAIN_FINAL_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}", whitelistEntry[3])
1729                     }
1730                 }
1731             }
1732         }
1733
1734         // Only check the third-party whitelists if this is a third-party request.
1735         if (isThirdPartyRequest) {
1736             // Third-party whitelist.
1737             for (whitelistEntry in blocklist[THIRD_PARTY_WHITELIST.toInt()]) {
1738                 when (whitelistEntry.size) {
1739                     // There is one entry.
1740                     2 -> if (resourceUrl.contains(whitelistEntry[0])) {
1741                         // Return a whitelist match request allowed.
1742                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, THIRD_PARTY_WHITELIST, whitelistEntry[0], whitelistEntry[1])
1743                     }
1744
1745                     // There are two entries.
1746                     3 -> if (resourceUrl.contains(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1])) {
1747                         // Return a whitelist match request allowed.
1748                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, THIRD_PARTY_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}", whitelistEntry[2])
1749                     }
1750
1751                     // There are three entries.
1752                     4 -> if (resourceUrl.contains(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1]) && resourceUrl.contains(whitelistEntry[2])) {
1753                         // Return a whitelist match request allowed.
1754                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, THIRD_PARTY_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}", whitelistEntry[3])
1755                     }
1756
1757                     // There are four entries.
1758                     5 -> if (resourceUrl.contains(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1]) && resourceUrl.contains(whitelistEntry[2]) && resourceUrl.contains(whitelistEntry[3])) {
1759                         // Return a whitelist match request allowed.
1760                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, THIRD_PARTY_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}\n${whitelistEntry[3]}",
1761                             whitelistEntry[4])
1762                     }
1763
1764                     // There are five entries.
1765                     6 -> if (resourceUrl.contains(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1]) && resourceUrl.contains(whitelistEntry[2]) && resourceUrl.contains(whitelistEntry[3]) &&
1766                         resourceUrl.contains(whitelistEntry[4])) {
1767                         // Return a whitelist match request allowed.
1768                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, THIRD_PARTY_WHITELIST,
1769                             "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}\n${whitelistEntry[3]}\n${whitelistEntry[4]}", whitelistEntry[5])
1770                     }
1771                 }
1772             }
1773
1774             // Third-party domain whitelist.
1775             for (whitelistEntry in blocklist[THIRD_PARTY_DOMAIN_WHITELIST.toInt()]) {
1776                 when (whitelistEntry.size) {
1777                     // There is one entry.
1778                     3 -> if (currentDomain!!.endsWith(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1])) {
1779                         // Return a whitelist match request allowed.
1780                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, THIRD_PARTY_DOMAIN_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n", whitelistEntry[2])
1781                     }
1782
1783                     // There are two entries.
1784                     4 -> if (currentDomain!!.endsWith(whitelistEntry[0]) && resourceUrl.contains(whitelistEntry[1]) && resourceUrl.contains(whitelistEntry[2])) {
1785                         // Return a whitelist match request allowed.
1786                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, THIRD_PARTY_DOMAIN_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}", whitelistEntry[3])
1787                     }
1788                 }
1789             }
1790
1791             // Third-party domain initial whitelist.
1792             for (whitelistEntry in blocklist[THIRD_PARTY_DOMAIN_INITIAL_WHITELIST.toInt()]) {
1793                 when (whitelistEntry.size) {
1794                     // There is one entry.
1795                     3 -> if (currentDomain!!.endsWith(whitelistEntry[0]) && resourceUrl.startsWith(whitelistEntry[1])) {
1796                         // Return a whitelist match request allowed.
1797                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, THIRD_PARTY_DOMAIN_INITIAL_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n", whitelistEntry[2])
1798                     }
1799
1800                     // There are two entries.
1801                     4 -> if (currentDomain!!.endsWith(whitelistEntry[0]) && resourceUrl.startsWith(whitelistEntry[1]) && resourceUrl.contains(whitelistEntry[2])) {
1802                         // Return a whitelist match request allowed.
1803                         return arrayOf(REQUEST_ALLOWED, resourceUrl, blocklistName, THIRD_PARTY_DOMAIN_WHITELIST, "${whitelistEntry[0]}\n${whitelistEntry[1]}\n${whitelistEntry[2]}", whitelistEntry[3])
1804                     }
1805                 }
1806             }
1807         }
1808
1809         // Process the blacklists.
1810         // Main blacklist.
1811         for (blacklistEntry in blocklist[MAIN_BLACKLIST.toInt()]) {
1812             when (blacklistEntry.size) {
1813                 // There is one entry.
1814                 2 -> if (resourceUrl.contains(blacklistEntry[0])) {
1815                     // Return a blacklist match request blocked.
1816                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, MAIN_BLACKLIST, blacklistEntry[0], blacklistEntry[1])
1817                 }
1818
1819                 // There are two entries.
1820                 3 -> if (resourceUrl.contains(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1])) {
1821                     // Return a blacklist match request blocked.
1822                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, MAIN_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}", blacklistEntry[2])
1823                 }
1824
1825                 // There are three entries.
1826                 4 -> if (resourceUrl.contains(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1]) && resourceUrl.contains(blacklistEntry[2])) {
1827                     // Return a blacklist match request blocked.
1828                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, MAIN_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}", blacklistEntry[3])
1829                 }
1830
1831                 // There are four entries.
1832                 5 -> if (resourceUrl.contains(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1]) && resourceUrl.contains(blacklistEntry[2]) && resourceUrl.contains(blacklistEntry[3])) {
1833                     // Return a blacklist match request blocked.
1834                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, MAIN_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}\n${blacklistEntry[3]}", blacklistEntry[4])
1835                 }
1836
1837                 // There are five entries.
1838                 6 -> if (resourceUrl.contains(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1]) && resourceUrl.contains(blacklistEntry[2]) && resourceUrl.contains(blacklistEntry[3]) &&
1839                     resourceUrl.contains(blacklistEntry[4])) {
1840                     // Return a blacklist match request blocked.
1841                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, MAIN_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}\n${blacklistEntry[3]}\n${blacklistEntry[4]}",
1842                         blacklistEntry[5])
1843                 }
1844             }
1845         }
1846
1847         // Initial blacklist.
1848         for (blacklistEntry in blocklist[INITIAL_BLACKLIST.toInt()]) {
1849             when (blacklistEntry.size) {
1850                 // There is one entry.
1851                 2 -> if (resourceUrl.startsWith(blacklistEntry[0])) {
1852                     // Return a blacklist match request blocked.
1853                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, INITIAL_BLACKLIST, blacklistEntry[0], blacklistEntry[1])
1854                 }
1855
1856                 // There are two entries
1857                 3 -> if (resourceUrl.startsWith(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1])) {
1858                     // Return a blacklist match request blocked.
1859                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, INITIAL_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}", blacklistEntry[2])
1860                 }
1861             }
1862         }
1863
1864         // Final blacklist.
1865         for (blacklistEntry in blocklist[FINAL_BLACKLIST.toInt()]) {
1866             when (blacklistEntry.size) {
1867                 // There is one entry.
1868                 2 -> if (resourceUrl.endsWith(blacklistEntry[0])) {
1869                     // Return a blacklist match request blocked.
1870                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, FINAL_BLACKLIST, blacklistEntry[0], blacklistEntry[1])
1871                 }
1872
1873                 // There are two entries.
1874                 3 -> if (resourceUrl.contains(blacklistEntry[0]) && resourceUrl.endsWith(blacklistEntry[1])) {
1875                     // Return a blacklist match request blocked.
1876                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, FINAL_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}", blacklistEntry[2])
1877                 }
1878
1879                 // There are three entries.
1880                 4 -> if (resourceUrl.contains(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1]) && resourceUrl.endsWith(blacklistEntry[2])) {
1881                     // Return a blacklist match request blocked.
1882                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, FINAL_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}", blacklistEntry[3])
1883                 }
1884             }
1885         }
1886
1887         // Only check the domain lists if the current domain is not null (like `about:blank`).
1888         if (currentDomain != null) {
1889             // Domain blacklist.
1890             for (blacklistEntry in blocklist[DOMAIN_BLACKLIST.toInt()]) {
1891                 when (blacklistEntry.size) {
1892                     // There is one entry.
1893                     3 -> if (currentDomain.endsWith(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1])) {
1894                         // Return a blacklist match request blocked.
1895                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, DOMAIN_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}", blacklistEntry[2])
1896                     }
1897
1898                     // There are two entries.
1899                     4 -> if (currentDomain.endsWith(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1]) && resourceUrl.contains(blacklistEntry[2])) {
1900                         // Return a blacklist match request blocked.
1901                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, DOMAIN_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}", blacklistEntry[3])
1902                     }
1903
1904                     // There are three entries.
1905                     5 -> if (currentDomain.endsWith(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1]) && resourceUrl.contains(blacklistEntry[2]) && resourceUrl.contains(blacklistEntry[3])) {
1906                         // Return a blacklist match request blocked.
1907                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, DOMAIN_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}\n${blacklistEntry[3]}", blacklistEntry[4])
1908                     }
1909                 }
1910             }
1911
1912             // Domain initial blacklist.
1913             for (blacklistEntry in blocklist[DOMAIN_INITIAL_BLACKLIST.toInt()]) {
1914                 // Store the entry in the resource request log.
1915                 if (currentDomain.endsWith(blacklistEntry[0]) && resourceUrl.startsWith(blacklistEntry[1])) {
1916                     // Return a blacklist match request blocked.
1917                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, DOMAIN_INITIAL_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}", blacklistEntry[2])
1918                 }
1919             }
1920
1921             // Domain final blacklist.
1922             for (blacklistEntry in blocklist[DOMAIN_FINAL_BLACKLIST.toInt()]) {
1923                 when (blacklistEntry.size) {
1924                     // There is one entry.
1925                     3 -> if (currentDomain.endsWith(blacklistEntry[0]) && resourceUrl.endsWith(blacklistEntry[1])) {
1926                         // Return a blacklist match request blocked.
1927                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, DOMAIN_FINAL_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}", blacklistEntry[2])
1928                     }
1929
1930                     // There are two entries.
1931                     4 -> if (currentDomain.endsWith(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1]) && resourceUrl.endsWith(blacklistEntry[2])) {
1932                         // Return a blacklist match request blocked.
1933                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, DOMAIN_FINAL_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}", blacklistEntry[3])
1934                     }
1935                 }
1936             }
1937
1938             // Domain regular expression blacklist.
1939             for (blacklistEntry in blocklist[DOMAIN_REGULAR_EXPRESSION_BLACKLIST.toInt()]) {
1940                 if (currentDomain.endsWith(blacklistEntry[0]) && Pattern.matches(blacklistEntry[1], resourceUrl)) {
1941                     // Return a blacklist match request blocked.
1942                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, DOMAIN_REGULAR_EXPRESSION_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}", blacklistEntry[2])
1943                 }
1944             }
1945         }
1946
1947         // Only check the third-party blacklists if this is a third-party request.
1948         if (isThirdPartyRequest) {
1949             // Third-party blacklist.
1950             for (blacklistEntry in blocklist[THIRD_PARTY_BLACKLIST.toInt()]) {
1951                 when (blacklistEntry.size) {
1952                     // There is one entry.
1953                     2 -> if (resourceUrl.contains(blacklistEntry[0])) {
1954                         // Return a blacklist match request blocked.
1955                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_BLACKLIST, blacklistEntry[0], blacklistEntry[1])
1956                     }
1957
1958                     // There are two entries.
1959                     3 -> if (resourceUrl.contains(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1])) {
1960                         // Return a blacklist match request blocked.
1961                         return arrayOf(
1962                             REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n", blacklistEntry[2])
1963                     }
1964
1965                     // There are three entries.
1966                     4 -> if (resourceUrl.contains(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1]) && resourceUrl.contains(blacklistEntry[2])) {
1967                         // Return a blacklist match request blocked.
1968                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}", blacklistEntry[3])
1969                     }
1970
1971                     // There are four entries.
1972                     5 -> if (resourceUrl.contains(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1]) && resourceUrl.contains(blacklistEntry[2]) && resourceUrl.contains(blacklistEntry[3])) {
1973                         // Return a blacklist match request blocked.
1974                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}\n${blacklistEntry[3]}",
1975                             blacklistEntry[4])
1976                     }
1977                 }
1978             }
1979
1980             // Third-party initial blacklist.
1981             for (blacklistEntry in blocklist[THIRD_PARTY_INITIAL_BLACKLIST.toInt()]) {
1982                 when (blacklistEntry.size) {
1983                     // There is one entry.
1984                     2 -> if (resourceUrl.startsWith(blacklistEntry[0])) {
1985                         // Return a blacklist match request blocked.
1986                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_INITIAL_BLACKLIST, blacklistEntry[0], blacklistEntry[1])
1987                     }
1988
1989                     // There are two entries.
1990                     3 -> if (resourceUrl.startsWith(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1])) {
1991                         // Return a blacklist match request blocked.
1992                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_INITIAL_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}", blacklistEntry[2])
1993                     }
1994                 }
1995             }
1996
1997             // Third-party domain blacklist.
1998             for (blacklistEntry in blocklist[THIRD_PARTY_DOMAIN_BLACKLIST.toInt()]) {
1999                 when (blacklistEntry.size) {
2000                     // There is one entry.
2001                     3 -> if (currentDomain!!.endsWith(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1])) {
2002                         // Return a blacklist match request blocked.
2003                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_DOMAIN_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}", blacklistEntry[2])
2004                     }
2005
2006                     // There are two entries.
2007                     4 -> if (currentDomain!!.endsWith(blacklistEntry[0]) && resourceUrl.contains(blacklistEntry[1]) && resourceUrl.contains(blacklistEntry[2])) {
2008                         // Return a blacklist match request blocked.
2009                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_DOMAIN_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}", blacklistEntry[3])
2010                     }
2011                 }
2012             }
2013
2014             // Third-party domain initial blacklist.
2015             for (blacklistEntry in blocklist[THIRD_PARTY_DOMAIN_INITIAL_BLACKLIST.toInt()]) {
2016                 when (blacklistEntry.size) {
2017                     // There is one entry.
2018                     3 -> if (currentDomain!!.endsWith(blacklistEntry[0]) && resourceUrl.startsWith(blacklistEntry[1])) {
2019                         // Return a blacklist match request blocked.
2020                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_DOMAIN_INITIAL_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n", blacklistEntry[2])
2021                     }
2022
2023                     // There are two entries.
2024                     4 -> if (currentDomain!!.endsWith(blacklistEntry[0]) && resourceUrl.startsWith(blacklistEntry[1]) && resourceUrl.contains(blacklistEntry[2])) {
2025                         // Return a blacklist match request blocked.
2026                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_DOMAIN_INITIAL_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}", blacklistEntry[3])
2027                     }
2028
2029                     // There are three entries.
2030                     5 -> if (currentDomain!!.endsWith(blacklistEntry[0]) && resourceUrl.startsWith(blacklistEntry[1]) && resourceUrl.contains(blacklistEntry[2]) && resourceUrl.contains(blacklistEntry[3])) {
2031                         // Return a blacklist match request blocked.
2032                         return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_DOMAIN_INITIAL_BLACKLIST,
2033                             "${blacklistEntry[0]}\n${blacklistEntry[1]}\n${blacklistEntry[2]}\n${blacklistEntry[3]}", blacklistEntry[4])
2034                     }
2035                 }
2036             }
2037
2038             // Third-party regular expression blacklist.
2039             for (blacklistEntry in blocklist[THIRD_PARTY_REGULAR_EXPRESSION_BLACKLIST.toInt()]) {
2040                 if (Pattern.matches(blacklistEntry[0], resourceUrl)) {
2041                     // Return a blacklist match request blocked.
2042                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_REGULAR_EXPRESSION_BLACKLIST, blacklistEntry[0], blacklistEntry[1])
2043                 }
2044             }
2045
2046             // Third-party domain regular expression blacklist.
2047             for (blacklistEntry in blocklist[THIRD_PARTY_DOMAIN_REGULAR_EXPRESSION_BLACKLIST.toInt()]) {
2048                 if (currentDomain!!.endsWith(blacklistEntry[0]) && Pattern.matches(blacklistEntry[1], resourceUrl)) {
2049                     // Return a blacklist match request blocked.
2050                     return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, THIRD_PARTY_DOMAIN_REGULAR_EXPRESSION_BLACKLIST, "${blacklistEntry[0]}\n${blacklistEntry[1]}", blacklistEntry[2])
2051                 }
2052             }
2053         }
2054
2055         // Regular expression blacklist.
2056         for (blacklistEntry in blocklist[REGULAR_EXPRESSION_BLACKLIST.toInt()]) {
2057             if (Pattern.matches(blacklistEntry[0], resourceUrl)) {
2058                 // Return a blacklist match request blocked.
2059                 return arrayOf(REQUEST_BLOCKED, resourceUrl, blocklistName, REGULAR_EXPRESSION_BLACKLIST, blacklistEntry[0], blacklistEntry[1])
2060             }
2061         }
2062
2063         // Return a no match request default.
2064         return arrayOf(REQUEST_DEFAULT)
2065     }
2066 }