GeneratePublicSuffixData.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Copyright (c) 2023, Cameron Youell <cameronyouell@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "../LibUnicode/GeneratorUtil.h"
  7. #include <AK/SourceGenerator.h>
  8. #include <AK/StringBuilder.h>
  9. #include <LibCore/ArgsParser.h>
  10. #include <LibCore/File.h>
  11. #include <LibMain/Main.h>
  12. ErrorOr<void> generate_header_file(Core::InputBufferedFile&, Core::File&);
  13. ErrorOr<void> generate_implementation_file(Core::InputBufferedFile&, Core::File&);
  14. ErrorOr<int> serenity_main(Main::Arguments arguments)
  15. {
  16. StringView generated_header_path;
  17. StringView generated_implementation_path;
  18. StringView public_suffix_list_path;
  19. Core::ArgsParser args_parser;
  20. args_parser.add_option(generated_header_path, "Path to the header file to generate", "generated-header-path", 'h', "generated-header-path");
  21. args_parser.add_option(generated_implementation_path, "Path to the implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
  22. args_parser.add_option(public_suffix_list_path, "Path to the public suffix list", "public-suffix-list-path", 'p', "public-suffix-list-path");
  23. args_parser.parse(arguments);
  24. auto identifier_data = TRY(open_file(public_suffix_list_path, Core::File::OpenMode::Read));
  25. auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
  26. auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
  27. TRY(generate_header_file(*identifier_data, *generated_header_file));
  28. TRY(generate_implementation_file(*identifier_data, *generated_implementation_file));
  29. return 0;
  30. }
  31. ErrorOr<void> generate_header_file(Core::InputBufferedFile&, Core::File& file)
  32. {
  33. StringBuilder builder;
  34. SourceGenerator generator { builder };
  35. generator.append(R"~~~(
  36. #pragma once
  37. #include <AK/DeprecatedString.h>
  38. #include <AK/Forward.h>
  39. #include <AK/Trie.h>
  40. namespace WebView {
  41. class PublicSuffixData {
  42. protected:
  43. PublicSuffixData();
  44. public:
  45. PublicSuffixData(PublicSuffixData const&) = delete;
  46. PublicSuffixData& operator=(PublicSuffixData const&) = delete;
  47. static PublicSuffixData* the()
  48. {
  49. static PublicSuffixData* s_the;
  50. if (!s_the)
  51. s_the = new PublicSuffixData;
  52. return s_the;
  53. }
  54. bool is_public_suffix(StringView host);
  55. ErrorOr<Optional<String>> get_public_suffix(StringView string);
  56. private:
  57. Trie<char, DeprecatedString> m_dictionary;
  58. };
  59. }
  60. )~~~");
  61. TRY(file.write_until_depleted(generator.as_string_view().bytes()));
  62. return {};
  63. }
  64. ErrorOr<void> generate_implementation_file(Core::InputBufferedFile& input, Core::File& file)
  65. {
  66. StringBuilder builder;
  67. SourceGenerator generator { builder };
  68. generator.append(R"~~~(
  69. #include <AK/String.h>
  70. #include <AK/Vector.h>
  71. #include <LibWebView/PublicSuffixData.h>
  72. namespace WebView {
  73. static constexpr auto s_public_suffixes = Array {)~~~");
  74. Array<u8, 1024> buffer {};
  75. while (TRY(input.can_read_line())) {
  76. auto line = TRY(input.read_line(buffer));
  77. if (line.starts_with("//"sv) || line.is_empty())
  78. continue;
  79. auto view = line.split_view("."sv);
  80. view.reverse();
  81. StringBuilder builder;
  82. builder.join("."sv, view);
  83. auto val = builder.string_view();
  84. generator.set("line", val);
  85. generator.append(R"~~~(
  86. "@line@"sv,)~~~");
  87. }
  88. generator.append(R"~~~(
  89. };
  90. PublicSuffixData::PublicSuffixData()
  91. : m_dictionary('/', "")
  92. {
  93. // FIXME: Reduce the depth of this trie
  94. for (auto str : s_public_suffixes) {
  95. MUST(m_dictionary.insert(str.begin(), str.end(), str, [](auto& parent, auto& it) -> Optional<DeprecatedString> {
  96. return DeprecatedString::formatted("{}{}", parent.metadata_value(), *it);
  97. }));
  98. }
  99. }
  100. bool PublicSuffixData::is_public_suffix(StringView host)
  101. {
  102. auto it = host.begin();
  103. auto& node = m_dictionary.traverse_until_last_accessible_node(it, host.end());
  104. return it.is_end() && node.metadata().has_value();
  105. }
  106. ErrorOr<Optional<String>> PublicSuffixData::get_public_suffix(StringView string)
  107. {
  108. auto input = string.split_view("."sv);
  109. input.reverse();
  110. StringBuilder overall_search_string;
  111. StringBuilder search_string;
  112. for (auto part : input) {
  113. search_string.clear();
  114. TRY(search_string.try_append(TRY(overall_search_string.to_string())));
  115. TRY(search_string.try_append(part));
  116. if (is_public_suffix(search_string.string_view())) {
  117. overall_search_string.append(TRY(String::from_utf8(part)));
  118. overall_search_string.append("."sv);
  119. continue;
  120. }
  121. search_string.clear();
  122. TRY(search_string.try_append(TRY(overall_search_string.to_string())));
  123. TRY(search_string.try_append("*"sv));
  124. if (is_public_suffix(search_string.string_view())) {
  125. overall_search_string.append(TRY(String::from_utf8(part)));
  126. overall_search_string.append("."sv);
  127. continue;
  128. }
  129. break;
  130. }
  131. auto view = overall_search_string.string_view().split_view("."sv);
  132. view.reverse();
  133. StringBuilder return_string_builder;
  134. return_string_builder.join('.', view);
  135. auto returnString = TRY(return_string_builder.to_string());
  136. if (!returnString.is_empty())
  137. return returnString;
  138. return Optional<String> {};
  139. }
  140. }
  141. )~~~");
  142. TRY(file.write_until_depleted(generator.as_string_view().bytes()));
  143. return {};
  144. }