Database.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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 PCIDB {
  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. auto const& device = vendor.value()->devices.get(device_id);
  34. if (!device.has_value())
  35. return ""sv;
  36. return device.value()->name;
  37. }
  38. const StringView Database::get_subsystem(u16 vendor_id, u16 device_id, u16 subvendor_id, u16 subdevice_id) const
  39. {
  40. auto const& vendor = m_vendors.get(vendor_id);
  41. if (!vendor.has_value())
  42. return ""sv;
  43. auto const& device = vendor.value()->devices.get(device_id);
  44. if (!device.has_value())
  45. return ""sv;
  46. auto const& subsystem = device.value()->subsystems.get((subvendor_id << 16) + subdevice_id);
  47. if (!subsystem.has_value())
  48. return ""sv;
  49. return subsystem.value()->name;
  50. }
  51. const StringView Database::get_class(u8 class_id) const
  52. {
  53. auto const& xclass = m_classes.get(class_id);
  54. if (!xclass.has_value())
  55. return ""sv;
  56. return xclass.value()->name;
  57. }
  58. const StringView Database::get_subclass(u8 class_id, u8 subclass_id) const
  59. {
  60. auto const& xclass = m_classes.get(class_id);
  61. if (!xclass.has_value())
  62. return ""sv;
  63. auto const& subclass = xclass.value()->subclasses.get(subclass_id);
  64. if (!subclass.has_value())
  65. return ""sv;
  66. return subclass.value()->name;
  67. }
  68. const StringView Database::get_programming_interface(u8 class_id, u8 subclass_id, u8 programming_interface_id) const
  69. {
  70. auto const& xclass = m_classes.get(class_id);
  71. if (!xclass.has_value())
  72. return ""sv;
  73. auto const& subclass = xclass.value()->subclasses.get(subclass_id);
  74. if (!subclass.has_value())
  75. return ""sv;
  76. auto const& programming_interface = subclass.value()->programming_interfaces.get(programming_interface_id);
  77. if (!programming_interface.has_value())
  78. return ""sv;
  79. return programming_interface.value()->name;
  80. }
  81. static u8 parse_hex_digit(char digit)
  82. {
  83. if (digit >= '0' && digit <= '9')
  84. return digit - '0';
  85. VERIFY(digit >= 'a' && digit <= 'f');
  86. return 10 + (digit - 'a');
  87. }
  88. template<typename T>
  89. static T parse_hex(StringView str, size_t count)
  90. {
  91. VERIFY(str.length() >= count);
  92. T res = 0;
  93. for (size_t i = 0; i < count; i++)
  94. res = (res << 4) + parse_hex_digit(str[i]);
  95. return res;
  96. }
  97. int Database::init()
  98. {
  99. if (m_ready)
  100. return 0;
  101. m_view = StringView { m_file->bytes() };
  102. ParseMode mode = ParseMode::UnknownMode;
  103. OwnPtr<Vendor> current_vendor {};
  104. OwnPtr<Device> current_device {};
  105. OwnPtr<Class> current_class {};
  106. OwnPtr<Subclass> current_subclass {};
  107. auto commit_device = [&]() {
  108. if (current_device && current_vendor) {
  109. auto id = current_device->id;
  110. current_vendor->devices.set(id, current_device.release_nonnull());
  111. }
  112. };
  113. auto commit_vendor = [&]() {
  114. commit_device();
  115. if (current_vendor) {
  116. auto id = current_vendor->id;
  117. m_vendors.set(id, current_vendor.release_nonnull());
  118. }
  119. };
  120. auto commit_subclass = [&]() {
  121. if (current_subclass && current_class) {
  122. auto id = current_subclass->id;
  123. current_class->subclasses.set(id, current_subclass.release_nonnull());
  124. }
  125. };
  126. auto commit_class = [&]() {
  127. commit_subclass();
  128. if (current_class) {
  129. auto id = current_class->id;
  130. m_classes.set(id, current_class.release_nonnull());
  131. }
  132. };
  133. auto commit_all = [&]() {
  134. commit_vendor();
  135. commit_class();
  136. };
  137. auto lines = m_view.split_view('\n');
  138. for (auto& line : lines) {
  139. if (line.length() < 2 || line[0] == '#')
  140. continue;
  141. if (line[0] == 'C') {
  142. mode = ParseMode::ClassMode;
  143. commit_all();
  144. } else if ((line[0] >= '0' && line[0] <= '9') || (line[0] >= 'a' && line[0] <= 'f')) {
  145. mode = ParseMode::VendorMode;
  146. commit_all();
  147. } else if (line[0] != '\t') {
  148. mode = ParseMode::UnknownMode;
  149. continue;
  150. }
  151. switch (mode) {
  152. case ParseMode::VendorMode:
  153. if (line[0] != '\t') {
  154. commit_vendor();
  155. current_vendor = make<Vendor>();
  156. current_vendor->id = parse_hex<u16>(line, 4);
  157. current_vendor->name = line.substring_view(6, line.length() - 6);
  158. } else if (line[0] == '\t' && line[1] != '\t') {
  159. commit_device();
  160. current_device = make<Device>();
  161. current_device->id = parse_hex<u16>(line.substring_view(1, line.length() - 1), 4);
  162. current_device->name = line.substring_view(7, line.length() - 7);
  163. } else if (line[0] == '\t' && line[1] == '\t') {
  164. auto subsystem = make<Subsystem>();
  165. subsystem->vendor_id = parse_hex<u16>(line.substring_view(2, 4), 4);
  166. subsystem->device_id = parse_hex<u16>(line.substring_view(7, 4), 4);
  167. subsystem->name = line.substring_view(13, line.length() - 13);
  168. current_device->subsystems.set((subsystem->vendor_id << 8) + subsystem->device_id, move(subsystem));
  169. }
  170. break;
  171. case ParseMode::ClassMode:
  172. if (line[0] != '\t') {
  173. commit_class();
  174. current_class = make<Class>();
  175. current_class->id = parse_hex<u8>(line.substring_view(2, 2), 2);
  176. current_class->name = line.substring_view(6, line.length() - 6);
  177. } else if (line[0] == '\t' && line[1] != '\t') {
  178. commit_subclass();
  179. current_subclass = make<Subclass>();
  180. current_subclass->id = parse_hex<u8>(line.substring_view(1, 2), 2);
  181. current_subclass->name = line.substring_view(5, line.length() - 5);
  182. } else if (line[0] == '\t' && line[1] == '\t') {
  183. auto programming_interface = make<ProgrammingInterface>();
  184. programming_interface->id = parse_hex<u8>(line.substring_view(2, 2), 2);
  185. programming_interface->name = line.substring_view(6, line.length() - 6);
  186. current_subclass->programming_interfaces.set(programming_interface->id, move(programming_interface));
  187. }
  188. break;
  189. default:
  190. break;
  191. }
  192. }
  193. commit_all();
  194. m_ready = true;
  195. return 0;
  196. }
  197. }