1 // Copyright 2013 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.
5 #include "components/autofill/core/browser/credit_card.h"
13 #include "base/basictypes.h"
14 #include "base/guid.h"
15 #include "base/logging.h"
16 #include "base/strings/string16.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_split.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/time/time.h"
22 #include "components/autofill/core/browser/autofill_field.h"
23 #include "components/autofill/core/browser/autofill_type.h"
24 #include "components/autofill/core/browser/validation.h"
25 #include "components/autofill/core/common/autofill_l10n_util.h"
26 #include "components/autofill/core/common/autofill_regexes.h"
27 #include "components/autofill/core/common/form_field_data.h"
28 #include "grit/components_scaled_resources.h"
29 #include "grit/components_strings.h"
30 #include "third_party/icu/source/common/unicode/uloc.h"
31 #include "third_party/icu/source/i18n/unicode/dtfmtsym.h"
32 #include "ui/base/l10n/l10n_util.h"
38 const base::char16 kCreditCardObfuscationSymbol
= '*';
40 bool ConvertYear(const base::string16
& year
, int* num
) {
41 // If the |year| is empty, clear the stored value.
47 // Try parsing the |year| as a number.
48 if (base::StringToInt(year
, num
))
55 base::string16
TypeForFill(const std::string
& type
) {
56 if (type
== kAmericanExpressCard
)
57 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX
);
58 if (type
== kDinersCard
)
59 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DINERS
);
60 if (type
== kDiscoverCard
)
61 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DISCOVER
);
63 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_JCB
);
64 if (type
== kMasterCard
)
65 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD
);
66 if (type
== kUnionPay
)
67 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_UNION_PAY
);
68 if (type
== kVisaCard
)
69 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA
);
71 // If you hit this DCHECK, the above list of cases needs to be updated to
72 // include a new card.
73 DCHECK_EQ(kGenericCard
, type
);
74 return base::string16();
79 CreditCard::CreditCard(const std::string
& guid
, const std::string
& origin
)
80 : AutofillDataModel(guid
, origin
),
81 record_type_(LOCAL_CARD
),
88 CreditCard::CreditCard(const base::string16
& card_number
,
91 : AutofillDataModel(std::string(), std::string()),
92 record_type_(LOCAL_CARD
),
94 SetNumber(card_number
);
95 SetExpirationMonth(expiration_month
);
96 SetExpirationYear(expiration_year
);
99 CreditCard::CreditCard(RecordType type
, const std::string
& server_id
)
100 : AutofillDataModel(base::GenerateGUID(), std::string()),
103 expiration_month_(0),
105 server_id_(server_id
),
107 DCHECK(type
== MASKED_SERVER_CARD
|| type
== FULL_SERVER_CARD
);
110 CreditCard::CreditCard()
111 : AutofillDataModel(base::GenerateGUID(), std::string()),
112 record_type_(LOCAL_CARD
),
114 expiration_month_(0),
119 CreditCard::CreditCard(const CreditCard
& credit_card
)
120 : AutofillDataModel(std::string(), std::string()) {
121 operator=(credit_card
);
124 CreditCard::~CreditCard() {}
127 const base::string16
CreditCard::StripSeparators(const base::string16
& number
) {
128 base::string16 stripped
;
129 base::RemoveChars(number
, base::ASCIIToUTF16("- "), &stripped
);
134 base::string16
CreditCard::TypeForDisplay(const std::string
& type
) {
135 if (kGenericCard
== type
)
136 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_GENERIC
);
137 if (kAmericanExpressCard
== type
)
138 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX_SHORT
);
140 return ::autofill::TypeForFill(type
);
143 // This method is not compiled on iOS because the resources are not used and
144 // should not be shipped.
147 int CreditCard::IconResourceId(const std::string
& type
) {
148 if (type
== kAmericanExpressCard
)
149 return IDR_AUTOFILL_CC_AMEX
;
150 if (type
== kDinersCard
)
151 return IDR_AUTOFILL_CC_GENERIC
;
152 if (type
== kDiscoverCard
)
153 return IDR_AUTOFILL_CC_DISCOVER
;
154 if (type
== kJCBCard
)
155 return IDR_AUTOFILL_CC_GENERIC
;
156 if (type
== kMasterCard
)
157 return IDR_AUTOFILL_CC_MASTERCARD
;
158 if (type
== kUnionPay
)
159 return IDR_AUTOFILL_CC_GENERIC
;
160 if (type
== kVisaCard
)
161 return IDR_AUTOFILL_CC_VISA
;
163 // If you hit this DCHECK, the above list of cases needs to be updated to
164 // include a new card.
165 DCHECK_EQ(kGenericCard
, type
);
166 return IDR_AUTOFILL_CC_GENERIC
;
168 #endif // #if !defined(OS_IOS)
171 const char* CreditCard::GetCreditCardType(const base::string16
& number
) {
172 // Credit card number specifications taken from:
173 // http://en.wikipedia.org/wiki/Credit_card_numbers,
174 // http://en.wikipedia.org/wiki/List_of_Issuer_Identification_Numbers,
175 // http://www.discovernetwork.com/merchants/images/Merchant_Marketing_PDF.pdf,
176 // http://www.regular-expressions.info/creditcard.html,
177 // http://developer.ean.com/general_info/Valid_Credit_Card_Types,
178 // http://www.bincodes.com/,
179 // http://www.fraudpractice.com/FL-binCC.html, and
180 // http://www.beachnet.com/~hstiles/cardtype.html
182 // The last site is currently unavailable, but a cached version remains at
183 // http://web.archive.org/web/20120923111349/http://www.beachnet.com/~hstiles/cardtype.html
185 // Card Type Prefix(es) Length
186 // ---------------------------------------------------------------
188 // American Express 34,37 15
189 // Diners Club 300-305,3095,36,38-39 14
190 // Discover Card 6011,644-649,65 16
192 // MasterCard 51-55 16
195 // Check for prefixes of length 1.
199 if (number
[0] == '4')
202 // Check for prefixes of length 2.
203 if (number
.size() < 2)
206 int first_two_digits
= 0;
207 if (!base::StringToInt(number
.substr(0, 2), &first_two_digits
))
210 if (first_two_digits
== 34 || first_two_digits
== 37)
211 return kAmericanExpressCard
;
213 if (first_two_digits
== 36 ||
214 first_two_digits
== 38 ||
215 first_two_digits
== 39)
218 if (first_two_digits
>= 51 && first_two_digits
<= 55)
221 if (first_two_digits
== 62)
224 if (first_two_digits
== 65)
225 return kDiscoverCard
;
227 // Check for prefixes of length 3.
228 if (number
.size() < 3)
231 int first_three_digits
= 0;
232 if (!base::StringToInt(number
.substr(0, 3), &first_three_digits
))
235 if (first_three_digits
>= 300 && first_three_digits
<= 305)
238 if (first_three_digits
>= 644 && first_three_digits
<= 649)
239 return kDiscoverCard
;
241 // Check for prefixes of length 4.
242 if (number
.size() < 4)
245 int first_four_digits
= 0;
246 if (!base::StringToInt(number
.substr(0, 4), &first_four_digits
))
249 if (first_four_digits
== 3095)
252 if (first_four_digits
>= 3528 && first_four_digits
<= 3589)
255 if (first_four_digits
== 6011)
256 return kDiscoverCard
;
261 void CreditCard::SetTypeForMaskedCard(const char* type
) {
262 DCHECK_EQ(MASKED_SERVER_CARD
, record_type());
266 void CreditCard::SetServerStatus(ServerStatus status
) {
267 DCHECK_NE(LOCAL_CARD
, record_type());
268 server_status_
= status
;
271 CreditCard::ServerStatus
CreditCard::GetServerStatus() const {
272 DCHECK_NE(LOCAL_CARD
, record_type());
273 return server_status_
;
276 base::string16
CreditCard::GetRawInfo(ServerFieldType type
) const {
277 DCHECK_EQ(CREDIT_CARD
, AutofillType(type
).group());
279 case CREDIT_CARD_NAME
:
280 return name_on_card_
;
282 case CREDIT_CARD_EXP_MONTH
:
283 return ExpirationMonthAsString();
285 case CREDIT_CARD_EXP_2_DIGIT_YEAR
:
286 return Expiration2DigitYearAsString();
288 case CREDIT_CARD_EXP_4_DIGIT_YEAR
:
289 return Expiration4DigitYearAsString();
291 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR
: {
292 base::string16 month
= ExpirationMonthAsString();
293 base::string16 year
= Expiration2DigitYearAsString();
294 if (!month
.empty() && !year
.empty())
295 return month
+ base::ASCIIToUTF16("/") + year
;
296 return base::string16();
299 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR
: {
300 base::string16 month
= ExpirationMonthAsString();
301 base::string16 year
= Expiration4DigitYearAsString();
302 if (!month
.empty() && !year
.empty())
303 return month
+ base::ASCIIToUTF16("/") + year
;
304 return base::string16();
307 case CREDIT_CARD_TYPE
:
308 return TypeForFill();
310 case CREDIT_CARD_NUMBER
:
313 case CREDIT_CARD_VERIFICATION_CODE
:
314 // Chrome doesn't store credit card verification codes.
315 return base::string16();
318 // ComputeDataPresentForArray will hit this repeatedly.
319 return base::string16();
323 void CreditCard::SetRawInfo(ServerFieldType type
,
324 const base::string16
& value
) {
325 DCHECK_EQ(CREDIT_CARD
, AutofillType(type
).group());
327 case CREDIT_CARD_NAME
:
328 name_on_card_
= value
;
331 case CREDIT_CARD_EXP_MONTH
:
332 SetExpirationMonthFromString(value
, std::string());
335 case CREDIT_CARD_EXP_2_DIGIT_YEAR
:
336 // This is a read-only attribute.
339 case CREDIT_CARD_EXP_4_DIGIT_YEAR
:
340 SetExpirationYearFromString(value
);
343 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR
:
344 // This is a read-only attribute.
347 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR
:
348 // This is a read-only attribute.
351 case CREDIT_CARD_TYPE
:
352 // This is a read-only attribute, determined by the credit card number.
355 case CREDIT_CARD_NUMBER
: {
356 // Don't change the real value if the input is an obfuscated string.
357 if (value
.size() > 0 && value
[0] != kCreditCardObfuscationSymbol
)
362 case CREDIT_CARD_VERIFICATION_CODE
:
363 // Chrome doesn't store the credit card verification code.
367 NOTREACHED() << "Attempting to set unknown info-type " << type
;
372 base::string16
CreditCard::GetInfo(const AutofillType
& type
,
373 const std::string
& app_locale
) const {
374 ServerFieldType storable_type
= type
.GetStorableType();
375 if (storable_type
== CREDIT_CARD_NUMBER
) {
376 // Web pages should never actually be filled by a masked server card,
377 // but this function is used at the preview stage.
378 if (record_type() == MASKED_SERVER_CARD
)
379 return TypeAndLastFourDigits();
381 return StripSeparators(number_
);
384 return GetRawInfo(storable_type
);
387 bool CreditCard::SetInfo(const AutofillType
& type
,
388 const base::string16
& value
,
389 const std::string
& app_locale
) {
390 ServerFieldType storable_type
= type
.GetStorableType();
391 if (storable_type
== CREDIT_CARD_NUMBER
)
392 SetRawInfo(storable_type
, StripSeparators(value
));
393 else if (storable_type
== CREDIT_CARD_EXP_MONTH
)
394 SetExpirationMonthFromString(value
, app_locale
);
396 SetRawInfo(storable_type
, value
);
401 void CreditCard::GetMatchingTypes(const base::string16
& text
,
402 const std::string
& app_locale
,
403 ServerFieldTypeSet
* matching_types
) const {
404 FormGroup::GetMatchingTypes(text
, app_locale
, matching_types
);
406 base::string16 card_number
=
407 GetInfo(AutofillType(CREDIT_CARD_NUMBER
), app_locale
);
408 if (!card_number
.empty() && StripSeparators(text
) == card_number
)
409 matching_types
->insert(CREDIT_CARD_NUMBER
);
412 if (ConvertMonth(text
, app_locale
, &month
) &&
413 month
== expiration_month_
) {
414 matching_types
->insert(CREDIT_CARD_EXP_MONTH
);
418 const base::string16
CreditCard::Label() const {
419 std::pair
<base::string16
, base::string16
> pieces
= LabelPieces();
420 return pieces
.first
+ pieces
.second
;
423 const std::pair
<base::string16
, base::string16
> CreditCard::LabelPieces()
425 base::string16 label
;
426 // No CC number, return name only.
427 if (number().empty())
428 return std::make_pair(name_on_card_
, base::string16());
430 base::string16 obfuscated_cc_number
= TypeAndLastFourDigits();
431 // No expiration date set.
432 if (!expiration_month_
|| !expiration_year_
)
433 return std::make_pair(obfuscated_cc_number
, base::string16());
435 base::string16
formatted_date(ExpirationMonthAsString());
436 formatted_date
.append(base::ASCIIToUTF16("/"));
437 formatted_date
.append(Expiration4DigitYearAsString());
439 base::string16 separator
=
440 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR
);
441 return std::make_pair(obfuscated_cc_number
, separator
+ formatted_date
);
444 void CreditCard::SetInfoForMonthInputType(const base::string16
& value
) {
445 // Check if |text| is "yyyy-mm" format first, and check normal month format.
446 if (!autofill::MatchesPattern(value
,
447 base::UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$"))) {
451 std::vector
<base::StringPiece16
> year_month
= base::SplitStringPiece(
452 value
, base::ASCIIToUTF16("-"),
453 base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
);
454 DCHECK_EQ(2u, year_month
.size());
456 bool converted
= false;
457 converted
= base::StringToInt(year_month
[0], &num
);
459 SetExpirationYear(num
);
460 converted
= base::StringToInt(year_month
[1], &num
);
462 SetExpirationMonth(num
);
465 void CreditCard::SetExpirationMonth(int expiration_month
) {
466 if (expiration_month
< 0 || expiration_month
> 12)
468 expiration_month_
= expiration_month
;
471 void CreditCard::SetExpirationYear(int expiration_year
) {
472 if (expiration_year
!= 0 &&
473 (expiration_year
< 2006 || expiration_year
> 10000))
475 expiration_year_
= expiration_year
;
478 base::string16
CreditCard::LastFourDigits() const {
479 static const size_t kNumLastDigits
= 4;
481 base::string16 number
= StripSeparators(number_
);
482 if (number
.size() <= kNumLastDigits
)
485 return number
.substr(number
.size() - kNumLastDigits
, kNumLastDigits
);
488 base::string16
CreditCard::TypeForDisplay() const {
489 return CreditCard::TypeForDisplay(type_
);
492 base::string16
CreditCard::TypeAndLastFourDigits() const {
493 base::string16 type
= TypeForDisplay();
495 base::string16 digits
= LastFourDigits();
499 // The separator character is a non breaking space and a horizontal midline
501 // TODO(estade): i18n?
502 return type
+ base::UTF8ToUTF16("\xC2\xA0\xE2\x8B\xAF") + digits
;
505 void CreditCard::operator=(const CreditCard
& credit_card
) {
506 set_use_count(credit_card
.use_count());
507 set_use_date(credit_card
.use_date());
508 set_modification_date(credit_card
.modification_date());
510 if (this == &credit_card
)
513 record_type_
= credit_card
.record_type_
;
514 number_
= credit_card
.number_
;
515 name_on_card_
= credit_card
.name_on_card_
;
516 type_
= credit_card
.type_
;
517 expiration_month_
= credit_card
.expiration_month_
;
518 expiration_year_
= credit_card
.expiration_year_
;
519 server_id_
= credit_card
.server_id_
;
520 server_status_
= credit_card
.server_status_
;
522 set_guid(credit_card
.guid());
523 set_origin(credit_card
.origin());
526 bool CreditCard::UpdateFromImportedCard(const CreditCard
& imported_card
,
527 const std::string
& app_locale
) {
528 if (this->GetInfo(AutofillType(CREDIT_CARD_NUMBER
), app_locale
) !=
529 imported_card
.GetInfo(AutofillType(CREDIT_CARD_NUMBER
), app_locale
)) {
533 // Heuristically aggregated data should never overwrite verified data.
534 // Instead, discard any heuristically aggregated credit cards that disagree
535 // with explicitly entered data, so that the UI is not cluttered with
537 if (this->IsVerified() && !imported_card
.IsVerified())
540 set_origin(imported_card
.origin());
542 // Note that the card number is intentionally not updated, so as to preserve
543 // any formatting (i.e. separator characters). Since the card number is not
544 // updated, there is no reason to update the card type, either.
545 if (!imported_card
.name_on_card_
.empty())
546 name_on_card_
= imported_card
.name_on_card_
;
548 // The expiration date for |imported_card| should always be set.
549 DCHECK(imported_card
.expiration_month_
&& imported_card
.expiration_year_
);
550 expiration_month_
= imported_card
.expiration_month_
;
551 expiration_year_
= imported_card
.expiration_year_
;
556 int CreditCard::Compare(const CreditCard
& credit_card
) const {
557 // The following CreditCard field types are the only types we store in the
558 // WebDB so far, so we're only concerned with matching these types in the
560 const ServerFieldType types
[] = { CREDIT_CARD_NAME
,
562 CREDIT_CARD_EXP_MONTH
,
563 CREDIT_CARD_EXP_4_DIGIT_YEAR
};
564 for (size_t i
= 0; i
< arraysize(types
); ++i
) {
566 GetRawInfo(types
[i
]).compare(credit_card
.GetRawInfo(types
[i
]));
571 int comparison
= server_id_
.compare(credit_card
.server_id_
);
575 if (static_cast<int>(server_status_
) <
576 static_cast<int>(credit_card
.server_status_
))
578 if (static_cast<int>(server_status_
) >
579 static_cast<int>(credit_card
.server_status_
))
581 if (static_cast<int>(record_type_
) <
582 static_cast<int>(credit_card
.record_type_
))
584 if (static_cast<int>(record_type_
) >
585 static_cast<int>(credit_card
.record_type_
))
590 bool CreditCard::IsLocalDuplicateOfServerCard(const CreditCard
& other
) const {
591 if (record_type() != LOCAL_CARD
|| other
.record_type() == LOCAL_CARD
)
594 // If |this| is only a partial card, i.e. some fields are missing, assume
595 // those fields match.
596 if ((!name_on_card_
.empty() && name_on_card_
!= other
.name_on_card_
) ||
597 (expiration_month_
!= 0 &&
598 expiration_month_
!= other
.expiration_month_
) ||
599 (expiration_year_
!= 0 && expiration_year_
!= other
.expiration_year_
)) {
606 if (other
.record_type() == FULL_SERVER_CARD
)
607 return StripSeparators(number_
) == StripSeparators(other
.number_
);
609 // For masked cards, this is the best we can do to compare card numbers.
610 return TypeAndLastFourDigits() == other
.TypeAndLastFourDigits();
613 bool CreditCard::operator==(const CreditCard
& credit_card
) const {
614 return guid() == credit_card
.guid() &&
615 origin() == credit_card
.origin() &&
616 Compare(credit_card
) == 0;
619 bool CreditCard::operator!=(const CreditCard
& credit_card
) const {
620 return !operator==(credit_card
);
623 bool CreditCard::IsEmpty(const std::string
& app_locale
) const {
624 ServerFieldTypeSet types
;
625 GetNonEmptyTypes(app_locale
, &types
);
626 return types
.empty();
629 bool CreditCard::IsComplete() const {
631 autofill::IsValidCreditCardNumber(number_
) &&
632 expiration_month_
!= 0 &&
633 expiration_year_
!= 0;
636 bool CreditCard::IsValid() const {
637 return autofill::IsValidCreditCardNumber(number_
) &&
638 autofill::IsValidCreditCardExpirationDate(
639 expiration_year_
, expiration_month_
, base::Time::Now());
642 void CreditCard::GetSupportedTypes(ServerFieldTypeSet
* supported_types
) const {
643 supported_types
->insert(CREDIT_CARD_NAME
);
644 supported_types
->insert(CREDIT_CARD_NUMBER
);
645 supported_types
->insert(CREDIT_CARD_TYPE
);
646 supported_types
->insert(CREDIT_CARD_EXP_MONTH
);
647 supported_types
->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR
);
648 supported_types
->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR
);
649 supported_types
->insert(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR
);
650 supported_types
->insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR
);
653 base::string16
CreditCard::ExpirationMonthAsString() const {
654 if (expiration_month_
== 0)
655 return base::string16();
657 base::string16 month
= base::IntToString16(expiration_month_
);
658 if (expiration_month_
>= 10)
661 base::string16 zero
= base::ASCIIToUTF16("0");
666 base::string16
CreditCard::TypeForFill() const {
667 return ::autofill::TypeForFill(type_
);
670 base::string16
CreditCard::Expiration4DigitYearAsString() const {
671 if (expiration_year_
== 0)
672 return base::string16();
674 return base::IntToString16(Expiration4DigitYear());
677 base::string16
CreditCard::Expiration2DigitYearAsString() const {
678 if (expiration_year_
== 0)
679 return base::string16();
681 return base::IntToString16(Expiration2DigitYear());
684 void CreditCard::SetExpirationMonthFromString(const base::string16
& text
,
685 const std::string
& app_locale
) {
687 if (!text
.empty() && !ConvertMonth(text
, app_locale
, &month
))
690 SetExpirationMonth(month
);
693 void CreditCard::SetExpirationYearFromString(const base::string16
& text
) {
695 if (!ConvertYear(text
, &year
))
698 SetExpirationYear(year
);
701 void CreditCard::SetNumber(const base::string16
& number
) {
704 // Set the type based on the card number, but only for full numbers, not
705 // when we have masked cards from the server (last 4 digits).
706 if (record_type_
!= MASKED_SERVER_CARD
)
707 type_
= GetCreditCardType(StripSeparators(number_
));
711 bool CreditCard::ConvertMonth(const base::string16
& month
,
712 const std::string
& app_locale
,
717 // Try parsing the |month| as a number (this doesn't require |app_locale|).
718 if (base::StringToInt(month
, num
))
721 if (app_locale
.empty())
724 // Otherwise, try parsing the |month| as a named month, e.g. "January" or
726 l10n::CaseInsensitiveCompare compare
;
727 UErrorCode status
= U_ZERO_ERROR
;
728 icu::Locale
locale(app_locale
.c_str());
729 icu::DateFormatSymbols
date_format_symbols(locale
, status
);
730 DCHECK(status
== U_ZERO_ERROR
|| status
== U_USING_FALLBACK_WARNING
||
731 status
== U_USING_DEFAULT_WARNING
);
734 const icu::UnicodeString
* months
= date_format_symbols
.getMonths(num_months
);
735 for (int32_t i
= 0; i
< num_months
; ++i
) {
736 const base::string16
icu_month(months
[i
].getBuffer(), months
[i
].length());
737 if (compare
.StringsEqual(icu_month
, month
)) {
738 *num
= i
+ 1; // Adjust from 0-indexed to 1-indexed.
743 months
= date_format_symbols
.getShortMonths(num_months
);
744 // Some abbreviations have . at the end (e.g., "janv." in French). We don't
745 // care about matching that.
746 base::string16 trimmed_month
;
747 base::TrimString(month
, base::ASCIIToUTF16("."), &trimmed_month
);
748 for (int32_t i
= 0; i
< num_months
; ++i
) {
749 base::string16
icu_month(months
[i
].getBuffer(), months
[i
].length());
750 base::TrimString(icu_month
, base::ASCIIToUTF16("."), &icu_month
);
751 if (compare
.StringsEqual(icu_month
, trimmed_month
)) {
752 *num
= i
+ 1; // Adjust from 0-indexed to 1-indexed.
760 // So we can compare CreditCards with EXPECT_EQ().
761 std::ostream
& operator<<(std::ostream
& os
, const CreditCard
& credit_card
) {
763 << base::UTF16ToUTF8(credit_card
.Label())
765 << credit_card
.guid()
767 << credit_card
.origin()
769 << base::UTF16ToUTF8(credit_card
.GetRawInfo(CREDIT_CARD_NAME
))
771 << base::UTF16ToUTF8(credit_card
.GetRawInfo(CREDIT_CARD_TYPE
))
773 << base::UTF16ToUTF8(credit_card
.GetRawInfo(CREDIT_CARD_NUMBER
))
775 << base::UTF16ToUTF8(credit_card
.GetRawInfo(CREDIT_CARD_EXP_MONTH
))
777 << base::UTF16ToUTF8(
778 credit_card
.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR
));
781 // These values must match the values in WebKitPlatformSupportImpl in
782 // webkit/glue. We send these strings to WebKit, which then asks
783 // WebKitPlatformSupportImpl to load the image data.
784 const char* const kAmericanExpressCard
= "americanExpressCC";
785 const char* const kDinersCard
= "dinersCC";
786 const char* const kDiscoverCard
= "discoverCC";
787 const char* const kGenericCard
= "genericCC";
788 const char* const kJCBCard
= "jcbCC";
789 const char* const kMasterCard
= "masterCardCC";
790 const char* const kUnionPay
= "unionPayCC";
791 const char* const kVisaCard
= "visaCC";
793 } // namespace autofill