Database.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/OwnPtr.h>
  7. #include <AK/RefPtr.h>
  8. #include <AK/StringView.h>
  9. #include "Database.h"
  10. namespace USBDB {
  11. RefPtr<Database> Database::open(ByteString const& filename)
  12. {
  13. auto file_or_error = Core::MappedFile::map(filename);
  14. if (file_or_error.is_error())
  15. return nullptr;
  16. auto res = adopt_ref(*new Database(file_or_error.release_value()));
  17. if (res->init() != 0)
  18. return nullptr;
  19. return res;
  20. }
  21. const StringView Database::get_vendor(u16 vendor_id) const
  22. {
  23. auto const& vendor = m_vendors.get(vendor_id);
  24. if (!vendor.has_value())
  25. return ""sv;
  26. return vendor.value()->name;
  27. }
  28. const StringView Database::get_device(u16 vendor_id, u16 device_id) const
  29. {
  30. auto const& vendor = m_vendors.get(vendor_id);
  31. if (!vendor.has_value()) {
  32. return ""sv;
  33. }
  34. auto const& device = vendor.value()->devices.get(device_id);
  35. if (!device.has_value())
  36. return ""sv;
  37. return device.value()->name;
  38. }
  39. const StringView Database::get_interface(u16 vendor_id, u16 device_id, u16 interface_id) const
  40. {
  41. auto const& vendor = m_vendors.get(vendor_id);
  42. if (!vendor.has_value())
  43. return ""sv;
  44. auto const& device = vendor.value()->devices.get(device_id);
  45. if (!device.has_value())
  46. return ""sv;
  47. auto const& interface = device.value()->interfaces.get(interface_id);
  48. if (!interface.has_value())
  49. return ""sv;
  50. return interface.value()->name;
  51. }
  52. const StringView Database::get_class(u8 class_id) const
  53. {
  54. auto const& xclass = m_classes.get(class_id);
  55. if (!xclass.has_value())
  56. return ""sv;
  57. return xclass.value()->name;
  58. }
  59. const StringView Database::get_subclass(u8 class_id, u8 subclass_id) const
  60. {
  61. auto const& xclass = m_classes.get(class_id);
  62. if (!xclass.has_value())
  63. return ""sv;
  64. auto const& subclass = xclass.value()->subclasses.get(subclass_id);
  65. if (!subclass.has_value())
  66. return ""sv;
  67. return subclass.value()->name;
  68. }
  69. const StringView Database::get_protocol(u8 class_id, u8 subclass_id, u8 protocol_id) const
  70. {
  71. auto const& xclass = m_classes.get(class_id);
  72. if (!xclass.has_value())
  73. return ""sv;
  74. auto const& subclass = xclass.value()->subclasses.get(subclass_id);
  75. if (!subclass.has_value())
  76. return ""sv;
  77. auto const& protocol = subclass.value()->protocols.get(protocol_id);
  78. if (!protocol.has_value())
  79. return ""sv;
  80. return protocol.value()->name;
  81. }
  82. int Database::init()
  83. {
  84. if (m_ready)
  85. return 0;
  86. m_view = StringView { m_file->bytes() };
  87. ParseMode mode = ParseMode::UnknownMode;
  88. OwnPtr<Vendor> current_vendor {};
  89. OwnPtr<Device> current_device {};
  90. OwnPtr<Class> current_class {};
  91. OwnPtr<Subclass> current_subclass {};
  92. auto commit_device = [&]() {
  93. if (current_device && current_vendor) {
  94. auto id = current_device->id;
  95. current_vendor->devices.set(id, current_device.release_nonnull());
  96. }
  97. };
  98. auto commit_vendor = [&]() {
  99. commit_device();
  100. if (current_vendor) {
  101. auto id = current_vendor->id;
  102. m_vendors.set(id, current_vendor.release_nonnull());
  103. }
  104. };
  105. auto commit_subclass = [&]() {
  106. if (current_subclass && current_class) {
  107. auto id = current_subclass->id;
  108. current_class->subclasses.set(id, current_subclass.release_nonnull());
  109. }
  110. };
  111. auto commit_class = [&]() {
  112. commit_subclass();
  113. if (current_class) {
  114. auto id = current_class->id;
  115. m_classes.set(id, current_class.release_nonnull());
  116. }
  117. };
  118. auto commit_all = [&]() {
  119. commit_vendor();
  120. commit_class();
  121. };
  122. auto lines = m_view.split_view('\n');
  123. for (auto& line : lines) {
  124. if (line.length() < 2 || line[0] == '#')
  125. continue;
  126. if (line[0] == 'C') {
  127. mode = ParseMode::ClassMode;
  128. commit_all();
  129. } else if ((line[0] >= '0' && line[0] <= '9') || (line[0] >= 'a' && line[0] <= 'f')) {
  130. mode = ParseMode::VendorMode;
  131. commit_all();
  132. } else if (line[0] != '\t') {
  133. mode = ParseMode::UnknownMode;
  134. continue;
  135. }
  136. switch (mode) {
  137. case ParseMode::VendorMode:
  138. if (line[0] != '\t') {
  139. commit_vendor();
  140. current_vendor = make<Vendor>();
  141. current_vendor->id = AK::StringUtils::convert_to_uint_from_hex<u16>(line.substring_view(0, 4)).value_or(0);
  142. current_vendor->name = line.substring_view(6, line.length() - 6);
  143. } else if (line[0] == '\t' && line[1] != '\t') {
  144. commit_device();
  145. current_device = make<Device>();
  146. current_device->id = AK::StringUtils::convert_to_uint_from_hex<u16>((line.substring_view(1, 4))).value_or(0);
  147. current_device->name = line.substring_view(7, line.length() - 7);
  148. } else if (line[0] == '\t' && line[1] == '\t') {
  149. auto interface = make<Interface>();
  150. interface->interface = AK::StringUtils::convert_to_uint_from_hex<u16>((line.substring_view(2, 4))).value_or(0);
  151. interface->name = line.substring_view(7, line.length() - 7);
  152. current_device->interfaces.set(interface->interface, move(interface));
  153. }
  154. break;
  155. case ParseMode::ClassMode:
  156. if (line[0] != '\t') {
  157. commit_class();
  158. current_class = make<Class>();
  159. current_class->id = AK::StringUtils::convert_to_uint_from_hex<u16>((line.substring_view(2, 2))).value_or(0);
  160. current_class->name = line.substring_view(6, line.length() - 6);
  161. } else if (line[0] == '\t' && line[1] != '\t') {
  162. commit_subclass();
  163. current_subclass = make<Subclass>();
  164. current_subclass->id = AK::StringUtils::convert_to_uint_from_hex<u16>((line.substring_view(1, 2))).value_or(0);
  165. current_subclass->name = line.substring_view(5, line.length() - 5);
  166. } else if (line[0] == '\t' && line[1] == '\t') {
  167. auto protocol = make<Protocol>();
  168. protocol->id = AK::StringUtils::convert_to_uint_from_hex<u16>((line.substring_view(2, 2))).value_or(0);
  169. protocol->name = line.substring_view(6, line.length() - 6);
  170. current_subclass->protocols.set(protocol->id, move(protocol));
  171. }
  172. break;
  173. default:
  174. break;
  175. }
  176. }
  177. commit_all();
  178. m_ready = true;
  179. return 0;
  180. }
  181. }