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