OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "chrome/browser/autofill/credit_card.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <ostream> | |
10 #include <string> | |
11 | |
12 #include "base/basictypes.h" | |
13 #include "base/guid.h" | |
14 #include "base/logging.h" | |
15 #include "base/string16.h" | |
16 #include "base/string_util.h" | |
17 #include "base/strings/string_number_conversions.h" | |
18 #include "base/strings/string_split.h" | |
19 #include "base/utf_string_conversions.h" | |
20 #include "chrome/browser/autofill/autofill_country.h" | |
21 #include "chrome/browser/autofill/autofill_field.h" | |
22 #include "chrome/browser/autofill/autofill_regexes.h" | |
23 #include "chrome/browser/autofill/autofill_type.h" | |
24 #include "chrome/browser/autofill/field_types.h" | |
25 #include "chrome/browser/autofill/validation.h" | |
26 #include "components/autofill/common/form_field_data.h" | |
27 #include "grit/generated_resources.h" | |
28 #include "grit/webkit_resources.h" | |
29 #include "third_party/icu/public/common/unicode/uloc.h" | |
30 #include "third_party/icu/public/i18n/unicode/dtfmtsym.h" | |
31 #include "ui/base/l10n/l10n_util.h" | |
32 | |
33 namespace { | |
34 | |
35 const char16 kCreditCardObfuscationSymbol = '*'; | |
36 | |
37 // This is the maximum obfuscated symbols displayed. | |
38 // It is introduced to avoid rare cases where the credit card number is | |
39 // too large and fills the screen. | |
40 const size_t kMaxObfuscationSize = 20; | |
41 | |
42 std::string GetCreditCardType(const string16& number) { | |
43 // Don't check for a specific type if this is not a credit card number. | |
44 if (!autofill::IsValidCreditCardNumber(number)) | |
45 return kGenericCard; | |
46 | |
47 // Credit card number specifications taken from: | |
48 // http://en.wikipedia.org/wiki/Credit_card_numbers and | |
49 // http://www.beachnet.com/~hstiles/cardtype.html | |
50 // Card Type Prefix(es) Length | |
51 // --------------------------------------------------------------- | |
52 // Visa 4 13,16 | |
53 // American Express 34,37 15 | |
54 // Diners Club 300-305,2014,2149,36, 14,15 | |
55 // Discover Card 6011,65 16 | |
56 // JCB 3 16 | |
57 // JCB 2131,1800 15 | |
58 // MasterCard 51-55 16 | |
59 // Solo (debit card) 6334,6767 16,18,19 | |
60 | |
61 // We need at least 4 digits to work with. | |
62 if (number.length() < 4) | |
63 return kGenericCard; | |
64 | |
65 int first_four_digits = 0; | |
66 if (!base::StringToInt(number.substr(0, 4), &first_four_digits)) | |
67 return kGenericCard; | |
68 | |
69 int first_three_digits = first_four_digits / 10; | |
70 int first_two_digits = first_three_digits / 10; | |
71 int first_digit = first_two_digits / 10; | |
72 | |
73 switch (number.length()) { | |
74 case 13: | |
75 if (first_digit == 4) | |
76 return kVisaCard; | |
77 | |
78 break; | |
79 case 14: | |
80 if (first_three_digits >= 300 && first_three_digits <= 305) | |
81 return kDinersCard; | |
82 | |
83 if (first_digit == 36) | |
84 return kDinersCard; | |
85 | |
86 break; | |
87 case 15: | |
88 if (first_two_digits == 34 || first_two_digits == 37) | |
89 return kAmericanExpressCard; | |
90 | |
91 if (first_four_digits == 2131 || first_four_digits == 1800) | |
92 return kJCBCard; | |
93 | |
94 if (first_four_digits == 2014 || first_four_digits == 2149) | |
95 return kDinersCard; | |
96 | |
97 break; | |
98 case 16: | |
99 if (first_four_digits == 6011 || first_two_digits == 65) | |
100 return kDiscoverCard; | |
101 | |
102 if (first_four_digits == 6334 || first_four_digits == 6767) | |
103 return kSoloCard; | |
104 | |
105 if (first_two_digits >= 51 && first_two_digits <= 55) | |
106 return kMasterCard; | |
107 | |
108 if (first_digit == 3) | |
109 return kJCBCard; | |
110 | |
111 if (first_digit == 4) | |
112 return kVisaCard; | |
113 | |
114 break; | |
115 case 18: | |
116 case 19: | |
117 if (first_four_digits == 6334 || first_four_digits == 6767) | |
118 return kSoloCard; | |
119 | |
120 break; | |
121 } | |
122 | |
123 return kGenericCard; | |
124 } | |
125 | |
126 bool ConvertYear(const string16& year, int* num) { | |
127 // If the |year| is empty, clear the stored value. | |
128 if (year.empty()) { | |
129 *num = 0; | |
130 return true; | |
131 } | |
132 | |
133 // Try parsing the |year| as a number. | |
134 if (base::StringToInt(year, num)) | |
135 return true; | |
136 | |
137 *num = 0; | |
138 return false; | |
139 } | |
140 | |
141 bool ConvertMonth(const string16& month, | |
142 const std::string& app_locale, | |
143 int* num) { | |
144 // If the |month| is empty, clear the stored value. | |
145 if (month.empty()) { | |
146 *num = 0; | |
147 return true; | |
148 } | |
149 | |
150 // Try parsing the |month| as a number. | |
151 if (base::StringToInt(month, num)) | |
152 return true; | |
153 | |
154 // If the locale is unknown, give up. | |
155 if (app_locale.empty()) | |
156 return false; | |
157 | |
158 // Otherwise, try parsing the |month| as a named month, e.g. "January" or | |
159 // "Jan". | |
160 string16 lowercased_month = StringToLowerASCII(month); | |
161 | |
162 UErrorCode status = U_ZERO_ERROR; | |
163 icu::Locale locale(app_locale.c_str()); | |
164 icu::DateFormatSymbols date_format_symbols(locale, status); | |
165 DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING || | |
166 status == U_USING_DEFAULT_WARNING); | |
167 | |
168 int32_t num_months; | |
169 const icu::UnicodeString* months = date_format_symbols.getMonths(num_months); | |
170 for (int32_t i = 0; i < num_months; ++i) { | |
171 const string16 icu_month = string16(months[i].getBuffer(), | |
172 months[i].length()); | |
173 if (lowercased_month == StringToLowerASCII(icu_month)) { | |
174 *num = i + 1; // Adjust from 0-indexed to 1-indexed. | |
175 return true; | |
176 } | |
177 } | |
178 | |
179 months = date_format_symbols.getShortMonths(num_months); | |
180 for (int32_t i = 0; i < num_months; ++i) { | |
181 const string16 icu_month = string16(months[i].getBuffer(), | |
182 months[i].length()); | |
183 if (lowercased_month == StringToLowerASCII(icu_month)) { | |
184 *num = i + 1; // Adjust from 0-indexed to 1-indexed. | |
185 return true; | |
186 } | |
187 } | |
188 | |
189 *num = 0; | |
190 return false; | |
191 } | |
192 | |
193 } // namespace | |
194 | |
195 CreditCard::CreditCard(const std::string& guid) | |
196 : type_(kGenericCard), | |
197 expiration_month_(0), | |
198 expiration_year_(0), | |
199 guid_(guid) { | |
200 } | |
201 | |
202 CreditCard::CreditCard() | |
203 : type_(kGenericCard), | |
204 expiration_month_(0), | |
205 expiration_year_(0), | |
206 guid_(base::GenerateGUID()) { | |
207 } | |
208 | |
209 CreditCard::CreditCard(const CreditCard& credit_card) : FormGroup() { | |
210 operator=(credit_card); | |
211 } | |
212 | |
213 CreditCard::~CreditCard() {} | |
214 | |
215 // static | |
216 const string16 CreditCard::StripSeparators(const string16& number) { | |
217 const char16 kSeparators[] = {'-', ' ', '\0'}; | |
218 string16 stripped; | |
219 RemoveChars(number, kSeparators, &stripped); | |
220 return stripped; | |
221 } | |
222 | |
223 std::string CreditCard::GetGUID() const { | |
224 return guid(); | |
225 } | |
226 | |
227 string16 CreditCard::GetRawInfo(AutofillFieldType type) const { | |
228 switch (type) { | |
229 case CREDIT_CARD_NAME: | |
230 return name_on_card_; | |
231 | |
232 case CREDIT_CARD_EXP_MONTH: | |
233 return ExpirationMonthAsString(); | |
234 | |
235 case CREDIT_CARD_EXP_2_DIGIT_YEAR: | |
236 return Expiration2DigitYearAsString(); | |
237 | |
238 case CREDIT_CARD_EXP_4_DIGIT_YEAR: | |
239 return Expiration4DigitYearAsString(); | |
240 | |
241 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: { | |
242 string16 month = ExpirationMonthAsString(); | |
243 string16 year = Expiration2DigitYearAsString(); | |
244 if (!month.empty() && !year.empty()) | |
245 return month + ASCIIToUTF16("/") + year; | |
246 return string16(); | |
247 } | |
248 | |
249 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: { | |
250 string16 month = ExpirationMonthAsString(); | |
251 string16 year = Expiration4DigitYearAsString(); | |
252 if (!month.empty() && !year.empty()) | |
253 return month + ASCIIToUTF16("/") + year; | |
254 return string16(); | |
255 } | |
256 | |
257 case CREDIT_CARD_TYPE: | |
258 return TypeForDisplay(); | |
259 | |
260 case CREDIT_CARD_NUMBER: | |
261 return number_; | |
262 | |
263 case CREDIT_CARD_VERIFICATION_CODE: | |
264 // Chrome doesn't store credit card verification codes. | |
265 return string16(); | |
266 | |
267 default: | |
268 // ComputeDataPresentForArray will hit this repeatedly. | |
269 return string16(); | |
270 } | |
271 } | |
272 | |
273 void CreditCard::SetRawInfo(AutofillFieldType type, const string16& value) { | |
274 switch (type) { | |
275 case CREDIT_CARD_NAME: | |
276 name_on_card_ = value; | |
277 break; | |
278 | |
279 case CREDIT_CARD_EXP_MONTH: | |
280 SetExpirationMonthFromString(value, std::string()); | |
281 break; | |
282 | |
283 case CREDIT_CARD_EXP_2_DIGIT_YEAR: | |
284 // This is a read-only attribute. | |
285 break; | |
286 | |
287 case CREDIT_CARD_EXP_4_DIGIT_YEAR: | |
288 SetExpirationYearFromString(value); | |
289 break; | |
290 | |
291 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: | |
292 // This is a read-only attribute. | |
293 break; | |
294 | |
295 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: | |
296 // This is a read-only attribute. | |
297 break; | |
298 | |
299 case CREDIT_CARD_TYPE: | |
300 // This is a read-only attribute, determined by the credit card number. | |
301 break; | |
302 | |
303 case CREDIT_CARD_NUMBER: { | |
304 // Don't change the real value if the input is an obfuscated string. | |
305 if (value.size() > 0 && value[0] != kCreditCardObfuscationSymbol) | |
306 SetNumber(value); | |
307 break; | |
308 } | |
309 | |
310 case CREDIT_CARD_VERIFICATION_CODE: | |
311 // Chrome doesn't store the credit card verification code. | |
312 break; | |
313 | |
314 default: | |
315 NOTREACHED() << "Attempting to set unknown info-type " << type; | |
316 break; | |
317 } | |
318 } | |
319 | |
320 string16 CreditCard::GetInfo(AutofillFieldType type, | |
321 const std::string& app_locale) const { | |
322 if (type == CREDIT_CARD_NUMBER) | |
323 return StripSeparators(number_); | |
324 | |
325 return GetRawInfo(type); | |
326 } | |
327 | |
328 bool CreditCard::SetInfo(AutofillFieldType type, | |
329 const string16& value, | |
330 const std::string& app_locale) { | |
331 if (type == CREDIT_CARD_NUMBER) | |
332 SetRawInfo(type, StripSeparators(value)); | |
333 else if (type == CREDIT_CARD_EXP_MONTH) | |
334 SetExpirationMonthFromString(value, app_locale); | |
335 else | |
336 SetRawInfo(type, value); | |
337 | |
338 return true; | |
339 } | |
340 | |
341 void CreditCard::GetMatchingTypes(const string16& text, | |
342 const std::string& app_locale, | |
343 FieldTypeSet* matching_types) const { | |
344 FormGroup::GetMatchingTypes(text, app_locale, matching_types); | |
345 | |
346 string16 card_number = GetInfo(CREDIT_CARD_NUMBER, app_locale); | |
347 if (!card_number.empty() && StripSeparators(text) == card_number) | |
348 matching_types->insert(CREDIT_CARD_NUMBER); | |
349 | |
350 int month; | |
351 if (ConvertMonth(text, app_locale, &month) && month != 0 && | |
352 month == expiration_month_) { | |
353 matching_types->insert(CREDIT_CARD_EXP_MONTH); | |
354 } | |
355 } | |
356 | |
357 const string16 CreditCard::Label() const { | |
358 string16 label; | |
359 if (number().empty()) | |
360 return name_on_card_; // No CC number, return name only. | |
361 | |
362 string16 obfuscated_cc_number = ObfuscatedNumber(); | |
363 if (!expiration_month_ || !expiration_year_) | |
364 return obfuscated_cc_number; // No expiration date set. | |
365 | |
366 // TODO(georgey): Internationalize date. | |
367 string16 formatted_date(ExpirationMonthAsString()); | |
368 formatted_date.append(ASCIIToUTF16("/")); | |
369 formatted_date.append(Expiration4DigitYearAsString()); | |
370 | |
371 label = l10n_util::GetStringFUTF16(IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT, | |
372 obfuscated_cc_number, | |
373 formatted_date); | |
374 return label; | |
375 } | |
376 | |
377 void CreditCard::SetInfoForMonthInputType(const string16& value) { | |
378 // Check if |text| is "yyyy-mm" format first, and check normal month format. | |
379 if (!autofill::MatchesPattern(value, UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$"))) | |
380 return; | |
381 | |
382 std::vector<string16> year_month; | |
383 base::SplitString(value, L'-', &year_month); | |
384 DCHECK_EQ((int)year_month.size(), 2); | |
385 int num = 0; | |
386 bool converted = false; | |
387 converted = base::StringToInt(year_month[0], &num); | |
388 DCHECK(converted); | |
389 SetExpirationYear(num); | |
390 converted = base::StringToInt(year_month[1], &num); | |
391 DCHECK(converted); | |
392 SetExpirationMonth(num); | |
393 } | |
394 | |
395 string16 CreditCard::ObfuscatedNumber() const { | |
396 // If the number is shorter than four digits, there's no need to obfuscate it. | |
397 if (number_.size() < 4) | |
398 return number_; | |
399 | |
400 string16 number = StripSeparators(number_); | |
401 | |
402 // Avoid making very long obfuscated numbers. | |
403 size_t obfuscated_digits = std::min(kMaxObfuscationSize, number.size() - 4); | |
404 string16 result(obfuscated_digits, kCreditCardObfuscationSymbol); | |
405 return result.append(LastFourDigits()); | |
406 } | |
407 | |
408 string16 CreditCard::LastFourDigits() const { | |
409 static const size_t kNumLastDigits = 4; | |
410 | |
411 string16 number = StripSeparators(number_); | |
412 if (number.size() < kNumLastDigits) | |
413 return string16(); | |
414 | |
415 return number.substr(number.size() - kNumLastDigits, kNumLastDigits); | |
416 } | |
417 | |
418 string16 CreditCard::TypeForDisplay() const { | |
419 if (type_ == kAmericanExpressCard) | |
420 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX); | |
421 if (type_ == kDinersCard) | |
422 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DINERS); | |
423 if (type_ == kDiscoverCard) | |
424 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DISCOVER); | |
425 if (type_ == kJCBCard) | |
426 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_JCB); | |
427 if (type_ == kMasterCard) | |
428 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD); | |
429 if (type_ == kSoloCard) | |
430 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_SOLO); | |
431 if (type_ == kVisaCard) | |
432 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA); | |
433 | |
434 // If you hit this DCHECK, the above list of cases needs to be updated to | |
435 // include a new card. | |
436 DCHECK_EQ(kGenericCard, type_); | |
437 return string16(); | |
438 } | |
439 | |
440 string16 CreditCard::TypeAndLastFourDigits() const { | |
441 string16 type = TypeForDisplay(); | |
442 // TODO(estade): type may be empty, we probably want to return | |
443 // "Card - 1234" or something in that case. | |
444 | |
445 string16 digits = LastFourDigits(); | |
446 if (digits.empty()) | |
447 return type; | |
448 | |
449 // TODO(estade): i18n. | |
450 return type + ASCIIToUTF16(" - ") + digits; | |
451 } | |
452 | |
453 int CreditCard::IconResourceId() const { | |
454 if (type_ == kAmericanExpressCard) | |
455 return IDR_AUTOFILL_CC_AMEX; | |
456 if (type_ == kDinersCard) | |
457 return IDR_AUTOFILL_CC_DINERS; | |
458 if (type_ == kDiscoverCard) | |
459 return IDR_AUTOFILL_CC_DISCOVER; | |
460 if (type_ == kJCBCard) | |
461 return IDR_AUTOFILL_CC_JCB; | |
462 if (type_ == kMasterCard) | |
463 return IDR_AUTOFILL_CC_MASTERCARD; | |
464 if (type_ == kSoloCard) | |
465 return IDR_AUTOFILL_CC_SOLO; | |
466 if (type_ == kVisaCard) | |
467 return IDR_AUTOFILL_CC_VISA; | |
468 | |
469 // If you hit this DCHECK, the above list of cases needs to be updated to | |
470 // include a new card. | |
471 DCHECK_EQ(kGenericCard, type_); | |
472 return IDR_AUTOFILL_CC_GENERIC; | |
473 } | |
474 | |
475 void CreditCard::operator=(const CreditCard& credit_card) { | |
476 if (this == &credit_card) | |
477 return; | |
478 | |
479 number_ = credit_card.number_; | |
480 name_on_card_ = credit_card.name_on_card_; | |
481 type_ = credit_card.type_; | |
482 expiration_month_ = credit_card.expiration_month_; | |
483 expiration_year_ = credit_card.expiration_year_; | |
484 guid_ = credit_card.guid_; | |
485 } | |
486 | |
487 bool CreditCard::UpdateFromImportedCard(const CreditCard& imported_card, | |
488 const std::string& app_locale) { | |
489 if (this->GetInfo(CREDIT_CARD_NUMBER, app_locale) != | |
490 imported_card.GetInfo(CREDIT_CARD_NUMBER, app_locale)) { | |
491 return false; | |
492 } | |
493 | |
494 // Note that the card number is intentionally not updated, so as to preserve | |
495 // any formatting (i.e. separator characters). Since the card number is not | |
496 // updated, there is no reason to update the card type, either. | |
497 if (!imported_card.name_on_card_.empty()) | |
498 name_on_card_ = imported_card.name_on_card_; | |
499 | |
500 // The expiration date for |imported_card| should always be set. | |
501 DCHECK(imported_card.expiration_month_ && imported_card.expiration_year_); | |
502 expiration_month_ = imported_card.expiration_month_; | |
503 expiration_year_ = imported_card.expiration_year_; | |
504 | |
505 return true; | |
506 } | |
507 | |
508 void CreditCard::FillFormField(const AutofillField& field, | |
509 size_t /*variant*/, | |
510 FormFieldData* field_data) const { | |
511 DCHECK_EQ(AutofillType::CREDIT_CARD, AutofillType(field.type()).group()); | |
512 DCHECK(field_data); | |
513 | |
514 const std::string app_locale = AutofillCountry::ApplicationLocale(); | |
515 | |
516 if (field_data->form_control_type == "select-one") { | |
517 FillSelectControl(field.type(), field_data); | |
518 } else if (field_data->form_control_type == "month") { | |
519 // HTML5 input="month" consists of year-month. | |
520 string16 year = GetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, app_locale); | |
521 string16 month = GetInfo(CREDIT_CARD_EXP_MONTH, app_locale); | |
522 if (!year.empty() && !month.empty()) { | |
523 // Fill the value only if |this| includes both year and month | |
524 // information. | |
525 field_data->value = year + ASCIIToUTF16("-") + month; | |
526 } | |
527 } else { | |
528 field_data->value = GetInfo(field.type(), app_locale); | |
529 } | |
530 } | |
531 | |
532 int CreditCard::Compare(const CreditCard& credit_card) const { | |
533 // The following CreditCard field types are the only types we store in the | |
534 // WebDB so far, so we're only concerned with matching these types in the | |
535 // credit card. | |
536 const AutofillFieldType types[] = { CREDIT_CARD_NAME, | |
537 CREDIT_CARD_NUMBER, | |
538 CREDIT_CARD_EXP_MONTH, | |
539 CREDIT_CARD_EXP_4_DIGIT_YEAR }; | |
540 for (size_t index = 0; index < arraysize(types); ++index) { | |
541 int comparison = GetRawInfo(types[index]).compare( | |
542 credit_card.GetRawInfo(types[index])); | |
543 if (comparison != 0) | |
544 return comparison; | |
545 } | |
546 | |
547 return 0; | |
548 } | |
549 | |
550 bool CreditCard::operator==(const CreditCard& credit_card) const { | |
551 if (guid_ != credit_card.guid_) | |
552 return false; | |
553 | |
554 return Compare(credit_card) == 0; | |
555 } | |
556 | |
557 bool CreditCard::operator!=(const CreditCard& credit_card) const { | |
558 return !operator==(credit_card); | |
559 } | |
560 | |
561 bool CreditCard::IsEmpty() const { | |
562 FieldTypeSet types; | |
563 GetNonEmptyTypes(AutofillCountry::ApplicationLocale(), &types); | |
564 return types.empty(); | |
565 } | |
566 | |
567 bool CreditCard::IsComplete() const { | |
568 return | |
569 autofill::IsValidCreditCardNumber(number_) && | |
570 expiration_month_ != 0 && | |
571 expiration_year_ != 0; | |
572 } | |
573 | |
574 void CreditCard::GetSupportedTypes(FieldTypeSet* supported_types) const { | |
575 supported_types->insert(CREDIT_CARD_NAME); | |
576 supported_types->insert(CREDIT_CARD_NUMBER); | |
577 supported_types->insert(CREDIT_CARD_TYPE); | |
578 supported_types->insert(CREDIT_CARD_EXP_MONTH); | |
579 supported_types->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR); | |
580 supported_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR); | |
581 supported_types->insert(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR); | |
582 supported_types->insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR); | |
583 } | |
584 | |
585 string16 CreditCard::ExpirationMonthAsString() const { | |
586 if (expiration_month_ == 0) | |
587 return string16(); | |
588 | |
589 string16 month = base::IntToString16(expiration_month_); | |
590 if (expiration_month_ >= 10) | |
591 return month; | |
592 | |
593 string16 zero = ASCIIToUTF16("0"); | |
594 zero.append(month); | |
595 return zero; | |
596 } | |
597 | |
598 string16 CreditCard::Expiration4DigitYearAsString() const { | |
599 if (expiration_year_ == 0) | |
600 return string16(); | |
601 | |
602 return base::IntToString16(Expiration4DigitYear()); | |
603 } | |
604 | |
605 string16 CreditCard::Expiration2DigitYearAsString() const { | |
606 if (expiration_year_ == 0) | |
607 return string16(); | |
608 | |
609 return base::IntToString16(Expiration2DigitYear()); | |
610 } | |
611 | |
612 void CreditCard::SetExpirationMonthFromString(const string16& text, | |
613 const std::string& app_locale) { | |
614 int month; | |
615 if (!ConvertMonth(text, app_locale, &month)) | |
616 return; | |
617 | |
618 SetExpirationMonth(month); | |
619 } | |
620 | |
621 void CreditCard::SetExpirationYearFromString(const string16& text) { | |
622 int year; | |
623 if (!ConvertYear(text, &year)) | |
624 return; | |
625 | |
626 SetExpirationYear(year); | |
627 } | |
628 | |
629 void CreditCard::SetNumber(const string16& number) { | |
630 number_ = number; | |
631 type_ = GetCreditCardType(StripSeparators(number_)); | |
632 } | |
633 | |
634 void CreditCard::SetExpirationMonth(int expiration_month) { | |
635 if (expiration_month < 0 || expiration_month > 12) | |
636 return; | |
637 | |
638 expiration_month_ = expiration_month; | |
639 } | |
640 | |
641 void CreditCard::SetExpirationYear(int expiration_year) { | |
642 if (expiration_year != 0 && | |
643 (expiration_year < 2006 || expiration_year > 10000)) { | |
644 return; | |
645 } | |
646 | |
647 expiration_year_ = expiration_year; | |
648 } | |
649 | |
650 // So we can compare CreditCards with EXPECT_EQ(). | |
651 std::ostream& operator<<(std::ostream& os, const CreditCard& credit_card) { | |
652 return os | |
653 << UTF16ToUTF8(credit_card.Label()) | |
654 << " " | |
655 << credit_card.guid() | |
656 << " " | |
657 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NAME)) | |
658 << " " | |
659 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_TYPE)) | |
660 << " " | |
661 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NUMBER)) | |
662 << " " | |
663 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_MONTH)) | |
664 << " " | |
665 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR)); | |
666 } | |
667 | |
668 // These values must match the values in WebKitPlatformSupportImpl in | |
669 // webkit/glue. We send these strings to WebKit, which then asks | |
670 // WebKitPlatformSupportImpl to load the image data. | |
671 const char* const kAmericanExpressCard = "americanExpressCC"; | |
672 const char* const kDinersCard = "dinersCC"; | |
673 const char* const kDiscoverCard = "discoverCC"; | |
674 const char* const kGenericCard = "genericCC"; | |
675 const char* const kJCBCard = "jcbCC"; | |
676 const char* const kMasterCard = "masterCardCC"; | |
677 const char* const kSoloCard = "soloCC"; | |
678 const char* const kVisaCard = "visaCC"; | |
OLD | NEW |