1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/storage_monitor/storage_info.h"
6
7#include "base/logging.h"
8#include "base/strings/utf_string_conversions.h"
9#include "components/storage_monitor/media_storage_util.h"
10#include "ui/base/l10n/l10n_util.h"
11#include "ui/base/text/bytes_formatting.h"
12
13namespace {
14
15// Prefix constants for different device id spaces.
16const char kRemovableMassStorageWithDCIMPrefix[] = "dcim:";
17const char kRemovableMassStorageNoDCIMPrefix[] = "nodcim:";
18const char kFixedMassStoragePrefix[] = "path:";
19const char kMtpPtpPrefix[] = "mtp:";
20const char kMacImageCapturePrefix[] = "ic:";
21const char kITunesPrefix[] = "itunes:";
22const char kPicasaPrefix[] = "picasa:";
23const char kIPhotoPrefix[] = "iphoto:";
24
25base::string16 GetDisplayNameForDevice(uint64 storage_size_in_bytes,
26                                       const base::string16& name) {
27  DCHECK(!name.empty());
28  return (storage_size_in_bytes == 0) ?
29      name :
30      ui::FormatBytes(storage_size_in_bytes) + base::ASCIIToUTF16(" ") + name;
31}
32
33base::string16 GetFullProductName(const base::string16& vendor_name,
34                                  const base::string16& model_name) {
35  if (vendor_name.empty() && model_name.empty())
36    return base::string16();
37
38  base::string16 product_name;
39  if (vendor_name.empty())
40    product_name = model_name;
41  else if (model_name.empty())
42    product_name = vendor_name;
43  else if (!vendor_name.empty() && !model_name.empty())
44    product_name = vendor_name + base::UTF8ToUTF16(", ") + model_name;
45
46  return product_name;
47}
48
49}  // namespace
50
51namespace storage_monitor {
52
53StorageInfo::StorageInfo() : total_size_in_bytes_(0) {
54}
55
56StorageInfo::StorageInfo(const std::string& device_id_in,
57                         const base::FilePath::StringType& device_location,
58                         const base::string16& label,
59                         const base::string16& vendor,
60                         const base::string16& model,
61                         uint64 size_in_bytes)
62    : device_id_(device_id_in),
63      location_(device_location),
64      storage_label_(label),
65      vendor_name_(vendor),
66      model_name_(model),
67      total_size_in_bytes_(size_in_bytes) {
68}
69
70StorageInfo::~StorageInfo() {
71}
72
73// static
74std::string StorageInfo::MakeDeviceId(Type type, const std::string& unique_id) {
75  DCHECK(!unique_id.empty());
76  switch (type) {
77    case REMOVABLE_MASS_STORAGE_WITH_DCIM:
78      return std::string(kRemovableMassStorageWithDCIMPrefix) + unique_id;
79    case REMOVABLE_MASS_STORAGE_NO_DCIM:
80      return std::string(kRemovableMassStorageNoDCIMPrefix) + unique_id;
81    case FIXED_MASS_STORAGE:
82      return std::string(kFixedMassStoragePrefix) + unique_id;
83    case MTP_OR_PTP:
84      return std::string(kMtpPtpPrefix) + unique_id;
85    case MAC_IMAGE_CAPTURE:
86      return std::string(kMacImageCapturePrefix) + unique_id;
87    case ITUNES:
88      return std::string(kITunesPrefix) + unique_id;
89    case PICASA:
90      return std::string(kPicasaPrefix) + unique_id;
91    case IPHOTO:
92      return std::string(kIPhotoPrefix) + unique_id;
93  }
94  NOTREACHED();
95  return std::string();
96}
97
98// static
99bool StorageInfo::CrackDeviceId(const std::string& device_id,
100                                Type* type, std::string* unique_id) {
101  size_t prefix_length = device_id.find_first_of(':');
102  std::string prefix = prefix_length != std::string::npos
103                           ? device_id.substr(0, prefix_length + 1)
104                           : std::string();
105
106  Type found_type;
107  if (prefix == kRemovableMassStorageWithDCIMPrefix) {
108    found_type = REMOVABLE_MASS_STORAGE_WITH_DCIM;
109  } else if (prefix == kRemovableMassStorageNoDCIMPrefix) {
110    found_type = REMOVABLE_MASS_STORAGE_NO_DCIM;
111  } else if (prefix == kFixedMassStoragePrefix) {
112    found_type = FIXED_MASS_STORAGE;
113  } else if (prefix == kMtpPtpPrefix) {
114    found_type = MTP_OR_PTP;
115  } else if (prefix == kMacImageCapturePrefix) {
116    found_type = MAC_IMAGE_CAPTURE;
117  } else if (prefix == kITunesPrefix) {
118    found_type = ITUNES;
119  } else if (prefix == kPicasaPrefix) {
120    found_type = PICASA;
121  } else if (prefix == kIPhotoPrefix) {
122    found_type = IPHOTO;
123  } else {
124    NOTREACHED();
125    return false;
126  }
127  if (type)
128    *type = found_type;
129
130  if (unique_id)
131    *unique_id = device_id.substr(prefix_length + 1);
132  return true;
133}
134
135// static
136bool StorageInfo::IsMediaDevice(const std::string& device_id) {
137  Type type;
138  return CrackDeviceId(device_id, &type, NULL) &&
139      (type == REMOVABLE_MASS_STORAGE_WITH_DCIM || type == MTP_OR_PTP ||
140       type == MAC_IMAGE_CAPTURE);
141}
142
143// static
144bool StorageInfo::IsRemovableDevice(const std::string& device_id) {
145  Type type;
146  return CrackDeviceId(device_id, &type, NULL) &&
147         (type == REMOVABLE_MASS_STORAGE_WITH_DCIM ||
148          type == REMOVABLE_MASS_STORAGE_NO_DCIM ||
149          type == MTP_OR_PTP ||
150          type == MAC_IMAGE_CAPTURE);
151}
152
153// static
154bool StorageInfo::IsMassStorageDevice(const std::string& device_id) {
155  Type type;
156  return CrackDeviceId(device_id, &type, NULL) &&
157         (type == REMOVABLE_MASS_STORAGE_WITH_DCIM ||
158          type == REMOVABLE_MASS_STORAGE_NO_DCIM ||
159          type == FIXED_MASS_STORAGE ||
160          type == ITUNES ||
161          type == IPHOTO ||
162          type == PICASA);
163}
164
165// static
166bool StorageInfo::IsITunesDevice(const std::string& device_id) {
167  Type type;
168  return CrackDeviceId(device_id, &type, NULL) && type == ITUNES;
169}
170
171// static
172bool StorageInfo::IsIPhotoDevice(const std::string& device_id) {
173  Type type;
174  return CrackDeviceId(device_id, &type, NULL) && type == IPHOTO;
175}
176
177// static
178bool StorageInfo::IsPicasaDevice(const std::string& device_id) {
179  Type type;
180  return CrackDeviceId(device_id, &type, NULL) && type == PICASA;
181}
182
183// static
184bool StorageInfo::IsMTPDevice(const std::string& device_id) {
185  Type type;
186  return CrackDeviceId(device_id, &type, NULL) && type == MTP_OR_PTP;
187}
188
189base::string16 StorageInfo::GetDisplayName(bool with_size) const {
190  return GetDisplayNameWithOverride(base::string16(), with_size);
191}
192
193base::string16 StorageInfo::GetDisplayNameWithOverride(
194    const base::string16& override_display_name, bool with_size) const {
195  if (!IsRemovableDevice(device_id_)) {
196    if (!storage_label_.empty())
197      return storage_label_;
198    return base::FilePath(location_).LossyDisplayName();
199  }
200
201  base::string16 name = override_display_name;
202  if (name.empty())
203    name = storage_label_;
204  if (name.empty())
205    name = GetFullProductName(vendor_name_, model_name_);
206  if (name.empty())
207    name = base::ASCIIToUTF16("Unlabeled device");
208
209  if (with_size)
210    name = GetDisplayNameForDevice(total_size_in_bytes_, name);
211  return name;
212}
213
214}  // namespace storage_monitor
215