Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: chrome/browser/chromeos/printing/usb_printer_util.cc

Issue 2777013003: Construct an id for USB printers so it is stable across plugins and (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698