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