| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/printing/usb_printer_util.h" | 5 #include "chrome/browser/chromeos/printing/usb_printer_util.h" |
| 6 | 6 |
| 7 #include <ctype.h> | 7 #include <ctype.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/big_endian.h" |
| 12 #include "base/md5.h" |
| 11 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
| 14 #include "base/strings/string16.h" |
| 15 #include "base/strings/string_piece.h" |
| 12 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
| 13 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
| 14 #include "chromeos/printing/printer_configuration.h" | 18 #include "chromeos/printing/printer_configuration.h" |
| 15 #include "device/usb/usb_device.h" | 19 #include "device/usb/usb_device.h" |
| 16 #include "device/usb/usb_device_filter.h" | 20 #include "device/usb/usb_device_filter.h" |
| 17 #include "ui/base/l10n/l10n_util.h" | 21 #include "ui/base/l10n/l10n_util.h" |
| 18 | 22 |
| 19 namespace chromeos { | 23 namespace chromeos { |
| 20 namespace { | 24 namespace { |
| 21 | 25 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 41 buf.push_back('%'); | 45 buf.push_back('%'); |
| 42 buf.push_back(kHexDigits[(c >> 4) & 0xf]); | 46 buf.push_back(kHexDigits[(c >> 4) & 0xf]); |
| 43 buf.push_back(kHexDigits[c & 0xf]); | 47 buf.push_back(kHexDigits[c & 0xf]); |
| 44 } else { | 48 } else { |
| 45 buf.push_back(c); | 49 buf.push_back(c); |
| 46 } | 50 } |
| 47 } | 51 } |
| 48 return std::string(buf.data(), buf.size()); | 52 return std::string(buf.data(), buf.size()); |
| 49 } | 53 } |
| 50 | 54 |
| 55 // Incorporate the bytes of |val| into the incremental hash carried in |ctx| in |
| 56 // big-endian order. |val| must be a simple integer type |
| 57 template <typename T> |
| 58 void MD5UpdateBigEndian(base::MD5Context* ctx, T val) { |
| 59 static_assert(std::is_integral<T>::value, "Value must be an integer"); |
| 60 char buf[sizeof(T)]; |
| 61 base::WriteBigEndian(buf, val); |
| 62 base::MD5Update(ctx, base::StringPiece(buf, sizeof(T))); |
| 63 } |
| 64 |
| 65 // Update the hash with the contents of |str|. |
| 66 // |
| 67 // UTF-16 strings are a bit fraught for consistency in memory representation; |
| 68 // endianness is an issue, but more importantly, there are *optional* prefix |
| 69 // codepoints to identify the endianness of the string. |
| 70 // |
| 71 // This is a long way to say "UTF-16 is hard to hash, let's just convert |
| 72 // to UTF-8 and hash that", which avoids all of these issues. |
| 73 void MD5UpdateString16(base::MD5Context* ctx, const base::string16& str) { |
| 74 std::string tmp = base::UTF16ToUTF8(str); |
| 75 base::MD5Update(ctx, base::StringPiece(tmp.data(), tmp.size())); |
| 76 } |
| 77 |
| 78 // Get the usb printer id for |device|. This is used both as the identifier for |
| 79 // the printer in the user's PrintersManager and as the name of the printer in |
| 80 // CUPS, so it has to satisfy the naming restrictions of both. CUPS in |
| 81 // particular is intolerant of much more than [a-z0-9_-], so we use that |
| 82 // character set. This needs to be stable for a given device, but as unique as |
| 83 // possible for that device. So we basically toss every bit of stable |
| 84 // information from the device into an MD5 hash, and then hexify the hash value |
| 85 // as a suffix to "usb-" as the final printer id. |
| 86 std::string UsbPrinterId(const device::UsbDevice& device) { |
| 87 // Paranoid checks; in the unlikely event someone messes with the USB device |
| 88 // definition, our (supposedly stable) hashes will change. |
| 89 static_assert(sizeof(device.device_class()) == 1, "Class size changed"); |
| 90 static_assert(sizeof(device.device_subclass()) == 1, "Subclass size changed"); |
| 91 static_assert(sizeof(device.device_protocol()) == 1, "Protocol size changed"); |
| 92 static_assert(sizeof(device.vendor_id()) == 2, "Vendor id size changed"); |
| 93 static_assert(sizeof(device.product_id()) == 2, "Product id size changed"); |
| 94 static_assert(sizeof(device.device_version()) == 2, "Version size changed"); |
| 95 |
| 96 base::MD5Context ctx; |
| 97 base::MD5Init(&ctx); |
| 98 MD5UpdateBigEndian(&ctx, device.device_class()); |
| 99 MD5UpdateBigEndian(&ctx, device.device_subclass()); |
| 100 MD5UpdateBigEndian(&ctx, device.device_protocol()); |
| 101 MD5UpdateBigEndian(&ctx, device.vendor_id()); |
| 102 MD5UpdateBigEndian(&ctx, device.product_id()); |
| 103 MD5UpdateBigEndian(&ctx, device.device_version()); |
| 104 MD5UpdateString16(&ctx, device.manufacturer_string()); |
| 105 MD5UpdateString16(&ctx, device.product_string()); |
| 106 MD5UpdateString16(&ctx, device.serial_number()); |
| 107 base::MD5Digest digest; |
| 108 base::MD5Final(&digest, &ctx); |
| 109 return base::StringPrintf("usb-%s", base::MD5DigestToBase16(digest).c_str()); |
| 110 } |
| 111 |
| 51 } // namespace | 112 } // namespace |
| 52 | 113 |
| 53 bool UsbDeviceIsPrinter(scoped_refptr<device::UsbDevice> usb_device) { | 114 bool UsbDeviceIsPrinter(scoped_refptr<device::UsbDevice> usb_device) { |
| 54 device::UsbDeviceFilter printer_filter; | 115 device::UsbDeviceFilter printer_filter; |
| 55 printer_filter.interface_class = kPrinterInterfaceClass; | 116 printer_filter.interface_class = kPrinterInterfaceClass; |
| 56 return printer_filter.Matches(usb_device); | 117 return printer_filter.Matches(usb_device); |
| 57 } | 118 } |
| 58 | 119 |
| 59 std::string UsbPrinterDeviceDetailsAsString(const device::UsbDevice& device) { | 120 std::string UsbPrinterDeviceDetailsAsString(const device::UsbDevice& device) { |
| 60 return base::StringPrintf( | 121 return base::StringPrintf( |
| (...skipping 29 matching lines...) Expand all Loading... |
| 90 return nullptr; | 151 return nullptr; |
| 91 } | 152 } |
| 92 | 153 |
| 93 auto printer = base::MakeUnique<Printer>(); | 154 auto printer = base::MakeUnique<Printer>(); |
| 94 printer->set_manufacturer(base::UTF16ToUTF8(device.manufacturer_string())); | 155 printer->set_manufacturer(base::UTF16ToUTF8(device.manufacturer_string())); |
| 95 printer->set_model(base::UTF16ToUTF8(device.product_string())); | 156 printer->set_model(base::UTF16ToUTF8(device.product_string())); |
| 96 printer->set_display_name(base::StringPrintf("%s %s (USB)", | 157 printer->set_display_name(base::StringPrintf("%s %s (USB)", |
| 97 printer->manufacturer().c_str(), | 158 printer->manufacturer().c_str(), |
| 98 printer->model().c_str())); | 159 printer->model().c_str())); |
| 99 printer->set_description(printer->display_name()); | 160 printer->set_description(printer->display_name()); |
| 100 | |
| 101 printer->set_uri(UsbPrinterUri(device)); | 161 printer->set_uri(UsbPrinterUri(device)); |
| 162 printer->set_id(UsbPrinterId(device)); |
| 102 return printer; | 163 return printer; |
| 103 } | 164 } |
| 104 | 165 |
| 105 std::string UsbPrinterUri(const device::UsbDevice& device) { | 166 std::string UsbPrinterUri(const device::UsbDevice& device) { |
| 106 // Note that serial may, for some devices, be empty or bogus (all zeros, non | 167 // Note that serial may, for some devices, be empty or bogus (all zeros, non |
| 107 // unique, or otherwise not really a serial number), but having a non-unique | 168 // unique, or otherwise not really a serial number), but having a non-unique |
| 108 // or empty serial field in the URI still lets us print, it just means we | 169 // or empty serial field in the URI still lets us print, it just means we |
| 109 // don't have a way to uniquely identify a printer if there are multiple ones | 170 // don't have a way to uniquely identify a printer if there are multiple ones |
| 110 // plugged in with the same VID/PID, so we may print to the *wrong* printer. | 171 // plugged in with the same VID/PID, so we may print to the *wrong* printer. |
| 111 // There doesn't seem to be a robust solution to this problem; if printers | 172 // There doesn't seem to be a robust solution to this problem; if printers |
| 112 // don't supply a serial number, we don't have any reliable way to do that | 173 // don't supply a serial number, we don't have any reliable way to do that |
| 113 // differentiation. | 174 // differentiation. |
| 114 std::string serial = base::UTF16ToUTF8(device.serial_number()); | 175 std::string serial = base::UTF16ToUTF8(device.serial_number()); |
| 115 return CupsURIEscape(base::StringPrintf("usb://%04x/%04x?serial=%s", | 176 return CupsURIEscape(base::StringPrintf("usb://%04x/%04x?serial=%s", |
| 116 device.vendor_id(), | 177 device.vendor_id(), |
| 117 device.product_id(), serial.c_str())); | 178 device.product_id(), serial.c_str())); |
| 118 } | 179 } |
| 119 | 180 |
| 120 } // namespace chromeos | 181 } // namespace chromeos |
| OLD | NEW |