summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorisherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-05 04:01:21 +0000
committerisherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-05 04:01:21 +0000
commit2a958550ec25aeb2da7fa893015133f2aae32f41 (patch)
treedafc82496cf0b1f14d39183b5e9860a8ca255e70
parentbed98da0c1e62387a477903910781f1b54916039 (diff)
downloadchromium_src-2a958550ec25aeb2da7fa893015133f2aae32f41.zip
chromium_src-2a958550ec25aeb2da7fa893015133f2aae32f41.tar.gz
chromium_src-2a958550ec25aeb2da7fa893015133f2aae32f41.tar.bz2
Refactor Autofill parsing code. Most notably, add a helper class for parsing with lookahead.
* Adds an AutofillScanner class to help with lookahead parsing. * Remove the NULL-termination from FormStructure's fields vector * Remove some redundant DCHECKs * Refactor PersonalDataManager::ImportFormData() to take a single form, not a vector of forms. * Move EmailField class to its own file * Remove some obsolete billing/shipping address distinguishing code * Refactor the code to remove the really wonky FormFieldSet() class * Refactor some interfaces to take |size_t| rather than |int| * Remove some unused fields from FormStructure * Const-correctness BUG=none TEST=none Review URL: http://codereview.chromium.org/6910018 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@84211 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/autofill/address_field.cc165
-rw-r--r--chrome/browser/autofill/address_field.h58
-rw-r--r--chrome/browser/autofill/address_field_unittest.cc108
-rw-r--r--chrome/browser/autofill/autofill_manager.cc14
-rw-r--r--chrome/browser/autofill/autofill_merge_unittest.cc3
-rw-r--r--chrome/browser/autofill/autofill_scanner.cc41
-rw-r--r--chrome/browser/autofill/autofill_scanner.h50
-rw-r--r--chrome/browser/autofill/credit_card_field.cc92
-rw-r--r--chrome/browser/autofill/credit_card_field.h24
-rw-r--r--chrome/browser/autofill/credit_card_field_unittest.cc51
-rw-r--r--chrome/browser/autofill/email_field.cc31
-rw-r--r--chrome/browser/autofill/email_field.h28
-rw-r--r--chrome/browser/autofill/form_field.cc345
-rw-r--r--chrome/browser/autofill/form_field.h76
-rw-r--r--chrome/browser/autofill/form_structure.cc70
-rw-r--r--chrome/browser/autofill/form_structure.h22
-rw-r--r--chrome/browser/autofill/form_structure_browsertest.cc3
-rw-r--r--chrome/browser/autofill/name_field.cc128
-rw-r--r--chrome/browser/autofill/name_field.h35
-rw-r--r--chrome/browser/autofill/name_field_unittest.cc66
-rw-r--r--chrome/browser/autofill/personal_data_manager.cc171
-rw-r--r--chrome/browser/autofill/personal_data_manager.h13
-rw-r--r--chrome/browser/autofill/personal_data_manager_unittest.cc135
-rw-r--r--chrome/browser/autofill/phone_field.cc100
-rw-r--r--chrome/browser/autofill/phone_field.h14
-rw-r--r--chrome/browser/autofill/phone_field_unittest.cc61
-rw-r--r--chrome/chrome_browser.gypi4
27 files changed, 897 insertions, 1011 deletions
diff --git a/chrome/browser/autofill/address_field.cc b/chrome/browser/autofill/address_field.cc
index 1cf05c7..4624fa5 100644
--- a/chrome/browser/autofill/address_field.cc
+++ b/chrome/browser/autofill/address_field.cc
@@ -12,6 +12,7 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
+#include "chrome/browser/autofill/autofill_scanner.h"
#include "grit/autofill_resources.h"
#include "ui/base/l10n/l10n_util.h"
@@ -52,44 +53,23 @@ bool AddressField::GetFieldInfo(FieldTypeMap* field_type_map) const {
return false;
}
- bool ok;
- ok = Add(field_type_map, company_, AutofillType(address_company));
- DCHECK(ok);
- ok = ok && Add(field_type_map, address1_, AutofillType(address_line1));
- DCHECK(ok);
- ok = ok && Add(field_type_map, address2_, AutofillType(address_line2));
- DCHECK(ok);
- ok = ok && Add(field_type_map, city_, AutofillType(address_city));
- DCHECK(ok);
- ok = ok && Add(field_type_map, state_, AutofillType(address_state));
- DCHECK(ok);
- ok = ok && Add(field_type_map, zip_, AutofillType(address_zip));
- DCHECK(ok);
- ok = ok && Add(field_type_map, country_, AutofillType(address_country));
- DCHECK(ok);
-
+ bool ok = Add(field_type_map, company_, address_company);
+ ok = ok && Add(field_type_map, address1_, address_line1);
+ ok = ok && Add(field_type_map, address2_, address_line2);
+ ok = ok && Add(field_type_map, city_, address_city);
+ ok = ok && Add(field_type_map, state_, address_state);
+ ok = ok && Add(field_type_map, zip_, address_zip);
+ ok = ok && Add(field_type_map, country_, address_country);
return ok;
}
-FormFieldType AddressField::GetFormFieldType() const {
- return kAddressType;
-}
-
-AddressField* AddressField::Parse(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml) {
- DCHECK(iter);
- if (!iter)
+AddressField* AddressField::Parse(AutofillScanner* scanner, bool is_ecml) {
+ if (scanner->IsEnd())
return NULL;
scoped_ptr<AddressField> address_field(new AddressField);
- std::vector<AutofillField*>::const_iterator q = *iter;
- string16 pattern;
-
- // The ECML standard uses 2 letter country codes. So we will
- // have to remember that this is an ECML form, for when we fill
- // it out.
- address_field->is_ecml_ = is_ecml;
+ const AutofillField* initial_field = scanner->Cursor();
+ scanner->SaveCursor();
string16 attention_ignored =
l10n_util::GetStringUTF16(IDS_AUTOFILL_ATTENTION_IGNORED_RE);
@@ -97,21 +77,21 @@ AddressField* AddressField::Parse(
l10n_util::GetStringUTF16(IDS_AUTOFILL_REGION_IGNORED_RE);
// Allow address fields to appear in any order.
- while (true) {
- if (ParseCompany(&q, is_ecml, address_field.get()) ||
- ParseAddressLines(&q, is_ecml, address_field.get()) ||
- ParseCity(&q, is_ecml, address_field.get()) ||
- ParseState(&q, is_ecml, address_field.get()) ||
- ParseZipCode(&q, is_ecml, address_field.get()) ||
- ParseCountry(&q, is_ecml, address_field.get())) {
+ while (!scanner->IsEnd()) {
+ if (ParseCompany(scanner, is_ecml, address_field.get()) ||
+ ParseAddressLines(scanner, is_ecml, address_field.get()) ||
+ ParseCity(scanner, is_ecml, address_field.get()) ||
+ ParseState(scanner, is_ecml, address_field.get()) ||
+ ParseZipCode(scanner, is_ecml, address_field.get()) ||
+ ParseCountry(scanner, is_ecml, address_field.get())) {
continue;
- } else if (ParseText(&q, attention_ignored) ||
- ParseText(&q, region_ignored)) {
+ } else if (ParseText(scanner, attention_ignored) ||
+ ParseText(scanner, region_ignored)) {
// We ignore the following:
// * Attention.
// * Province/Region/Other.
continue;
- } else if (*q != **iter && ParseEmpty(&q)) {
+ } else if (scanner->Cursor() != initial_field && ParseEmpty(scanner)) {
// Ignore non-labeled fields within an address; the page
// MapQuest Driving Directions North America.html contains such a field.
// We only ignore such fields after we've parsed at least one other field;
@@ -133,10 +113,11 @@ AddressField* AddressField::Parse(
address_field->city_ != NULL || address_field->state_ != NULL ||
address_field->zip_ != NULL || address_field->zip4_ ||
address_field->country_ != NULL) {
- *iter = q;
+ address_field->type_ = address_field->FindType();
return address_field.release();
}
+ scanner->Rewind();
return NULL;
}
@@ -167,34 +148,31 @@ AddressField::AddressField()
zip_(NULL),
zip4_(NULL),
country_(NULL),
- type_(kGenericAddress),
- is_ecml_(false) {
+ type_(kGenericAddress) {
}
// static
-bool AddressField::ParseCompany(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field) {
+bool AddressField::ParseCompany(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field) {
if (address_field->company_ && !address_field->company_->IsEmpty())
return false;
string16 pattern;
- if (is_ecml)
+ if (is_ecml) {
pattern = GetEcmlPattern(kEcmlShipToCompanyName,
kEcmlBillToCompanyName, '|');
- else
+ } else {
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_COMPANY_RE);
+ }
- if (!ParseText(iter, pattern, &address_field->company_))
- return false;
-
- return true;
+ return ParseText(scanner, pattern, &address_field->company_);
}
// static
-bool AddressField::ParseAddressLines(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field) {
+bool AddressField::ParseAddressLines(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field) {
// We only match the string "address" in page text, not in element names,
// because sometimes every element in a group of address fields will have
// a name containing the string "address"; for example, on the page
@@ -209,16 +187,16 @@ bool AddressField::ParseAddressLines(
string16 pattern;
if (is_ecml) {
pattern = GetEcmlPattern(kEcmlShipToAddress1, kEcmlBillToAddress1, '|');
- if (!ParseText(iter, pattern, &address_field->address1_))
+ if (!ParseText(scanner, pattern, &address_field->address1_))
return false;
} else {
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_1_RE);
string16 label_pattern =
l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_1_LABEL_RE);
- if (!ParseText(iter, pattern, &address_field->address1_))
- if (!ParseLabelText(iter, label_pattern, &address_field->address1_))
- return false;
+ if (!ParseText(scanner, pattern, &address_field->address1_) &&
+ !ParseLabelText(scanner, label_pattern, &address_field->address1_))
+ return false;
}
// Optionally parse more address lines, which may have empty labels.
@@ -226,26 +204,26 @@ bool AddressField::ParseAddressLines(
// Some pages even have 4 address lines (e.g. uk/ShoesDirect2.html)!
if (is_ecml) {
pattern = GetEcmlPattern(kEcmlShipToAddress2, kEcmlBillToAddress2, '|');
- if (!ParseEmptyText(iter, &address_field->address2_))
- ParseText(iter, pattern, &address_field->address2_);
+ if (!ParseEmptyText(scanner, &address_field->address2_))
+ ParseText(scanner, pattern, &address_field->address2_);
} else {
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_2_RE);
string16 label_pattern =
l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_1_LABEL_RE);
- if (!ParseEmptyText(iter, &address_field->address2_))
- if (!ParseText(iter, pattern, &address_field->address2_))
- ParseLabelText(iter, label_pattern, &address_field->address2_);
+ if (!ParseEmptyText(scanner, &address_field->address2_) &&
+ !ParseText(scanner, pattern, &address_field->address2_))
+ ParseLabelText(scanner, label_pattern, &address_field->address2_);
}
// Try for a third line, which we will promptly discard.
if (address_field->address2_ != NULL) {
if (is_ecml) {
pattern = GetEcmlPattern(kEcmlShipToAddress3, kEcmlBillToAddress3, '|');
- ParseText(iter, pattern);
+ ParseText(scanner, pattern);
} else {
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_3_RE);
- if (!ParseEmptyText(iter, NULL))
- ParseText(iter, pattern, NULL);
+ if (!ParseEmptyText(scanner, NULL))
+ ParseText(scanner, pattern, NULL);
}
}
@@ -253,9 +231,9 @@ bool AddressField::ParseAddressLines(
}
// static
-bool AddressField::ParseCountry(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field) {
+bool AddressField::ParseCountry(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field) {
// Parse a country. The occasional page (e.g.
// Travelocity_New Member Information1.html) calls this a "location".
// Note: ECML standard uses 2 letter country code (ISO 3166)
@@ -268,16 +246,13 @@ bool AddressField::ParseCountry(
else
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_COUNTRY_RE);
- if (!ParseText(iter, pattern, &address_field->country_))
- return false;
-
- return true;
+ return ParseText(scanner, pattern, &address_field->country_);
}
// static
-bool AddressField::ParseZipCode(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field) {
+bool AddressField::ParseZipCode(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field) {
// Parse a zip code. On some UK pages (e.g. The China Shop2.html) this
// is called a "post code".
//
@@ -288,10 +263,6 @@ bool AddressField::ParseZipCode(
if (address_field->zip_)
return false;
- // We may be out of fields.
- if (!**iter)
- return false;
-
string16 pattern;
if (is_ecml) {
pattern = GetEcmlPattern(kEcmlShipToPostalCode, kEcmlBillToPostalCode, '|');
@@ -300,7 +271,7 @@ bool AddressField::ParseZipCode(
}
AddressType tempType;
- string16 name = (**iter)->name;
+ string16 name = scanner->Cursor()->name;
// Note: comparisons using the ecml compliant name as a prefix must be used in
// order to accommodate Google Checkout. See FormFieldSet::GetEcmlPattern for
@@ -314,14 +285,14 @@ bool AddressField::ParseZipCode(
tempType = kGenericAddress;
}
- if (!ParseText(iter, pattern, &address_field->zip_))
+ if (!ParseText(scanner, pattern, &address_field->zip_))
return false;
address_field->type_ = tempType;
if (!is_ecml) {
// Look for a zip+4, whose field name will also often contain
// the substring "zip".
- ParseText(iter,
+ ParseText(scanner,
l10n_util::GetStringUTF16(IDS_AUTOFILL_ZIP_4_RE),
&address_field->zip4_);
}
@@ -330,9 +301,9 @@ bool AddressField::ParseZipCode(
}
// static
-bool AddressField::ParseCity(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field) {
+bool AddressField::ParseCity(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field) {
// Parse a city name. Some UK pages (e.g. The China Shop2.html) use
// the term "town".
if (address_field->city_)
@@ -344,16 +315,13 @@ bool AddressField::ParseCity(
else
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CITY_RE);
- if (!ParseText(iter, pattern, &address_field->city_))
- return false;
-
- return true;
+ return ParseText(scanner, pattern, &address_field->city_);
}
// static
-bool AddressField::ParseState(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field) {
+bool AddressField::ParseState(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field) {
if (address_field->state_)
return false;
@@ -363,10 +331,7 @@ bool AddressField::ParseState(
else
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_STATE_RE);
- if (!ParseText(iter, pattern, &address_field->state_))
- return false;
-
- return true;
+ return ParseText(scanner, pattern, &address_field->state_);
}
AddressType AddressField::AddressTypeFromText(const string16 &text) {
diff --git a/chrome/browser/autofill/address_field.h b/chrome/browser/autofill/address_field.h
index 2d546e9..f2cc08a 100644
--- a/chrome/browser/autofill/address_field.h
+++ b/chrome/browser/autofill/address_field.h
@@ -9,26 +9,24 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/compiler_specific.h"
#include "base/string16.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/field_types.h"
#include "chrome/browser/autofill/form_field.h"
class AutofillField;
+class AutofillScanner;
class AddressField : public FormField {
public:
- virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const;
- virtual FormFieldType GetFormFieldType() const;
+ virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const OVERRIDE;
- static AddressField* Parse(std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml);
+ static AddressField* Parse(AutofillScanner* scanner, bool is_ecml);
// Tries to determine the billing/shipping type of this address.
AddressType FindType() const;
- void SetType(AddressType address_type) { type_ = address_type; }
-
// Returns true if this is a full address as opposed to an address fragment
// such as a stand-alone ZIP code.
bool IsFullAddress();
@@ -36,35 +34,39 @@ class AddressField : public FormField {
private:
AddressField();
- static bool ParseCompany(std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field);
- static bool ParseAddressLines(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field);
- static bool ParseCountry(std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field);
- static bool ParseZipCode(std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field);
- static bool ParseCity(std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field);
- static bool ParseState(std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml, AddressField* address_field);
+ static bool ParseCompany(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field);
+ static bool ParseAddressLines(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field);
+ static bool ParseCountry(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field);
+ static bool ParseZipCode(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field);
+ static bool ParseCity(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field);
+ static bool ParseState(AutofillScanner* scanner,
+ bool is_ecml,
+ AddressField* address_field);
// Looks for an address type in the given text, which the caller must
// convert to lowercase.
static AddressType AddressTypeFromText(const string16& text);
- AutofillField* company_; // optional
- AutofillField* address1_;
- AutofillField* address2_; // optional
- AutofillField* city_;
- AutofillField* state_; // optional
- AutofillField* zip_;
- AutofillField* zip4_; // optional ZIP+4; we don't fill this yet
- AutofillField* country_; // optional
+ const AutofillField* company_; // optional
+ const AutofillField* address1_;
+ const AutofillField* address2_; // optional
+ const AutofillField* city_;
+ const AutofillField* state_; // optional
+ const AutofillField* zip_;
+ const AutofillField* zip4_; // optional ZIP+4; we don't fill this yet
+ const AutofillField* country_; // optional
AddressType type_;
- bool is_ecml_;
DISALLOW_COPY_AND_ASSIGN(AddressField);
};
diff --git a/chrome/browser/autofill/address_field_unittest.cc b/chrome/browser/autofill/address_field_unittest.cc
index 7f63a3c..fe7a910 100644
--- a/chrome/browser/autofill/address_field_unittest.cc
+++ b/chrome/browser/autofill/address_field_unittest.cc
@@ -7,6 +7,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/address_field.h"
#include "chrome/browser/autofill/autofill_field.h"
+#include "chrome/browser/autofill/autofill_scanner.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/glue/form_field.h"
@@ -27,17 +28,15 @@ class AddressFieldTest : public testing::Test {
};
TEST_F(AddressFieldTest, Empty) {
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_EQ(static_cast<AddressField*>(NULL), field_.get());
}
TEST_F(AddressFieldTest, NonParse) {
list_.push_back(new AutofillField);
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_EQ(static_cast<AddressField*>(NULL), field_.get());
}
@@ -50,9 +49,8 @@ TEST_F(AddressFieldTest, ParseOneLineAddress) {
0,
false),
ASCIIToUTF16("addr1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_TRUE(field_->IsFullAddress());
@@ -71,16 +69,15 @@ TEST_F(AddressFieldTest, ParseOneLineAddressBilling) {
0,
false),
ASCIIToUTF16("addr1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kBillingAddress, field_->FindType());
EXPECT_TRUE(field_->IsFullAddress());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
field_type_map_.find(ASCIIToUTF16("addr1")) != field_type_map_.end());
- EXPECT_EQ(ADDRESS_HOME_LINE1, field_type_map_[ASCIIToUTF16("addr1")]);
+ EXPECT_EQ(ADDRESS_BILLING_LINE1, field_type_map_[ASCIIToUTF16("addr1")]);
}
TEST_F(AddressFieldTest, ParseOneLineAddressShipping) {
@@ -92,9 +89,8 @@ TEST_F(AddressFieldTest, ParseOneLineAddressShipping) {
0,
false),
ASCIIToUTF16("addr1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kShippingAddress, field_->FindType());
EXPECT_TRUE(field_->IsFullAddress());
@@ -114,9 +110,8 @@ TEST_F(AddressFieldTest, ParseOneLineAddressEcml) {
0,
false),
ASCIIToUTF16("addr1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, true));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, true));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kShippingAddress, field_->FindType());
EXPECT_TRUE(field_->IsFullAddress());
@@ -143,9 +138,8 @@ TEST_F(AddressFieldTest, ParseTwoLineAddress) {
0,
false),
ASCIIToUTF16("addr2")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_TRUE(field_->IsFullAddress());
@@ -183,9 +177,8 @@ TEST_F(AddressFieldTest, ParseThreeLineAddress) {
0,
false),
ASCIIToUTF16("addr3")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_TRUE(field_->IsFullAddress());
@@ -219,9 +212,8 @@ TEST_F(AddressFieldTest, ParseTwoLineAddressEcml) {
0,
false),
ASCIIToUTF16("addr2")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, true));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, true));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kShippingAddress, field_->FindType());
EXPECT_TRUE(field_->IsFullAddress());
@@ -243,9 +235,8 @@ TEST_F(AddressFieldTest, ParseCity) {
0,
false),
ASCIIToUTF16("city1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_FALSE(field_->IsFullAddress());
@@ -264,9 +255,8 @@ TEST_F(AddressFieldTest, ParseCityEcml) {
0,
false),
ASCIIToUTF16("city1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, true));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, true));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_FALSE(field_->IsFullAddress());
@@ -285,9 +275,8 @@ TEST_F(AddressFieldTest, ParseState) {
0,
false),
ASCIIToUTF16("state1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_FALSE(field_->IsFullAddress());
@@ -307,9 +296,8 @@ TEST_F(AddressFieldTest, ParseStateEcml) {
0,
false),
ASCIIToUTF16("state1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, true));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, true));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_FALSE(field_->IsFullAddress());
@@ -328,9 +316,8 @@ TEST_F(AddressFieldTest, ParseZip) {
0,
false),
ASCIIToUTF16("zip1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_FALSE(field_->IsFullAddress());
@@ -350,9 +337,8 @@ TEST_F(AddressFieldTest, ParseZipEcml) {
0,
false),
ASCIIToUTF16("zip1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, true));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, true));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_FALSE(field_->IsFullAddress());
@@ -383,9 +369,8 @@ TEST_F(AddressFieldTest, ParseStateAndZipOneLabel) {
0,
false),
ASCIIToUTF16("zip")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_FALSE(field_->IsFullAddress());
@@ -407,9 +392,8 @@ TEST_F(AddressFieldTest, ParseCountry) {
0,
false),
ASCIIToUTF16("country1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_FALSE(field_->IsFullAddress());
@@ -428,9 +412,8 @@ TEST_F(AddressFieldTest, ParseCountryEcml) {
0,
false),
ASCIIToUTF16("country1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, true));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, true));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_FALSE(field_->IsFullAddress());
@@ -457,9 +440,8 @@ TEST_F(AddressFieldTest, ParseTwoLineAddressMissingLabel) {
0,
false),
ASCIIToUTF16("addr2")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_TRUE(field_->IsFullAddress());
@@ -481,9 +463,8 @@ TEST_F(AddressFieldTest, ParseCompany) {
0,
false),
ASCIIToUTF16("company1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, false));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_FALSE(field_->IsFullAddress());
@@ -503,9 +484,8 @@ TEST_F(AddressFieldTest, ParseCompanyEcml) {
0,
false),
ASCIIToUTF16("company1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(AddressField::Parse(&iter_, true));
+ AutofillScanner scanner(list_.get());
+ field_.reset(AddressField::Parse(&scanner, true));
ASSERT_NE(static_cast<AddressField*>(NULL), field_.get());
EXPECT_EQ(kGenericAddress, field_->FindType());
EXPECT_FALSE(field_->IsFullAddress());
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
index ea32437..e11a6d4 100644
--- a/chrome/browser/autofill/autofill_manager.cc
+++ b/chrome/browser/autofill/autofill_manager.cc
@@ -625,11 +625,8 @@ void AutofillManager::DeterminePossibleFieldTypesForUpload(
}
void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
- std::vector<const FormStructure*> submitted_forms;
- submitted_forms.push_back(&submitted_form);
-
const CreditCard* imported_credit_card;
- if (!personal_data_->ImportFormData(submitted_forms, &imported_credit_card))
+ if (!personal_data_->ImportFormData(submitted_form, &imported_credit_card))
return;
// If credit card information was submitted, show an infobar to offer to save
@@ -742,11 +739,6 @@ bool AutofillManager::FindCachedFormAndField(const FormData& form,
for (std::vector<AutofillField*>::const_iterator iter =
(*form_structure)->begin();
iter != (*form_structure)->end(); ++iter) {
- // The field list is terminated with a NULL AutofillField, so don't try to
- // dereference it.
- if (!*iter)
- break;
-
if ((**iter) == field) {
*autofill_field = *iter;
break;
@@ -793,10 +785,6 @@ void AutofillManager::GetProfileSuggestions(FormStructure* form,
form_fields.reserve(form->field_count());
for (std::vector<AutofillField*>::const_iterator iter = form->begin();
iter != form->end(); ++iter) {
- // The field list is terminated with a NULL AutofillField, so don't try to
- // dereference it.
- if (!*iter)
- break;
form_fields.push_back((*iter)->type());
}
diff --git a/chrome/browser/autofill/autofill_merge_unittest.cc b/chrome/browser/autofill/autofill_merge_unittest.cc
index 64ee661..6541e24 100644
--- a/chrome/browser/autofill/autofill_merge_unittest.cc
+++ b/chrome/browser/autofill/autofill_merge_unittest.cc
@@ -199,11 +199,10 @@ void AutofillMergeTest::MergeProfiles(const std::string& profiles,
AutofillType::StringToFieldType(UTF16ToUTF8(field->name));
field->set_heuristic_type(type);
}
- std::vector<const FormStructure*> form_structures(1, &form_structure);
// Import the profile.
const CreditCard* imported_credit_card;
- personal_data_->ImportFormData(form_structures, &imported_credit_card);
+ personal_data_->ImportFormData(form_structure, &imported_credit_card);
EXPECT_FALSE(imported_credit_card);
// Clear the |form| to start a new profile.
diff --git a/chrome/browser/autofill/autofill_scanner.cc b/chrome/browser/autofill/autofill_scanner.cc
new file mode 100644
index 0000000..9358854
--- /dev/null
+++ b/chrome/browser/autofill/autofill_scanner.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/autofill/autofill_scanner.h"
+
+#include "base/logging.h"
+#include "chrome/browser/autofill/autofill_field.h"
+
+AutofillScanner::AutofillScanner(const std::vector<AutofillField*>& fields)
+ : cursor_(fields.begin()),
+ end_(fields.end()) {
+}
+
+void AutofillScanner::Advance() {
+ DCHECK(!IsEnd());
+ ++cursor_;
+}
+
+const AutofillField* AutofillScanner::Cursor() const {
+ if (IsEnd()) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ return *cursor_;
+}
+
+bool AutofillScanner::IsEnd() const {
+ return cursor_ == end_;
+}
+
+void AutofillScanner::Rewind() {
+ DCHECK(!saved_cursors_.empty());
+ cursor_ = saved_cursors_.back();
+ saved_cursors_.pop_back();
+}
+
+void AutofillScanner::SaveCursor() {
+ saved_cursors_.push_back(cursor_);
+}
diff --git a/chrome/browser/autofill/autofill_scanner.h b/chrome/browser/autofill/autofill_scanner.h
new file mode 100644
index 0000000..13e8b24
--- /dev/null
+++ b/chrome/browser/autofill/autofill_scanner.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_SCANNER_H_
+#define CHROME_BROWSER_AUTOFILL_AUTOFILL_SCANNER_H_
+#pragma once
+
+#include <vector>
+
+#include "base/basictypes.h"
+
+class AutofillField;
+
+// A helper class for parsing a stream of |AutofillField|'s with lookahead.
+class AutofillScanner {
+ public:
+ explicit AutofillScanner(const std::vector<AutofillField*>& fields);
+
+ // Advances the cursor by one step, if possible.
+ void Advance();
+
+ // Returns the current field in the stream, or |NULL| if there are no more
+ // fields in the stream.
+ const AutofillField* Cursor() const;
+
+ // Returns |true| if the cursor has reached the end of the stream.
+ bool IsEnd() const;
+
+ // Returns the most recently saved cursor -- see also |SaveCursor()|.
+ void Rewind();
+
+ // Saves the current cursor position. Multiple cursor positions can be saved,
+ // with stack ordering semantics. See also |Rewind()|.
+ void SaveCursor();
+
+ private:
+ // Indicates the current position in the stream, represented as a vector.
+ std::vector<AutofillField*>::const_iterator cursor_;
+
+ // A stack of saved positions in the stream.
+ std::vector<std::vector<AutofillField*>::const_iterator> saved_cursors_;
+
+ // The past-the-end pointer for the stream.
+ const std::vector<AutofillField*>::const_iterator end_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillScanner);
+};
+
+#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_SCANNER_H_
diff --git a/chrome/browser/autofill/credit_card_field.cc b/chrome/browser/autofill/credit_card_field.cc
index 9e31e32..b322574 100644
--- a/chrome/browser/autofill/credit_card_field.cc
+++ b/chrome/browser/autofill/credit_card_field.cc
@@ -12,52 +12,41 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
+#include "chrome/browser/autofill/autofill_scanner.h"
#include "chrome/browser/autofill/field_types.h"
#include "grit/autofill_resources.h"
#include "ui/base/l10n/l10n_util.h"
bool CreditCardField::GetFieldInfo(FieldTypeMap* field_type_map) const {
- bool ok = Add(field_type_map, number_, AutofillType(CREDIT_CARD_NUMBER));
- DCHECK(ok);
+ bool ok = Add(field_type_map, number_, CREDIT_CARD_NUMBER);
// If the heuristics detected first and last name in separate fields,
// then ignore both fields. Putting them into separate fields is probably
// wrong, because the credit card can also contain a middle name or middle
// initial.
- if (cardholder_last_ == NULL) {
- // Add() will check if cardholder_ is != NULL.
- ok = ok && Add(field_type_map, cardholder_, AutofillType(CREDIT_CARD_NAME));
- DCHECK(ok);
- }
+ if (cardholder_last_ == NULL)
+ ok = ok && Add(field_type_map, cardholder_, CREDIT_CARD_NAME);
- ok = ok && Add(field_type_map, type_, AutofillType(CREDIT_CARD_TYPE));
- DCHECK(ok);
- ok = ok && Add(field_type_map, expiration_month_,
- AutofillType(CREDIT_CARD_EXP_MONTH));
- DCHECK(ok);
+ ok = ok && Add(field_type_map, type_, CREDIT_CARD_TYPE);
+ ok = ok && Add(field_type_map, expiration_month_, CREDIT_CARD_EXP_MONTH);
ok = ok && Add(field_type_map, expiration_year_,
- AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR));
- DCHECK(ok);
-
+ CREDIT_CARD_EXP_4_DIGIT_YEAR);
return ok;
}
-FormFieldType CreditCardField::GetFormFieldType() const {
- return kCreditCardType;
-}
-
// static
-CreditCardField* CreditCardField::Parse(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml) {
+CreditCardField* CreditCardField::Parse(AutofillScanner* scanner,
+ bool is_ecml) {
+ if (scanner->IsEnd())
+ return NULL;
+
scoped_ptr<CreditCardField> credit_card_field(new CreditCardField);
- std::vector<AutofillField*>::const_iterator q = *iter;
- string16 pattern;
+ scanner->SaveCursor();
// Credit card fields can appear in many different orders.
// We loop until no more credit card related fields are found, see |break| at
// bottom of the loop.
- for (int fields = 0; true; ++fields) {
+ for (int fields = 0; !scanner->IsEnd(); ++fields) {
// Sometimes the cardholder field is just labeled "name". Unfortunately this
// is a dangerously generic word to search for, since it will often match a
// name (not cardholder name) field before or after credit card fields. So
@@ -79,22 +68,22 @@ CreditCardField* CreditCardField::Parse(
}
}
- if (ParseText(&q, name_pattern, &credit_card_field->cardholder_))
+ if (ParseText(scanner, name_pattern, &credit_card_field->cardholder_))
continue;
// As a hard-coded hack for Expedia's billing pages (expedia_checkout.html
// and ExpediaBilling.html in our test suite), recognize separate fields
// for the cardholder's first and last name if they have the labels "cfnm"
// and "clnm".
- std::vector<AutofillField*>::const_iterator p = q;
- AutofillField* first;
- if (!is_ecml && ParseText(&p, ASCIIToUTF16("^cfnm"), &first) &&
- ParseText(&p, ASCIIToUTF16("^clnm"),
+ scanner->SaveCursor();
+ const AutofillField* first;
+ if (!is_ecml && ParseText(scanner, ASCIIToUTF16("^cfnm"), &first) &&
+ ParseText(scanner, ASCIIToUTF16("^clnm"),
&credit_card_field->cardholder_last_)) {
credit_card_field->cardholder_ = first;
- q = p;
continue;
}
+ scanner->Rewind();
}
// We look for a card security code before we look for a credit
@@ -102,14 +91,14 @@ CreditCardField* CreditCardField::Parse(
// has a plethora of names; we've seen "verification #",
// "verification number", "card identification number" and others listed
// in the |pattern| below.
- if (is_ecml) {
+ string16 pattern;
+ if (is_ecml)
pattern = GetEcmlPattern(kEcmlCardVerification);
- } else {
+ else
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_CVC_RE);
- }
- if (credit_card_field->verification_ == NULL &&
- ParseText(&q, pattern, &credit_card_field->verification_))
+ if (!credit_card_field->verification_ &&
+ ParseText(scanner, pattern, &credit_card_field->verification_))
continue;
// TODO(jhawkins): Parse the type select control.
@@ -119,12 +108,13 @@ CreditCardField* CreditCardField::Parse(
else
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_NUMBER_RE);
- if (credit_card_field->number_ == NULL && ParseText(&q, pattern,
- &credit_card_field->number_))
+ if (!credit_card_field->number_ &&
+ ParseText(scanner, pattern, &credit_card_field->number_))
continue;
- if ((*q) && LowerCaseEqualsASCII((*q)->form_control_type, "month")) {
- credit_card_field->expiration_month_ = *q++;
+ if (LowerCaseEqualsASCII(scanner->Cursor()->form_control_type, "month")) {
+ credit_card_field->expiration_month_ = scanner->Cursor();
+ scanner->Advance();
} else {
// "Expiration date" is the most common label here, but some pages have
// "Expires", "exp. date" or "exp. month" and "exp. year". We also look
@@ -144,22 +134,23 @@ CreditCardField* CreditCardField::Parse(
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_MONTH_RE);
if ((!credit_card_field->expiration_month_ ||
- credit_card_field->expiration_month_->IsEmpty()) &&
- ParseText(&q, pattern, &credit_card_field->expiration_month_)) {
-
+ credit_card_field->expiration_month_->IsEmpty()) &&
+ ParseText(scanner, pattern, &credit_card_field->expiration_month_)) {
if (is_ecml)
pattern = GetEcmlPattern(kEcmlCardExpireYear);
else
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_DATE_RE);
- if (!ParseText(&q, pattern, &credit_card_field->expiration_year_)) {
+ if (!ParseText(scanner, pattern,
+ &credit_card_field->expiration_year_)) {
+ scanner->Rewind();
return NULL;
}
continue;
}
}
- if (ParseText(&q, GetEcmlPattern(kEcmlCardExpireDay)))
+ if (ParseText(scanner, GetEcmlPattern(kEcmlCardExpireDay)))
continue;
// Some pages (e.g. ExpediaBilling.html) have a "card description"
@@ -167,7 +158,8 @@ CreditCardField* CreditCardField::Parse(
// We also ignore any other fields within a credit card block that
// start with "card", under the assumption that they are related to
// the credit card section being processed but are uninteresting to us.
- if (ParseText(&q, l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_IGNORED_RE)))
+ if (ParseText(scanner,
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_IGNORED_RE)))
continue;
break;
@@ -176,10 +168,8 @@ CreditCardField* CreditCardField::Parse(
// Some pages have a billing address field after the cardholder name field.
// For that case, allow only just the cardholder name field. The remaining
// CC fields will be picked up in a following CreditCardField.
- if (credit_card_field->cardholder_) {
- *iter = q;
+ if (credit_card_field->cardholder_)
return credit_card_field.release();
- }
// On some pages, the user selects a card type using radio buttons
// (e.g. test page Apple Store Billing.html). We can't handle that yet,
@@ -194,10 +184,10 @@ CreditCardField* CreditCardField::Parse(
(LowerCaseEqualsASCII(
credit_card_field->expiration_month_->form_control_type,
"month")))) {
- *iter = q;
- return credit_card_field.release();
+ return credit_card_field.release();
}
+ scanner->Rewind();
return NULL;
}
diff --git a/chrome/browser/autofill/credit_card_field.h b/chrome/browser/autofill/credit_card_field.h
index bef9aae..8a0a53a 100644
--- a/chrome/browser/autofill/credit_card_field.h
+++ b/chrome/browser/autofill/credit_card_field.h
@@ -9,25 +9,24 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/compiler_specific.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/form_field.h"
class AutofillField;
+class AutofillScanner;
class CreditCardField : public FormField {
public:
// FormField implementation:
- virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const;
- virtual FormFieldType GetFormFieldType() const;
+ virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const OVERRIDE;
- static CreditCardField* Parse(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml);
+ static CreditCardField* Parse(AutofillScanner* scanner, bool is_ecml);
private:
CreditCardField();
- AutofillField* cardholder_; // Optional.
+ const AutofillField* cardholder_; // Optional.
// Occasionally pages have separate fields for the cardholder's first and
// last names; for such pages cardholder_ holds the first name field and
@@ -36,17 +35,18 @@ class CreditCardField : public FormField {
// because the text patterns for matching a cardholder name are different
// than for ordinary names, and because cardholder names never have titles,
// middle names or suffixes.)
- AutofillField* cardholder_last_;
+ const AutofillField* cardholder_last_;
- AutofillField* type_; // Optional. TODO(jhawkins): Parse the select control.
- AutofillField* number_; // Required.
+ // TODO(jhawkins): Parse the select control.
+ const AutofillField* type_; // Optional.
+ const AutofillField* number_; // Required.
// The 3-digit card verification number; we don't currently fill this.
- AutofillField* verification_;
+ const AutofillField* verification_;
// Both required. TODO(jhawkins): Parse the select control.
- AutofillField* expiration_month_;
- AutofillField* expiration_year_;
+ const AutofillField* expiration_month_;
+ const AutofillField* expiration_year_;
DISALLOW_COPY_AND_ASSIGN(CreditCardField);
};
diff --git a/chrome/browser/autofill/credit_card_field_unittest.cc b/chrome/browser/autofill/credit_card_field_unittest.cc
index d9b6fa9..7fd248a 100644
--- a/chrome/browser/autofill/credit_card_field_unittest.cc
+++ b/chrome/browser/autofill/credit_card_field_unittest.cc
@@ -6,6 +6,7 @@
#include "base/memory/scoped_vector.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
+#include "chrome/browser/autofill/autofill_scanner.h"
#include "chrome/browser/autofill/credit_card_field.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/glue/form_field.h"
@@ -27,17 +28,15 @@ class CreditCardFieldTest : public testing::Test {
};
TEST_F(CreditCardFieldTest, Empty) {
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(CreditCardField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(CreditCardField::Parse(&scanner, false));
ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get());
}
TEST_F(CreditCardFieldTest, NonParse) {
list_.push_back(new AutofillField);
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(CreditCardField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(CreditCardField::Parse(&scanner, false));
ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get());
}
@@ -58,9 +57,8 @@ TEST_F(CreditCardFieldTest, ParseCreditCardNoNumber) {
0,
false),
ASCIIToUTF16("year1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(CreditCardField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(CreditCardField::Parse(&scanner, false));
ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get());
}
@@ -73,9 +71,8 @@ TEST_F(CreditCardFieldTest, ParseCreditCardNoDate) {
0,
false),
ASCIIToUTF16("number1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(CreditCardField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(CreditCardField::Parse(&scanner, false));
ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get());
}
@@ -104,9 +101,8 @@ TEST_F(CreditCardFieldTest, ParseMiniumCreditCard) {
0,
false),
ASCIIToUTF16("year1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(CreditCardField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(CreditCardField::Parse(&scanner, false));
ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -148,9 +144,8 @@ TEST_F(CreditCardFieldTest, ParseMiniumCreditCardEcml) {
0,
false),
ASCIIToUTF16("year1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(CreditCardField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(CreditCardField::Parse(&scanner, false));
ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -206,9 +201,8 @@ TEST_F(CreditCardFieldTest, ParseFullCreditCard) {
0,
false),
ASCIIToUTF16("cvc1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(CreditCardField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(CreditCardField::Parse(&scanner, false));
ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -273,9 +267,8 @@ TEST_F(CreditCardFieldTest, ParseFullCreditCardEcml) {
0,
false),
ASCIIToUTF16("cvc1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(CreditCardField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(CreditCardField::Parse(&scanner, false));
ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -331,9 +324,8 @@ TEST_F(CreditCardFieldTest, ParseExpMonthYear) {
0,
false),
ASCIIToUTF16("year")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(CreditCardField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(CreditCardField::Parse(&scanner, false));
ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -386,9 +378,8 @@ TEST_F(CreditCardFieldTest, ParseExpMonthYear2) {
0,
false),
ASCIIToUTF16("year")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(CreditCardField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(CreditCardField::Parse(&scanner, false));
ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
diff --git a/chrome/browser/autofill/email_field.cc b/chrome/browser/autofill/email_field.cc
new file mode 100644
index 0000000..0f7a666
--- /dev/null
+++ b/chrome/browser/autofill/email_field.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/autofill/email_field.h"
+
+#include "chrome/browser/autofill/autofill_scanner.h"
+#include "grit/autofill_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+// static
+EmailField* EmailField::Parse(AutofillScanner* scanner, bool is_ecml) {
+ string16 pattern;
+ if (is_ecml)
+ pattern = GetEcmlPattern(kEcmlShipToEmail, kEcmlBillToEmail, '|');
+ else
+ pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EMAIL_RE);
+
+ const AutofillField* field;
+ if (ParseText(scanner, pattern, &field))
+ return new EmailField(field);
+
+ return NULL;
+}
+
+bool EmailField::GetFieldInfo(FieldTypeMap* field_type_map) const {
+ return Add(field_type_map, field_, EMAIL_ADDRESS);
+}
+
+EmailField::EmailField(const AutofillField* field) : field_(field) {
+}
diff --git a/chrome/browser/autofill/email_field.h b/chrome/browser/autofill/email_field.h
new file mode 100644
index 0000000..0de5ef1
--- /dev/null
+++ b/chrome/browser/autofill/email_field.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_AUTOFILL_EMAIL_FIELD_H_
+#define CHROME_BROWSER_AUTOFILL_EMAIL_FIELD_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/autofill/form_field.h"
+
+class EmailField : public FormField {
+ public:
+ static EmailField* Parse(AutofillScanner* scanner, bool is_ecml);
+
+ // FormField:
+ virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const OVERRIDE;
+
+ private:
+ explicit EmailField(const AutofillField* field);
+
+ const AutofillField* field_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmailField);
+};
+
+#endif // CHROME_BROWSER_AUTOFILL_EMAIL_FIELD_H_
diff --git a/chrome/browser/autofill/form_field.cc b/chrome/browser/autofill/form_field.cc
index 19d0dab..3195c4e 100644
--- a/chrome/browser/autofill/form_field.cc
+++ b/chrome/browser/autofill/form_field.cc
@@ -14,7 +14,9 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/address_field.h"
#include "chrome/browser/autofill/autofill_field.h"
+#include "chrome/browser/autofill/autofill_scanner.h"
#include "chrome/browser/autofill/credit_card_field.h"
+#include "chrome/browser/autofill/email_field.h"
#include "chrome/browser/autofill/field_types.h"
#include "chrome/browser/autofill/form_structure.h"
#include "chrome/browser/autofill/name_field.h"
@@ -72,62 +74,117 @@ const char kEcmlCardExpireDay[] = "ecom_payment_card_expdate_day";
const char kEcmlCardExpireMonth[] = "ecom_payment_card_expdate_month";
const char kEcmlCardExpireYear[] = "ecom_payment_card_expdate_year";
-class EmailField : public FormField {
- public:
- virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const {
- bool ok = Add(field_type_map, field_, AutofillType(EMAIL_ADDRESS));
- DCHECK(ok);
- return true;
- }
+namespace {
+
+// Checks if any of the |form|'s labels are named according to the ECML
+// standard. Returns true if at least one ECML named element is found.
+bool HasECMLField(const std::vector<AutofillField*>& fields) {
+ struct EcmlField {
+ const char* name_;
+ const int length_;
+ } ecml_fields[] = {
+#define ECML_STRING_ENTRY(x) { x, arraysize(x) - 1 },
+ ECML_STRING_ENTRY(kEcmlShipToTitle)
+ ECML_STRING_ENTRY(kEcmlShipToFirstName)
+ ECML_STRING_ENTRY(kEcmlShipToMiddleName)
+ ECML_STRING_ENTRY(kEcmlShipToLastName)
+ ECML_STRING_ENTRY(kEcmlShipToNameSuffix)
+ ECML_STRING_ENTRY(kEcmlShipToCompanyName)
+ ECML_STRING_ENTRY(kEcmlShipToAddress1)
+ ECML_STRING_ENTRY(kEcmlShipToAddress2)
+ ECML_STRING_ENTRY(kEcmlShipToAddress3)
+ ECML_STRING_ENTRY(kEcmlShipToCity)
+ ECML_STRING_ENTRY(kEcmlShipToStateProv)
+ ECML_STRING_ENTRY(kEcmlShipToPostalCode)
+ ECML_STRING_ENTRY(kEcmlShipToCountry)
+ ECML_STRING_ENTRY(kEcmlShipToPhone)
+ ECML_STRING_ENTRY(kEcmlShipToPhone)
+ ECML_STRING_ENTRY(kEcmlShipToEmail)
+ ECML_STRING_ENTRY(kEcmlBillToTitle)
+ ECML_STRING_ENTRY(kEcmlBillToFirstName)
+ ECML_STRING_ENTRY(kEcmlBillToMiddleName)
+ ECML_STRING_ENTRY(kEcmlBillToLastName)
+ ECML_STRING_ENTRY(kEcmlBillToNameSuffix)
+ ECML_STRING_ENTRY(kEcmlBillToCompanyName)
+ ECML_STRING_ENTRY(kEcmlBillToAddress1)
+ ECML_STRING_ENTRY(kEcmlBillToAddress2)
+ ECML_STRING_ENTRY(kEcmlBillToAddress3)
+ ECML_STRING_ENTRY(kEcmlBillToCity)
+ ECML_STRING_ENTRY(kEcmlBillToStateProv)
+ ECML_STRING_ENTRY(kEcmlBillToPostalCode)
+ ECML_STRING_ENTRY(kEcmlBillToCountry)
+ ECML_STRING_ENTRY(kEcmlBillToPhone)
+ ECML_STRING_ENTRY(kEcmlBillToPhone)
+ ECML_STRING_ENTRY(kEcmlBillToEmail)
+ ECML_STRING_ENTRY(kEcmlCardHolder)
+ ECML_STRING_ENTRY(kEcmlCardType)
+ ECML_STRING_ENTRY(kEcmlCardNumber)
+ ECML_STRING_ENTRY(kEcmlCardVerification)
+ ECML_STRING_ENTRY(kEcmlCardExpireMonth)
+ ECML_STRING_ENTRY(kEcmlCardExpireYear)
+#undef ECML_STRING_ENTRY
+ };
- static EmailField* Parse(std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml) {
- string16 pattern;
- if (is_ecml) {
- pattern = GetEcmlPattern(kEcmlShipToEmail, kEcmlBillToEmail, '|');
- } else {
- pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EMAIL_RE);
+ const string16 ecom(ASCIIToUTF16("ecom"));
+ for (std::vector<AutofillField*>::const_iterator field = fields.begin();
+ field != fields.end();
+ ++field) {
+ const string16& utf16_name = (*field)->name;
+ if (StartsWith(utf16_name, ecom, true)) {
+ std::string name(UTF16ToUTF8(utf16_name));
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(ecml_fields); ++i) {
+ if (base::strncasecmp(name.c_str(), ecml_fields[i].name_,
+ ecml_fields[i].length_) == 0) {
+ return true;
+ }
+ }
}
+ }
- AutofillField* field;
- if (ParseText(iter, pattern, &field))
- return new EmailField(field);
+ return false;
+}
- return NULL;
- }
+} // namespace
- private:
- explicit EmailField(AutofillField *field) : field_(field) {}
+// static
+void FormField::ParseFormFields(const std::vector<AutofillField*>& fields,
+ FieldTypeMap* field_type_map) {
+ // First, check if there is at least one form field with an ECML name.
+ // If there is, then we will match an element only if it is in the standard.
+ bool is_ecml = HasECMLField(fields);
- AutofillField* field_;
-};
+ // Parse fields.
+ AutofillScanner scanner(fields);
+ while (!scanner.IsEnd()) {
+ FormField* form_field = FormField::ParseFormField(&scanner, is_ecml);
+ if (!form_field) {
+ scanner.Advance();
+ continue;
+ }
-FormFieldType FormField::GetFormFieldType() const {
- return kOtherFieldType;
+ bool ok = form_field->GetFieldInfo(field_type_map);
+ DCHECK(ok);
+ }
}
// static
-bool FormField::Match(AutofillField* field,
+bool FormField::Match(const AutofillField* field,
const string16& pattern,
bool match_label_only) {
- if (match_label_only) {
- if (MatchLabel(field, pattern)) {
- return true;
- }
- } else {
- // For now, we apply the same pattern to the field's label and the field's
- // name. Matching the name is a bit of a long shot for many patterns, but
- // it generally doesn't hurt to try.
- if (MatchLabel(field, pattern) || MatchName(field, pattern)) {
- return true;
- }
- }
+ if (MatchLabel(field, pattern))
+ return true;
+
+ // For now, we apply the same pattern to the field's label and the field's
+ // name. Matching the name is a bit of a long shot for many patterns, but
+ // it generally doesn't hurt to try.
+ if (!match_label_only && MatchName(field, pattern))
+ return true;
return false;
}
// static
-bool FormField::MatchName(AutofillField* field, const string16& pattern) {
+bool FormField::MatchName(const AutofillField* field, const string16& pattern) {
// TODO(jhawkins): Remove StringToLowerASCII. WebRegularExpression needs to
// be fixed to take WebTextCaseInsensitive into account.
WebKit::WebRegularExpression re(WebKit::WebString(pattern),
@@ -138,7 +195,8 @@ bool FormField::MatchName(AutofillField* field, const string16& pattern) {
}
// static
-bool FormField::MatchLabel(AutofillField* field, const string16& pattern) {
+bool FormField::MatchLabel(const AutofillField* field,
+ const string16& pattern) {
// TODO(jhawkins): Remove StringToLowerASCII. WebRegularExpression needs to
// be fixed to take WebTextCaseInsensitive into account.
WebKit::WebRegularExpression re(WebKit::WebString(pattern),
@@ -149,71 +207,70 @@ bool FormField::MatchLabel(AutofillField* field, const string16& pattern) {
}
// static
-FormField* FormField::ParseFormField(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml) {
+FormField* FormField::ParseFormField(AutofillScanner* scanner, bool is_ecml) {
FormField *field;
- field = EmailField::Parse(iter, is_ecml);
- if (field != NULL)
+
+ field = EmailField::Parse(scanner, is_ecml);
+ if (field)
return field;
+
// Parses both phone and fax.
- field = PhoneField::Parse(iter, is_ecml);
- if (field != NULL)
+ field = PhoneField::Parse(scanner, is_ecml);
+ if (field)
return field;
- field = AddressField::Parse(iter, is_ecml);
- if (field != NULL)
+
+ field = AddressField::Parse(scanner, is_ecml);
+ if (field)
return field;
- field = CreditCardField::Parse(iter, is_ecml);
- if (field != NULL)
+
+ field = CreditCardField::Parse(scanner, is_ecml);
+ if (field)
return field;
- // We search for a NameField last since it matches the word "name", which is
+ // We search for a |NameField| last since it matches the word "name", which is
// relatively general.
- return NameField::Parse(iter, is_ecml);
+ return NameField::Parse(scanner, is_ecml);
}
// static
-bool FormField::ParseText(std::vector<AutofillField*>::const_iterator* iter,
- const string16& pattern) {
- AutofillField* field;
- return ParseText(iter, pattern, &field);
+bool FormField::ParseText(AutofillScanner* scanner, const string16& pattern) {
+ const AutofillField* field;
+ return ParseText(scanner, pattern, &field);
}
// static
-bool FormField::ParseText(std::vector<AutofillField*>::const_iterator* iter,
+bool FormField::ParseText(AutofillScanner* scanner,
const string16& pattern,
- AutofillField** dest) {
- return ParseText(iter, pattern, dest, false);
+ const AutofillField** dest) {
+ return ParseText(scanner, pattern, dest, false);
}
// static
-bool FormField::ParseEmptyText(
- std::vector<AutofillField*>::const_iterator* iter,
- AutofillField** dest) {
- return ParseLabelText(iter, ASCIIToUTF16("^$"), dest);
+bool FormField::ParseEmptyText(AutofillScanner* scanner,
+ const AutofillField** dest) {
+ return ParseLabelText(scanner, ASCIIToUTF16("^$"), dest);
}
// static
-bool FormField::ParseLabelText(
- std::vector<AutofillField*>::const_iterator* iter,
- const string16& pattern,
- AutofillField** dest) {
- return ParseText(iter, pattern, dest, true);
+bool FormField::ParseLabelText(AutofillScanner* scanner,
+ const string16& pattern,
+ const AutofillField** dest) {
+ return ParseText(scanner, pattern, dest, true);
}
// static
-bool FormField::ParseText(std::vector<AutofillField*>::const_iterator* iter,
+bool FormField::ParseText(AutofillScanner* scanner,
const string16& pattern,
- AutofillField** dest,
+ const AutofillField** dest,
bool match_label_only) {
- AutofillField* field = **iter;
- if (!field)
+ if (scanner->IsEnd())
return false;
+ const AutofillField* field = scanner->Cursor();
if (Match(field, pattern, match_label_only)) {
if (dest)
*dest = field;
- (*iter)++;
+ scanner->Advance();
return true;
}
@@ -221,18 +278,14 @@ bool FormField::ParseText(std::vector<AutofillField*>::const_iterator* iter,
}
// static
-bool FormField::ParseLabelAndName(
- std::vector<AutofillField*>::const_iterator* iter,
- const string16& pattern,
- AutofillField** dest) {
- AutofillField* field = **iter;
- if (!field)
- return false;
-
+bool FormField::ParseLabelAndName(AutofillScanner* scanner,
+ const string16& pattern,
+ const AutofillField** dest) {
+ const AutofillField* field = scanner->Cursor();
if (MatchLabel(field, pattern) && MatchName(field, pattern)) {
if (dest)
*dest = field;
- (*iter)++;
+ scanner->Advance();
return true;
}
@@ -240,19 +293,21 @@ bool FormField::ParseLabelAndName(
}
// static
-bool FormField::ParseEmpty(std::vector<AutofillField*>::const_iterator* iter) {
+bool FormField::ParseEmpty(AutofillScanner* scanner) {
// TODO(jhawkins): Handle select fields.
- return ParseLabelAndName(iter, ASCIIToUTF16("^$"), NULL);
+ return ParseLabelAndName(scanner, ASCIIToUTF16("^$"), NULL);
}
// static
-bool FormField::Add(FieldTypeMap* field_type_map, AutofillField* field,
- const AutofillType& type) {
+bool FormField::Add(FieldTypeMap* field_type_map,
+ const AutofillField* field,
+ AutofillFieldType type) {
// Several fields are optional.
- if (field)
- field_type_map->insert(make_pair(field->unique_name(), type.field_type()));
+ if (!field)
+ return true;
- return true;
+ // TODO(isherman): Is this the intent?
+ return field_type_map->insert(make_pair(field->unique_name(), type)).second;
}
string16 FormField::GetEcmlPattern(const char* ecml_name) {
@@ -263,113 +318,5 @@ string16 FormField::GetEcmlPattern(const char* ecml_name1,
const char* ecml_name2,
char pattern_operator) {
return ASCIIToUTF16(StringPrintf("^%s%c^%s",
- ecml_name1, pattern_operator, ecml_name2));
-}
-
-FormFieldSet::FormFieldSet(FormStructure* fields) {
- std::vector<AddressField*> addresses;
-
- // First, find if there is one form field with an ECML name. If there is,
- // then we will match an element only if it is in the standard.
- bool is_ecml = CheckECML(fields);
-
- // Parse fields.
- std::vector<AutofillField*>::const_iterator field = fields->begin();
- while (field != fields->end() && *field != NULL) {
- FormField* form_field = FormField::ParseFormField(&field, is_ecml);
- if (!form_field) {
- field++;
- continue;
- }
-
- push_back(form_field);
-
- if (form_field->GetFormFieldType() == kAddressType) {
- AddressField* address = static_cast<AddressField*>(form_field);
- if (address->IsFullAddress())
- addresses.push_back(address);
- }
- }
-
- // Now determine an address type for each address. Note, if this is an ECML
- // form, then we already got this info from the field names.
- if (!is_ecml && !addresses.empty()) {
- if (addresses.size() == 1) {
- addresses[0]->SetType(addresses[0]->FindType());
- } else {
- AddressType type0 = addresses[0]->FindType();
- AddressType type1 = addresses[1]->FindType();
-
- // When there are two addresses on a page, they almost always appear in
- // the order (billing, shipping).
- bool reversed = (type0 == kShippingAddress && type1 == kBillingAddress);
- addresses[0]->SetType(reversed ? kShippingAddress : kBillingAddress);
- addresses[1]->SetType(reversed ? kBillingAddress : kShippingAddress);
- }
- }
-}
-
-bool FormFieldSet::CheckECML(FormStructure* fields) {
- size_t num_fields = fields->field_count();
- struct EcmlField {
- const char* name_;
- const int length_;
- } form_fields[] = {
-#define ECML_STRING_ENTRY(x) { x, arraysize(x) - 1 },
- ECML_STRING_ENTRY(kEcmlShipToTitle)
- ECML_STRING_ENTRY(kEcmlShipToFirstName)
- ECML_STRING_ENTRY(kEcmlShipToMiddleName)
- ECML_STRING_ENTRY(kEcmlShipToLastName)
- ECML_STRING_ENTRY(kEcmlShipToNameSuffix)
- ECML_STRING_ENTRY(kEcmlShipToCompanyName)
- ECML_STRING_ENTRY(kEcmlShipToAddress1)
- ECML_STRING_ENTRY(kEcmlShipToAddress2)
- ECML_STRING_ENTRY(kEcmlShipToAddress3)
- ECML_STRING_ENTRY(kEcmlShipToCity)
- ECML_STRING_ENTRY(kEcmlShipToStateProv)
- ECML_STRING_ENTRY(kEcmlShipToPostalCode)
- ECML_STRING_ENTRY(kEcmlShipToCountry)
- ECML_STRING_ENTRY(kEcmlShipToPhone)
- ECML_STRING_ENTRY(kEcmlShipToPhone)
- ECML_STRING_ENTRY(kEcmlShipToEmail)
- ECML_STRING_ENTRY(kEcmlBillToTitle)
- ECML_STRING_ENTRY(kEcmlBillToFirstName)
- ECML_STRING_ENTRY(kEcmlBillToMiddleName)
- ECML_STRING_ENTRY(kEcmlBillToLastName)
- ECML_STRING_ENTRY(kEcmlBillToNameSuffix)
- ECML_STRING_ENTRY(kEcmlBillToCompanyName)
- ECML_STRING_ENTRY(kEcmlBillToAddress1)
- ECML_STRING_ENTRY(kEcmlBillToAddress2)
- ECML_STRING_ENTRY(kEcmlBillToAddress3)
- ECML_STRING_ENTRY(kEcmlBillToCity)
- ECML_STRING_ENTRY(kEcmlBillToStateProv)
- ECML_STRING_ENTRY(kEcmlBillToPostalCode)
- ECML_STRING_ENTRY(kEcmlBillToCountry)
- ECML_STRING_ENTRY(kEcmlBillToPhone)
- ECML_STRING_ENTRY(kEcmlBillToPhone)
- ECML_STRING_ENTRY(kEcmlBillToEmail)
- ECML_STRING_ENTRY(kEcmlCardHolder)
- ECML_STRING_ENTRY(kEcmlCardType)
- ECML_STRING_ENTRY(kEcmlCardNumber)
- ECML_STRING_ENTRY(kEcmlCardVerification)
- ECML_STRING_ENTRY(kEcmlCardExpireMonth)
- ECML_STRING_ENTRY(kEcmlCardExpireYear)
-#undef ECML_STRING_ENTRY
- };
-
- const string16 ecom(ASCIIToUTF16("ecom"));
- for (size_t index = 0; index < num_fields; ++index) {
- const string16& utf16_name = fields->field(index)->name;
- if (StartsWith(utf16_name, ecom, true)) {
- std::string name(UTF16ToASCII(utf16_name));
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(form_fields); ++i) {
- if (base::strncasecmp(name.c_str(), form_fields[i].name_,
- form_fields[i].length_) == 0) {
- return true;
- }
- }
- }
- }
-
- return false;
+ ecml_name1, pattern_operator, ecml_name2));
}
diff --git a/chrome/browser/autofill/form_field.h b/chrome/browser/autofill/form_field.h
index 70dea64..3bb5c0e 100644
--- a/chrome/browser/autofill/form_field.h
+++ b/chrome/browser/autofill/form_field.h
@@ -13,7 +13,7 @@
#include "chrome/browser/autofill/autofill_type.h"
class AutofillField;
-class FormStructure;
+class AutofillScanner;
extern const char kEcmlShipToTitle[];
extern const char kEcmlShipToFirstName[];
@@ -57,12 +57,6 @@ extern const char kEcmlCardExpireDay[];
extern const char kEcmlCardExpireMonth[];
extern const char kEcmlCardExpireYear[];
-enum FormFieldType {
- kAddressType,
- kCreditCardType,
- kOtherFieldType
-};
-
// Represents a logical form field in a web form. Classes that implement this
// interface can identify themselves as a particular type of form field, e.g.
// name, phone number, or address field.
@@ -70,53 +64,53 @@ class FormField {
public:
virtual ~FormField() {}
+ // Associates each field in |fields| with its heuristically detected type.
+ // The association is stored into |field_type_map|.
+ static void ParseFormFields(const std::vector<AutofillField*>& fields,
+ FieldTypeMap* field_type_map);
+
// Associates the available AutofillTypes of a FormField into
// |field_type_map|.
virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const = 0;
- // Returns the type of form field of the class implementing this interface.
- virtual FormFieldType GetFormFieldType() const;
-
// Returns true if |field| contains the regexp |pattern| in the name or label.
// If |match_label_only| is true, then only the field's label is considered.
- static bool Match(AutofillField* field,
+ static bool Match(const AutofillField* field,
const string16& pattern,
bool match_label_only);
// Parses a field using the different field views we know about. |is_ecml|
// should be true when the field conforms to the ECML specification.
- static FormField* ParseFormField(
- std::vector<AutofillField*>::const_iterator* field,
- bool is_ecml);
+ static FormField* ParseFormField(AutofillScanner* scanner, bool is_ecml);
// Attempts to parse a text field with the given pattern; returns true on
// success, but doesn't return the actual text field itself.
- static bool ParseText(std::vector<AutofillField*>::const_iterator* iter,
- const string16& pattern);
+ static bool ParseText(AutofillScanner* scanner, const string16& pattern);
// Attempts to parse a text field with the given pattern. Returns true on
// success and fills |dest| with a pointer to the field.
- static bool ParseText(std::vector<AutofillField*>::const_iterator* iter,
+ static bool ParseText(AutofillScanner* scanner,
const string16& pattern,
- AutofillField** dest);
+ const AutofillField** dest);
// Attempts to parse a text field with an empty name or label. Returns true
// on success and fills |dest| with a pointer to the field.
- static bool ParseEmptyText(std::vector<AutofillField*>::const_iterator* iter,
- AutofillField** dest);
+ static bool ParseEmptyText(AutofillScanner* scanner,
+ const AutofillField** dest);
// Attempts to parse a text field label with the given pattern. Returns true
// on success and fills |dest| with a pointer to the field.
- static bool ParseLabelText(std::vector<AutofillField*>::const_iterator* iter,
+ static bool ParseLabelText(AutofillScanner* scanner,
const string16& pattern,
- AutofillField** dest);
+ const AutofillField** dest);
// Attempts to parse a control with an empty label.
- static bool ParseEmpty(std::vector<AutofillField*>::const_iterator* iter);
+ static bool ParseEmpty(AutofillScanner* scanner);
// Adds an association between a field and a type to |field_type_map|.
- static bool Add(FieldTypeMap* field_type_map, AutofillField* field,
- const AutofillType& type);
+ static bool Add(FieldTypeMap* field_type_map,
+ const AutofillField* field,
+ AutofillFieldType type);
protected:
// Only derived classes may instantiate.
@@ -135,37 +129,19 @@ class FormField {
char pattern_operator);
private:
- static bool ParseText(std::vector<AutofillField*>::const_iterator* iter,
+ static bool ParseText(AutofillScanner* scanner,
const string16& pattern,
- AutofillField** dest,
+ const AutofillField** dest,
bool match_label_only);
// For empty strings we need to test that both label and name are empty.
- static bool ParseLabelAndName(
- std::vector<AutofillField*>::const_iterator* iter,
- const string16& pattern,
- AutofillField** dest);
- static bool MatchName(AutofillField* field, const string16& pattern);
- static bool MatchLabel(AutofillField* field, const string16& pattern);
+ static bool ParseLabelAndName(AutofillScanner* scanner,
+ const string16& pattern,
+ const AutofillField** dest);
+ static bool MatchName(const AutofillField* field, const string16& pattern);
+ static bool MatchLabel(const AutofillField* field, const string16& pattern);
DISALLOW_COPY_AND_ASSIGN(FormField);
};
-class FormFieldSet : public std::vector<FormField*> {
- public:
- explicit FormFieldSet(FormStructure* form);
-
- ~FormFieldSet() {
- for (iterator i = begin(); i != end(); ++i)
- delete *i;
- }
-
- private:
- // Checks if any of the labels are named according to the ECML standard.
- // Returns true if at least one ECML named element is found.
- bool CheckECML(FormStructure* fields);
-
- DISALLOW_COPY_AND_ASSIGN(FormFieldSet);
-};
-
#endif // CHROME_BROWSER_AUTOFILL_FORM_FIELD_H_
diff --git a/chrome/browser/autofill/form_structure.cc b/chrome/browser/autofill/form_structure.cc
index e7b0ad9..ce38d80 100644
--- a/chrome/browser/autofill/form_structure.cc
+++ b/chrome/browser/autofill/form_structure.cc
@@ -47,9 +47,6 @@ FormStructure::FormStructure(const FormData& form)
: form_name_(form.name),
source_url_(form.origin),
target_url_(form.action),
- has_credit_card_field_(false),
- has_autofillable_field_(false),
- has_password_fields_(false),
autofill_count_(0) {
// Copy the form fields.
std::vector<webkit_glue::FormField>::const_iterator field;
@@ -66,9 +63,6 @@ FormStructure::FormStructure(const FormData& form)
fields_.push_back(new AutofillField(*field, unique_name));
}
- // Terminate the vector with a NULL item.
- fields_.push_back(NULL);
-
std::string method = UTF16ToUTF8(form.method);
if (StringToLowerASCII(method) == kFormMethodPost) {
method_ = POST;
@@ -82,16 +76,13 @@ FormStructure::FormStructure(const FormData& form)
FormStructure::~FormStructure() {}
void FormStructure::DetermineHeuristicTypes() {
- has_credit_card_field_ = false;
- has_autofillable_field_ = false;
autofill_count_ = 0;
FieldTypeMap field_type_map;
- GetHeuristicFieldInfo(&field_type_map);
+ FormField::ParseFormFields(fields_.get(), &field_type_map);
for (size_t index = 0; index < field_count(); index++) {
AutofillField* field = fields_[index];
- DCHECK(field);
FieldTypeMap::iterator iter = field_type_map.find(field->unique_name());
AutofillFieldType heuristic_autofill_type;
@@ -105,10 +96,6 @@ void FormStructure::DetermineHeuristicTypes() {
field->set_heuristic_type(heuristic_autofill_type);
AutofillType autofill_type(field->type());
- if (autofill_type.group() == AutofillType::CREDIT_CARD)
- has_credit_card_field_ = true;
- if (autofill_type.field_type() != UNKNOWN_TYPE)
- has_autofillable_field_ = true;
}
}
@@ -223,18 +210,8 @@ void FormStructure::ParseQueryResponse(const std::string& response_xml,
FormStructure* form = *iter;
form->server_experiment_id_ = experiment_id;
- if (form->has_autofillable_field_)
- heuristics_detected_fillable_field = true;
-
- form->has_credit_card_field_ = false;
- form->has_autofillable_field_ = false;
-
for (std::vector<AutofillField*>::iterator field = form->fields_.begin();
field != form->fields_.end(); ++field, ++current_type) {
- // The field list is terminated by a NULL AutofillField.
- if (!*field)
- break;
-
// In some cases *successful* response does not return all the fields.
// Quit the update of the types then.
if (current_type == field_types.end())
@@ -244,15 +221,12 @@ void FormStructure::ParseQueryResponse(const std::string& response_xml,
DCHECK_NE(*current_type, UNKNOWN_TYPE);
AutofillFieldType heuristic_type = (*field)->type();
+ if (heuristic_type != UNKNOWN_TYPE)
+ heuristics_detected_fillable_field = true;
+
(*field)->set_server_type(*current_type);
if (heuristic_type != (*field)->type())
query_response_overrode_heuristics = true;
-
- AutofillType autofill_type((*field)->type());
- if (autofill_type.group() == AutofillType::CREDIT_CARD)
- form->has_credit_card_field_ = true;
- if (autofill_type.field_type() != UNKNOWN_TYPE)
- form->has_autofillable_field_ = true;
}
form->UpdateAutofillCount();
@@ -330,8 +304,6 @@ void FormStructure::UpdateFromCache(const FormStructure& cached_form) {
for (std::vector<AutofillField*>::const_iterator iter = begin();
iter != end(); ++iter) {
AutofillField* field = *iter;
- if (!field)
- continue;
std::map<std::string, const AutofillField*>::const_iterator
cached_field = cached_fields.find(field->FieldSignature());
@@ -466,21 +438,27 @@ void FormStructure::LogQualityMetrics(
}
}
-void FormStructure::set_possible_types(int index, const FieldTypeSet& types) {
- int num_fields = static_cast<int>(field_count());
- DCHECK(index >= 0 && index < num_fields);
- if (index >= 0 && index < num_fields)
- fields_[index]->set_possible_types(types);
+void FormStructure::set_possible_types(size_t index,
+ const FieldTypeSet& types) {
+ if (index >= fields_.size()) {
+ NOTREACHED();
+ return;
+ }
+
+ fields_[index]->set_possible_types(types);
}
-const AutofillField* FormStructure::field(int index) const {
+const AutofillField* FormStructure::field(size_t index) const {
+ if (index >= fields_.size()) {
+ NOTREACHED();
+ return NULL;
+ }
+
return fields_[index];
}
size_t FormStructure::field_count() const {
- // Don't count the NULL terminator.
- size_t field_size = fields_.size();
- return (field_size == 0) ? 0 : field_size - 1;
+ return fields_.size();
}
std::string FormStructure::server_experiment_id() const {
@@ -521,16 +499,6 @@ std::string FormStructure::Hash64Bit(const std::string& str) {
return base::Uint64ToString(hash64);
}
-void FormStructure::GetHeuristicFieldInfo(FieldTypeMap* field_type_map) {
- FormFieldSet fields(this);
-
- FormFieldSet::const_iterator field;
- for (field = fields.begin(); field != fields.end(); field++) {
- bool ok = (*field)->GetFieldInfo(field_type_map);
- DCHECK(ok);
- }
-}
-
bool FormStructure::EncodeFormRequest(
FormStructure::EncodeRequestType request_type,
buzz::XmlElement* encompassing_xml_element) const {
diff --git a/chrome/browser/autofill/form_structure.h b/chrome/browser/autofill/form_structure.h
index 341bf19..ee9b7a7 100644
--- a/chrome/browser/autofill/form_structure.h
+++ b/chrome/browser/autofill/form_structure.h
@@ -16,10 +16,6 @@
#include "googleurl/src/gurl.h"
#include "webkit/glue/form_data.h"
-namespace buzz {
- class XmlElement;
-} // namespace buzz
-
enum RequestMethod {
GET,
POST
@@ -33,6 +29,10 @@ enum UploadRequired {
class AutofillMetrics;
+namespace buzz {
+class XmlElement;
+}
+
// FormStructure stores a single HTML form together with the values entered
// in the fields along with additional information needed by Autofill.
class FormStructure {
@@ -92,9 +92,9 @@ class FormStructure {
void LogQualityMetrics(const AutofillMetrics& metric_logger) const;
// Sets the possible types for the field at |index|.
- void set_possible_types(int index, const FieldTypeSet& types);
+ void set_possible_types(size_t index, const FieldTypeSet& types);
- const AutofillField* field(int index) const;
+ const AutofillField* field(size_t index) const;
size_t field_count() const;
// Returns the number of fields that are able to be autofilled.
@@ -129,9 +129,6 @@ class FormStructure {
UPLOAD,
};
- // Associates the field with the heuristic type for each of the field views.
- void GetHeuristicFieldInfo(FieldTypeMap* field_types_map);
-
// Adds form info to |encompassing_xml_element|. |request_type| indicates if
// it is a query or upload.
bool EncodeFormRequest(EncodeRequestType request_type,
@@ -150,15 +147,10 @@ class FormStructure {
// The target URL.
GURL target_url_;
- bool has_credit_card_field_;
- bool has_autofillable_field_;
- bool has_password_fields_;
-
// The number of fields able to be auto-filled.
size_t autofill_count_;
- // A vector of all the input fields in the form. The vector is terminated by
- // a NULL entry.
+ // A vector of all the input fields in the form.
ScopedVector<AutofillField> fields_;
// The names of the form input elements, that are part of the form signature.
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index 9578a74..71f7c13 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -77,9 +77,6 @@ std::string FormStructureBrowserTest::FormStructuresToString(
(*iter)->begin();
field_iter != (*iter)->end();
++field_iter) {
- // The field list is NULL-terminated. Exit loop when at the end.
- if (!*field_iter)
- break;
forms_string += AutofillType::FieldTypeToString((*field_iter)->type());
forms_string += "\n";
}
diff --git a/chrome/browser/autofill/name_field.cc b/chrome/browser/autofill/name_field.cc
index 3c86b39..87f98ce 100644
--- a/chrome/browser/autofill/name_field.cc
+++ b/chrome/browser/autofill/name_field.cc
@@ -8,60 +8,68 @@
#include "base/memory/scoped_ptr.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/autofill_scanner.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "grit/autofill_resources.h"
#include "ui/base/l10n/l10n_util.h"
-NameField* NameField::Parse(std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml) {
+NameField* NameField::Parse(AutofillScanner* scanner, bool is_ecml) {
+ if (scanner->IsEnd())
+ return NULL;
+
// Try FirstLastNameField first since it's more specific.
- NameField* field = FirstLastNameField::Parse(iter, is_ecml);
- if (field == NULL && !is_ecml)
- field = FullNameField::Parse(iter);
+ NameField* field = FirstLastNameField::Parse(scanner, is_ecml);
+ if (!field && !is_ecml)
+ field = FullNameField::Parse(scanner);
return field;
}
bool FullNameField::GetFieldInfo(FieldTypeMap* field_type_map) const {
- bool ok = Add(field_type_map, field_, AutofillType(NAME_FULL));
- DCHECK(ok);
- return true;
+ return Add(field_type_map, field_, NAME_FULL);
}
-FullNameField* FullNameField::Parse(
- std::vector<AutofillField*>::const_iterator* iter) {
+FullNameField* FullNameField::Parse(AutofillScanner* scanner) {
// Exclude labels containing the string "username", which typically
// denotes a login ID rather than the user's actual name.
- AutofillField* field = **iter;
+ const AutofillField* field = scanner->Cursor();
if (Match(field, l10n_util::GetStringUTF16(IDS_AUTOFILL_USERNAME_RE), false))
return NULL;
// Searching for any label containing the word "name" is too general;
// for example, Travelocity_Edit travel profile.html contains a field
// "Travel Profile Name".
- const string16 name_match = l10n_util::GetStringUTF16(IDS_AUTOFILL_NAME_RE);
- if (ParseText(iter, name_match, &field))
+ if (ParseText(scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_NAME_RE),
+ &field))
return new FullNameField(field);
return NULL;
}
-FullNameField::FullNameField(AutofillField* field)
+FullNameField::FullNameField(const AutofillField* field)
: field_(field) {
}
-FirstLastNameField* FirstLastNameField::Parse1(
- std::vector<AutofillField*>::const_iterator* iter) {
+bool FirstLastNameField::GetFieldInfo(FieldTypeMap* field_type_map) const {
+ bool ok = Add(field_type_map, first_name_, NAME_FIRST);
+ ok = ok && Add(field_type_map, last_name_, NAME_LAST);
+ AutofillFieldType type = middle_initial_ ? NAME_MIDDLE_INITIAL : NAME_MIDDLE;
+ ok = ok && Add(field_type_map, middle_name_, type);
+ return ok;
+}
+
+FirstLastNameField* FirstLastNameField::ParseSpecificName(
+ AutofillScanner* scanner) {
// Some pages (e.g. Overstock_comBilling.html, SmithsonianCheckout.html)
// have the label "Name" followed by two or three text fields.
scoped_ptr<FirstLastNameField> v(new FirstLastNameField);
- std::vector<AutofillField*>::const_iterator q = *iter;
+ scanner->SaveCursor();
- AutofillField* next;
- if (ParseText(&q,
+ const AutofillField* next;
+ if (ParseText(scanner,
l10n_util::GetStringUTF16(IDS_AUTOFILL_NAME_SPECIFIC_RE),
&v->first_name_) &&
- ParseEmptyText(&q, &next)) {
- if (ParseEmptyText(&q, &v->last_name_)) {
+ ParseEmptyText(scanner, &next)) {
+ if (ParseEmptyText(scanner, &v->last_name_)) {
// There are three name fields; assume that the middle one is a
// middle initial (it is, at least, on SmithsonianCheckout.html).
v->middle_name_ = next;
@@ -70,17 +78,17 @@ FirstLastNameField* FirstLastNameField::Parse1(
v->last_name_ = next;
}
- *iter = q;
return v.release();
}
+ scanner->Rewind();
return NULL;
}
-FirstLastNameField* FirstLastNameField::Parse2(
- std::vector<AutofillField*>::const_iterator* iter) {
+FirstLastNameField* FirstLastNameField::ParseComponentNames(
+ AutofillScanner* scanner) {
scoped_ptr<FirstLastNameField> v(new FirstLastNameField);
- std::vector<AutofillField*>::const_iterator q = *iter;
+ scanner->SaveCursor();
// A fair number of pages use the names "fname" and "lname" for naming
// first and last name fields (examples from the test suite:
@@ -90,8 +98,8 @@ FirstLastNameField* FirstLastNameField::Parse2(
// so we match "initials" here (and just fill in a first name there,
// American-style).
// The ".*first$" matches fields ending in "first" (example in sample8.html).
- string16 match = l10n_util::GetStringUTF16(IDS_AUTOFILL_FIRST_NAME_RE);
- if (!ParseText(&q, match, &v->first_name_))
+ if (!ParseText(scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_FIRST_NAME_RE),
+ &v->first_name_))
return NULL;
// We check for a middle initial before checking for a middle name
@@ -99,70 +107,55 @@ FirstLastNameField* FirstLastNameField::Parse2(
// as both (the label text is "MI" and the element name is
// "txtmiddlename"); such a field probably actually represents a
// middle initial.
- match = l10n_util::GetStringUTF16(IDS_AUTOFILL_MIDDLE_INITIAL_RE);
- if (ParseText(&q, match, &v->middle_name_)) {
+ if (ParseText(scanner,
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_MIDDLE_INITIAL_RE),
+ &v->middle_name_)) {
v->middle_initial_ = true;
} else {
- match = l10n_util::GetStringUTF16(IDS_AUTOFILL_MIDDLE_NAME_RE);
- ParseText(&q, match, &v->middle_name_);
+ ParseText(scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_MIDDLE_NAME_RE),
+ &v->middle_name_);
}
// The ".*last$" matches fields ending in "last" (example in sample8.html).
- match = l10n_util::GetStringUTF16(IDS_AUTOFILL_LAST_NAME_RE);
- if (!ParseText(&q, match, &v->last_name_))
- return NULL;
+ if (ParseText(scanner, l10n_util::GetStringUTF16(IDS_AUTOFILL_LAST_NAME_RE),
+ &v->last_name_)) {
+ return v.release();
+ }
- *iter = q;
- return v.release();
+ scanner->Rewind();
+ return NULL;
}
FirstLastNameField* FirstLastNameField::ParseEcmlName(
- std::vector<AutofillField*>::const_iterator* iter) {
+ AutofillScanner* scanner) {
scoped_ptr<FirstLastNameField> field(new FirstLastNameField);
- std::vector<AutofillField*>::const_iterator q = *iter;
+ scanner->SaveCursor();
string16 pattern = GetEcmlPattern(kEcmlShipToFirstName,
kEcmlBillToFirstName, '|');
- if (!ParseText(&q, pattern, &field->first_name_))
+ if (!ParseText(scanner, pattern, &field->first_name_))
return NULL;
pattern = GetEcmlPattern(kEcmlShipToMiddleName, kEcmlBillToMiddleName, '|');
- ParseText(&q, pattern, &field->middle_name_);
+ ParseText(scanner, pattern, &field->middle_name_);
pattern = GetEcmlPattern(kEcmlShipToLastName, kEcmlBillToLastName, '|');
- if (ParseText(&q, pattern, &field->last_name_)) {
- *iter = q;
+ if (ParseText(scanner, pattern, &field->last_name_))
return field.release();
- }
+ scanner->Rewind();
return NULL;
}
-FirstLastNameField* FirstLastNameField::Parse(
- std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml) {
- if (is_ecml) {
- return ParseEcmlName(iter);
- } else {
- FirstLastNameField* v = Parse1(iter);
- if (v != NULL)
- return v;
-
- return Parse2(iter);
- }
-}
+FirstLastNameField* FirstLastNameField::Parse(AutofillScanner* scanner,
+ bool is_ecml) {
+ if (is_ecml)
+ return ParseEcmlName(scanner);
-bool FirstLastNameField::GetFieldInfo(FieldTypeMap* field_type_map) const {
- bool ok = Add(field_type_map, first_name_, AutofillType(NAME_FIRST));
- DCHECK(ok);
- ok = ok && Add(field_type_map, last_name_, AutofillType(NAME_LAST));
- DCHECK(ok);
- AutofillType type = middle_initial_ ?
- AutofillType(NAME_MIDDLE_INITIAL) : AutofillType(NAME_MIDDLE);
- ok = ok && Add(field_type_map, middle_name_, type);
- DCHECK(ok);
-
- return ok;
+ FirstLastNameField* field = ParseSpecificName(scanner);
+ if (!field)
+ field = ParseComponentNames(scanner);
+ return field;
}
FirstLastNameField::FirstLastNameField()
@@ -171,4 +164,3 @@ FirstLastNameField::FirstLastNameField()
last_name_(NULL),
middle_initial_(false) {
}
-
diff --git a/chrome/browser/autofill/name_field.h b/chrome/browser/autofill/name_field.h
index 2625ae1..307b076 100644
--- a/chrome/browser/autofill/name_field.h
+++ b/chrome/browser/autofill/name_field.h
@@ -8,14 +8,16 @@
#include <vector>
+#include "base/compiler_specific.h"
#include "chrome/browser/autofill/autofill_field.h"
#include "chrome/browser/autofill/form_field.h"
+class AutofillScanner;
+
// A form field that can parse either a FullNameField or a FirstLastNameField.
class NameField : public FormField {
public:
- static NameField* Parse(std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml);
+ static NameField* Parse(AutofillScanner* scanner, bool is_ecml);
protected:
NameField() {}
@@ -27,38 +29,33 @@ class NameField : public FormField {
// A form field that can parse a full name field.
class FullNameField : public NameField {
public:
- virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const;
+ virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const OVERRIDE;
- static FullNameField* Parse(
- std::vector<AutofillField*>::const_iterator* iter);
+ static FullNameField* Parse(AutofillScanner* scanner);
private:
- explicit FullNameField(AutofillField* field);
+ explicit FullNameField(const AutofillField* field);
- AutofillField* field_;
+ const AutofillField* field_;
DISALLOW_COPY_AND_ASSIGN(FullNameField);
};
// A form field that can parse a first and last name field.
class FirstLastNameField : public NameField {
public:
- static FirstLastNameField* Parse1(
- std::vector<AutofillField*>::const_iterator* iter);
- static FirstLastNameField* Parse2(
- std::vector<AutofillField*>::const_iterator* iter);
- static FirstLastNameField* ParseEcmlName(
- std::vector<AutofillField*>::const_iterator* iter);
- static FirstLastNameField* Parse(
- std::vector<AutofillField*>::const_iterator* iter, bool is_ecml);
+ virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const OVERRIDE;
- virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const;
+ static FirstLastNameField* ParseSpecificName(AutofillScanner* scanner);
+ static FirstLastNameField* ParseComponentNames(AutofillScanner* scanner);
+ static FirstLastNameField* ParseEcmlName(AutofillScanner* scanner);
+ static FirstLastNameField* Parse(AutofillScanner* scanner, bool is_ecml);
private:
FirstLastNameField();
- AutofillField* first_name_;
- AutofillField* middle_name_; // Optional.
- AutofillField* last_name_;
+ const AutofillField* first_name_;
+ const AutofillField* middle_name_; // Optional.
+ const AutofillField* last_name_;
bool middle_initial_; // True if middle_name_ is a middle initial.
DISALLOW_COPY_AND_ASSIGN(FirstLastNameField);
diff --git a/chrome/browser/autofill/name_field_unittest.cc b/chrome/browser/autofill/name_field_unittest.cc
index 2f93556..a583ea5 100644
--- a/chrome/browser/autofill/name_field_unittest.cc
+++ b/chrome/browser/autofill/name_field_unittest.cc
@@ -6,6 +6,7 @@
#include "base/memory/scoped_vector.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
+#include "chrome/browser/autofill/autofill_scanner.h"
#include "chrome/browser/autofill/name_field.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/glue/form_field.h"
@@ -51,9 +52,8 @@ TEST_F(NameFieldTest, FirstMiddleLast) {
0,
false),
ASCIIToUTF16("name3")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, false));
ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -92,9 +92,8 @@ TEST_F(NameFieldTest, FirstMiddleLast2) {
0,
false),
ASCIIToUTF16("name3")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, false));
ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -125,9 +124,8 @@ TEST_F(NameFieldTest, FirstLast) {
0,
false),
ASCIIToUTF16("name2")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, false));
ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -155,9 +153,8 @@ TEST_F(NameFieldTest, FirstLast2) {
0,
false),
ASCIIToUTF16("name2")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, false));
ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -193,9 +190,8 @@ TEST_F(NameFieldTest, FirstLastMiddleWithSpaces) {
0,
false),
ASCIIToUTF16("name3")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, false));
ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -226,9 +222,8 @@ TEST_F(NameFieldTest, FirstLastEmpty) {
0,
false),
ASCIIToUTF16("name2")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, false));
ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -264,9 +259,8 @@ TEST_F(NameFieldTest, FirstMiddleLastEmpty) {
0,
false),
ASCIIToUTF16("name3")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, false));
ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -305,9 +299,8 @@ TEST_F(NameFieldTest, MiddleInitial) {
0,
false),
ASCIIToUTF16("name3")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, false));
ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -338,9 +331,8 @@ TEST_F(NameFieldTest, MiddleInitialNoLastName) {
0,
false),
ASCIIToUTF16("name2")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, false));
ASSERT_EQ(static_cast<NameField*>(NULL), field_.get());
}
@@ -371,9 +363,8 @@ TEST_F(NameFieldTest, MiddleInitialAtEnd) {
0,
false),
ASCIIToUTF16("name3")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, false));
ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -396,9 +387,8 @@ TEST_F(NameFieldTest, ECMLNoName) {
0,
false),
ASCIIToUTF16("field1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, true));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, true));
ASSERT_EQ(static_cast<NameField*>(NULL), field_.get());
}
@@ -419,9 +409,8 @@ TEST_F(NameFieldTest, ECMLMiddleInitialNoLastName) {
0,
false),
ASCIIToUTF16("name2")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, true));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, true));
ASSERT_EQ(static_cast<NameField*>(NULL), field_.get());
}
@@ -450,9 +439,8 @@ TEST_F(NameFieldTest, ECMLFirstMiddleLast) {
0,
false),
ASCIIToUTF16("name3")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(NameField::Parse(&iter_, true));
+ AutofillScanner scanner(list_.get());
+ field_.reset(NameField::Parse(&scanner, true));
ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
diff --git a/chrome/browser/autofill/personal_data_manager.cc b/chrome/browser/autofill/personal_data_manager.cc
index 0684c72..afe1f6b 100644
--- a/chrome/browser/autofill/personal_data_manager.cc
+++ b/chrome/browser/autofill/personal_data_manager.cc
@@ -189,7 +189,7 @@ void PersonalDataManager::OnStateChanged() {
}
bool PersonalDataManager::ImportFormData(
- const std::vector<const FormStructure*>& form_structures,
+ const FormStructure& form,
const CreditCard** imported_credit_card) {
scoped_ptr<AutofillProfile> imported_profile(new AutofillProfile);
scoped_ptr<CreditCard> local_imported_credit_card(new CreditCard);
@@ -202,104 +202,101 @@ bool PersonalDataManager::ImportFormData(
// Detect and discard forms with multiple fields of the same type.
std::set<AutofillFieldType> types_seen;
- for (iter = form_structures.begin(); iter != form_structures.end(); ++iter) {
- const FormStructure* form = *iter;
- for (size_t i = 0; i < form->field_count(); ++i) {
- const AutofillField* field = form->field(i);
- string16 value = CollapseWhitespace(field->value, false);
+ for (size_t i = 0; i < form.field_count(); ++i) {
+ const AutofillField* field = form.field(i);
+ string16 value = CollapseWhitespace(field->value, false);
- // If we don't know the type of the field, or the user hasn't entered any
- // information into the field, then skip it.
- if (!field->IsFieldFillable() || value.empty())
- continue;
-
- AutofillFieldType field_type = field->type();
- FieldTypeGroup group(AutofillType(field_type).group());
+ // If we don't know the type of the field, or the user hasn't entered any
+ // information into the field, then skip it.
+ if (!field->IsFieldFillable() || value.empty())
+ continue;
- // Abandon the import if two fields of the same type are encountered.
- // This indicates ambiguous data or miscategorization of types.
- // Make an exception for PHONE_HOME_NUMBER however as both prefix and
- // suffix are stored against this type.
- if (types_seen.count(field_type) &&
- field_type != PHONE_HOME_NUMBER &&
- field_type != PHONE_FAX_NUMBER) {
- imported_profile.reset();
- local_imported_credit_card.reset();
- break;
- } else {
- types_seen.insert(field_type);
- }
+ AutofillFieldType field_type = field->type();
+ FieldTypeGroup group(AutofillType(field_type).group());
+
+ // Abandon the import if two fields of the same type are encountered.
+ // This indicates ambiguous data or miscategorization of types.
+ // Make an exception for PHONE_HOME_NUMBER however as both prefix and
+ // suffix are stored against this type.
+ if (types_seen.count(field_type) &&
+ field_type != PHONE_HOME_NUMBER &&
+ field_type != PHONE_FAX_NUMBER) {
+ imported_profile.reset();
+ local_imported_credit_card.reset();
+ break;
+ } else {
+ types_seen.insert(field_type);
+ }
- if (group == AutofillType::CREDIT_CARD) {
- // If the user has a password set, we have no way of setting credit
- // card numbers.
- if (!HasPassword()) {
- if (LowerCaseEqualsASCII(field->form_control_type, "month")) {
- DCHECK_EQ(CREDIT_CARD_EXP_MONTH, field_type);
- local_imported_credit_card->SetInfoForMonthInputType(value);
- } else {
- if (field_type == CREDIT_CARD_NUMBER) {
- // Clean up any imported credit card numbers.
- value = CreditCard::StripSeparators(value);
- }
- local_imported_credit_card->SetInfo(field_type, value);
+ if (group == AutofillType::CREDIT_CARD) {
+ // If the user has a password set, we have no way of setting credit
+ // card numbers.
+ if (!HasPassword()) {
+ if (LowerCaseEqualsASCII(field->form_control_type, "month")) {
+ DCHECK_EQ(CREDIT_CARD_EXP_MONTH, field_type);
+ local_imported_credit_card->SetInfoForMonthInputType(value);
+ } else {
+ if (field_type == CREDIT_CARD_NUMBER) {
+ // Clean up any imported credit card numbers.
+ value = CreditCard::StripSeparators(value);
}
- ++importable_credit_card_fields;
+ local_imported_credit_card->SetInfo(field_type, value);
}
- } else {
- // In the case of a phone number, if the whole phone number was entered
- // into a single field, then parse it and set the sub components.
- if (AutofillType(field_type).subgroup() ==
- AutofillType::PHONE_WHOLE_NUMBER) {
- string16 number;
- string16 city_code;
- string16 country_code;
- PhoneNumber::ParsePhoneNumber(value,
- &number,
- &city_code,
- &country_code);
- if (number.empty())
- continue;
-
- if (group == AutofillType::PHONE_HOME) {
- imported_profile->SetInfo(PHONE_HOME_COUNTRY_CODE, country_code);
- imported_profile->SetInfo(PHONE_HOME_CITY_CODE, city_code);
- imported_profile->SetInfo(PHONE_HOME_NUMBER, number);
- } else if (group == AutofillType::PHONE_FAX) {
- imported_profile->SetInfo(PHONE_FAX_COUNTRY_CODE, country_code);
- imported_profile->SetInfo(PHONE_FAX_CITY_CODE, city_code);
- imported_profile->SetInfo(PHONE_FAX_NUMBER, number);
- }
-
+ ++importable_credit_card_fields;
+ }
+ } else {
+ // In the case of a phone number, if the whole phone number was entered
+ // into a single field, then parse it and set the sub components.
+ if (AutofillType(field_type).subgroup() ==
+ AutofillType::PHONE_WHOLE_NUMBER) {
+ string16 number;
+ string16 city_code;
+ string16 country_code;
+ PhoneNumber::ParsePhoneNumber(value,
+ &number,
+ &city_code,
+ &country_code);
+ if (number.empty())
continue;
- }
- // Phone and fax numbers can be split across multiple fields, so we
- // might have already stored the prefix, and now be at the suffix.
- // If so, combine them to form the full number.
- if (group == AutofillType::PHONE_HOME ||
- group == AutofillType::PHONE_FAX) {
- AutofillFieldType number_type = PHONE_HOME_NUMBER;
- if (group == AutofillType::PHONE_FAX)
- number_type = PHONE_FAX_NUMBER;
-
- string16 stored_number = imported_profile->GetInfo(number_type);
- if (stored_number.size() ==
- static_cast<size_t>(PhoneNumber::kPrefixLength) &&
- value.size() == static_cast<size_t>(PhoneNumber::kSuffixLength)) {
- value = stored_number + value;
- }
+ if (group == AutofillType::PHONE_HOME) {
+ imported_profile->SetInfo(PHONE_HOME_COUNTRY_CODE, country_code);
+ imported_profile->SetInfo(PHONE_HOME_CITY_CODE, city_code);
+ imported_profile->SetInfo(PHONE_HOME_NUMBER, number);
+ } else if (group == AutofillType::PHONE_FAX) {
+ imported_profile->SetInfo(PHONE_FAX_COUNTRY_CODE, country_code);
+ imported_profile->SetInfo(PHONE_FAX_CITY_CODE, city_code);
+ imported_profile->SetInfo(PHONE_FAX_NUMBER, number);
}
- imported_profile->SetInfo(field_type, value);
+ continue;
+ }
- // Reject profiles with invalid country information.
- if (field_type == ADDRESS_HOME_COUNTRY &&
- !value.empty() && imported_profile->CountryCode().empty()) {
- imported_profile.reset();
- break;
+ // Phone and fax numbers can be split across multiple fields, so we
+ // might have already stored the prefix, and now be at the suffix.
+ // If so, combine them to form the full number.
+ if (group == AutofillType::PHONE_HOME ||
+ group == AutofillType::PHONE_FAX) {
+ AutofillFieldType number_type = PHONE_HOME_NUMBER;
+ if (group == AutofillType::PHONE_FAX)
+ number_type = PHONE_FAX_NUMBER;
+
+ string16 stored_number = imported_profile->GetInfo(number_type);
+ if (stored_number.size() ==
+ static_cast<size_t>(PhoneNumber::kPrefixLength) &&
+ value.size() == static_cast<size_t>(PhoneNumber::kSuffixLength)) {
+ value = stored_number + value;
}
}
+
+ imported_profile->SetInfo(field_type, value);
+
+ // Reject profiles with invalid country information.
+ if (field_type == ADDRESS_HOME_COUNTRY &&
+ !value.empty() && imported_profile->CountryCode().empty()) {
+ imported_profile.reset();
+ break;
+ }
}
}
diff --git a/chrome/browser/autofill/personal_data_manager.h b/chrome/browser/autofill/personal_data_manager.h
index 7b6299a..d98420c 100644
--- a/chrome/browser/autofill/personal_data_manager.h
+++ b/chrome/browser/autofill/personal_data_manager.h
@@ -9,6 +9,7 @@
#include <set>
#include <vector>
+#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
@@ -63,12 +64,12 @@ class PersonalDataManager
// ProfileSyncServiceObserver:
virtual void OnStateChanged();
- // TODO(isherman): Update this comment
- // If Autofill is able to determine the field types of a significant number of
- // field types that contain information in the FormStructures a profile will
- // be created with all of the information from recognized fields. Returns
- // whether a profile was created.
- bool ImportFormData(const std::vector<const FormStructure*>& form_structures,
+ // Scans the given |form| for importable Autofill data. If the form includes
+ // sufficient address data, it is immediately imported. If the form includes
+ // sufficient credit card data, it is stored into |credit_card|, so that we
+ // can prompt the user whether to save this data.
+ // Returns |true| if sufficient address or credit card data was found.
+ bool ImportFormData(const FormStructure& form,
const CreditCard** credit_card);
// Saves a credit card value detected in |ImportedFormData|.
diff --git a/chrome/browser/autofill/personal_data_manager_unittest.cc b/chrome/browser/autofill/personal_data_manager_unittest.cc
index 458f0e5c..4320e04 100644
--- a/chrome/browser/autofill/personal_data_manager_unittest.cc
+++ b/chrome/browser/autofill/personal_data_manager_unittest.cc
@@ -611,10 +611,9 @@ TEST_F(PersonalDataManagerTest, ImportFormData) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -658,10 +657,9 @@ TEST_F(PersonalDataManagerTest, ImportFormDataBadEmail) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure);
const CreditCard* imported_credit_card;
- EXPECT_FALSE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_FALSE(personal_data_->ImportFormData(form_structure,
+ &imported_credit_card));
ASSERT_EQ(static_cast<CreditCard*>(NULL), imported_credit_card);
// Wait for the refresh.
@@ -688,10 +686,9 @@ TEST_F(PersonalDataManagerTest, ImportFormDataNotEnoughFilledFields) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure);
const CreditCard* imported_credit_card;
- EXPECT_FALSE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_FALSE(personal_data_->ImportFormData(form_structure,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -741,10 +738,9 @@ TEST_F(PersonalDataManagerTest, ImportPhoneNumberSplitAcrossMultipleFields) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -844,10 +840,9 @@ TEST_F(PersonalDataManagerTest, AggregateTwoDifferentProfiles) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -890,9 +885,8 @@ TEST_F(PersonalDataManagerTest, AggregateTwoDifferentProfiles) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- forms.clear();
- forms.push_back(&form_structure2);
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure2,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -939,10 +933,9 @@ TEST_F(PersonalDataManagerTest, AggregateTwoProfilesWithMultiValue) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -985,9 +978,8 @@ TEST_F(PersonalDataManagerTest, AggregateTwoProfilesWithMultiValue) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- forms.clear();
- forms.push_back(&form_structure2);
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure2,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -1045,10 +1037,9 @@ TEST_F(PersonalDataManagerTest, AggregateSameProfileWithConflict) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -1103,9 +1094,8 @@ TEST_F(PersonalDataManagerTest, AggregateSameProfileWithConflict) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- forms.clear();
- forms.push_back(&form_structure2);
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure2,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -1150,10 +1140,9 @@ TEST_F(PersonalDataManagerTest, AggregateProfileWithMissingInfoInOld) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -1196,9 +1185,8 @@ TEST_F(PersonalDataManagerTest, AggregateProfileWithMissingInfoInOld) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- forms.clear();
- forms.push_back(&form_structure2);
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure2,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -1247,10 +1235,9 @@ TEST_F(PersonalDataManagerTest, AggregateProfileWithMissingInfoInNew) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -1294,9 +1281,8 @@ TEST_F(PersonalDataManagerTest, AggregateProfileWithMissingInfoInNew) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- forms.clear();
- forms.push_back(&form_structure2);
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure2,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -1336,10 +1322,9 @@ TEST_F(PersonalDataManagerTest, AggregateProfileWithInsufficientAddress) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_FALSE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_FALSE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Wait for the refresh.
@@ -1375,10 +1360,9 @@ TEST_F(PersonalDataManagerTest, AggregateTwoDifferentCreditCards) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
delete imported_credit_card;
@@ -1413,9 +1397,8 @@ TEST_F(PersonalDataManagerTest, AggregateTwoDifferentCreditCards) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- forms.clear();
- forms.push_back(&form_structure2);
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure2,
+ &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
delete imported_credit_card;
@@ -1455,10 +1438,9 @@ TEST_F(PersonalDataManagerTest, AggregateInvalidCreditCard) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
delete imported_credit_card;
@@ -1493,9 +1475,8 @@ TEST_F(PersonalDataManagerTest, AggregateInvalidCreditCard) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- forms.clear();
- forms.push_back(&form_structure2);
- EXPECT_FALSE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_FALSE(personal_data_->ImportFormData(form_structure2,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Note: no refresh here.
@@ -1525,10 +1506,9 @@ TEST_F(PersonalDataManagerTest, AggregateSameCreditCardWithConflict) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
delete imported_credit_card;
@@ -1564,9 +1544,8 @@ TEST_F(PersonalDataManagerTest, AggregateSameCreditCardWithConflict) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- forms.clear();
- forms.push_back(&form_structure2);
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure2,
+ &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
delete imported_credit_card;
@@ -1607,10 +1586,9 @@ TEST_F(PersonalDataManagerTest, AggregateEmptyCreditCardWithConflict) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
delete imported_credit_card;
@@ -1642,9 +1620,8 @@ TEST_F(PersonalDataManagerTest, AggregateEmptyCreditCardWithConflict) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- forms.clear();
- forms.push_back(&form_structure2);
- EXPECT_FALSE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_FALSE(personal_data_->ImportFormData(form_structure2,
+ &imported_credit_card));
EXPECT_FALSE(imported_credit_card);
// Note: no refresh here.
@@ -1678,10 +1655,9 @@ TEST_F(PersonalDataManagerTest, AggregateCreditCardWithMissingInfoInNew) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
delete imported_credit_card;
@@ -1715,9 +1691,8 @@ TEST_F(PersonalDataManagerTest, AggregateCreditCardWithMissingInfoInNew) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- forms.clear();
- forms.push_back(&form_structure2);
- EXPECT_FALSE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_FALSE(personal_data_->ImportFormData(form_structure2,
+ &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
// Note: no refresh here.
@@ -1749,10 +1724,9 @@ TEST_F(PersonalDataManagerTest, AggregateCreditCardWithMissingInfoInOld) {
FormStructure form_structure1(form1);
form_structure1.DetermineHeuristicTypes();
- std::vector<const FormStructure*> forms;
- forms.push_back(&form_structure1);
const CreditCard* imported_credit_card;
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure1,
+ &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
delete imported_credit_card;
@@ -1788,9 +1762,8 @@ TEST_F(PersonalDataManagerTest, AggregateCreditCardWithMissingInfoInOld) {
FormStructure form_structure2(form2);
form_structure2.DetermineHeuristicTypes();
- forms.clear();
- forms.push_back(&form_structure2);
- EXPECT_TRUE(personal_data_->ImportFormData(forms, &imported_credit_card));
+ EXPECT_TRUE(personal_data_->ImportFormData(form_structure2,
+ &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
personal_data_->SaveImportedCreditCard(*imported_credit_card);
delete imported_credit_card;
diff --git a/chrome/browser/autofill/phone_field.cc b/chrome/browser/autofill/phone_field.cc
index ef1695d..7306764 100644
--- a/chrome/browser/autofill/phone_field.cc
+++ b/chrome/browser/autofill/phone_field.cc
@@ -10,6 +10,7 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
+#include "chrome/browser/autofill/autofill_scanner.h"
#include "chrome/browser/autofill/fax_number.h"
#include "chrome/browser/autofill/home_phone_number.h"
#include "grit/autofill_resources.h"
@@ -97,14 +98,12 @@ PhoneField::Parser PhoneField::phone_field_grammars_[] = {
PhoneField::~PhoneField() {}
// static
-PhoneField* PhoneField::Parse(std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml) {
- DCHECK(iter);
- if (!iter)
+PhoneField* PhoneField::Parse(AutofillScanner* scanner, bool is_ecml) {
+ if (scanner->IsEnd())
return NULL;
if (is_ecml)
- return ParseECML(iter);
+ return ParseECML(scanner);
scoped_ptr<PhoneField> phone_field(new PhoneField);
@@ -113,7 +112,7 @@ PhoneField* PhoneField::Parse(std::vector<AutofillField*>::const_iterator* iter,
// but "area" and "someotherarea" parsed as HOME, for example).
for (int i = PHONE_TYPE_MAX - 1; i >= PHONE_TYPE_FIRST; --i) {
phone_field->SetPhoneType(static_cast<PhoneField::PhoneType>(i));
- if (ParseInternal(phone_field.get(), iter, i == HOME_PHONE))
+ if (ParseInternal(phone_field.get(), scanner, i == HOME_PHONE))
return phone_field.release();
}
@@ -121,12 +120,11 @@ PhoneField* PhoneField::Parse(std::vector<AutofillField*>::const_iterator* iter,
}
// static
-PhoneField* PhoneField::ParseECML(
- std::vector<AutofillField*>::const_iterator* iter) {
+PhoneField* PhoneField::ParseECML(AutofillScanner* scanner) {
string16 pattern(GetEcmlPattern(kEcmlShipToPhone, kEcmlBillToPhone, '|'));
- AutofillField* field;
- if (ParseText(iter, pattern, &field)) {
+ const AutofillField* field;
+ if (ParseText(scanner, pattern, &field)) {
PhoneField* phone_field = new PhoneField();
phone_field->parsed_phone_fields_[FIELD_PHONE] = field;
return phone_field;
@@ -136,7 +134,7 @@ PhoneField* PhoneField::ParseECML(
}
bool PhoneField::GetFieldInfo(FieldTypeMap* field_type_map) const {
- bool ok = false;
+ bool ok = true;
DCHECK(parsed_phone_fields_[FIELD_PHONE]); // Phone was correctly parsed.
@@ -144,36 +142,31 @@ bool PhoneField::GetFieldInfo(FieldTypeMap* field_type_map) const {
(parsed_phone_fields_[FIELD_AREA_CODE] != NULL) ||
(parsed_phone_fields_[FIELD_SUFFIX] != NULL)) {
if (parsed_phone_fields_[FIELD_COUNTRY_CODE] != NULL) {
- ok = Add(field_type_map,
- parsed_phone_fields_[FIELD_COUNTRY_CODE],
- AutofillType(number_->GetCountryCodeType()));
- DCHECK(ok);
+ ok = ok && Add(field_type_map,
+ parsed_phone_fields_[FIELD_COUNTRY_CODE],
+ number_->GetCountryCodeType());
}
if (parsed_phone_fields_[FIELD_AREA_CODE] != NULL) {
- ok = Add(field_type_map,
- parsed_phone_fields_[FIELD_AREA_CODE],
- AutofillType(number_->GetCityCodeType()));
- DCHECK(ok);
+ ok = ok && Add(field_type_map,
+ parsed_phone_fields_[FIELD_AREA_CODE],
+ number_->GetCityCodeType());
}
// We tag the prefix as PHONE_HOME_NUMBER, then when filling the form
// we fill only the prefix depending on the size of the input field.
- ok = Add(field_type_map,
- parsed_phone_fields_[FIELD_PHONE],
- AutofillType(number_->GetNumberType()));
- DCHECK(ok);
+ ok = ok && Add(field_type_map,
+ parsed_phone_fields_[FIELD_PHONE],
+ number_->GetNumberType());
// We tag the suffix as PHONE_HOME_NUMBER, then when filling the form
// we fill only the suffix depending on the size of the input field.
if (parsed_phone_fields_[FIELD_SUFFIX] != NULL) {
- ok = Add(field_type_map,
- parsed_phone_fields_[FIELD_SUFFIX],
- AutofillType(number_->GetNumberType()));
- DCHECK(ok);
+ ok = ok && Add(field_type_map,
+ parsed_phone_fields_[FIELD_SUFFIX],
+ number_->GetNumberType());
}
} else {
ok = Add(field_type_map,
parsed_phone_fields_[FIELD_PHONE],
- AutofillType(number_->GetWholeNumberType()));
- DCHECK(ok);
+ number_->GetWholeNumberType());
}
return ok;
@@ -256,28 +249,25 @@ string16 PhoneField::GetRegExp(RegexType regex_id) const {
}
// static
-bool PhoneField::ParseInternal(
- PhoneField *phone_field,
- std::vector<AutofillField*>::const_iterator* iter,
- bool regular_phone) {
- DCHECK(iter);
-
+bool PhoneField::ParseInternal(PhoneField *phone_field,
+ AutofillScanner* scanner,
+ bool regular_phone) {
DCHECK(phone_field);
- if (!phone_field)
- return false;
-
- std::vector<AutofillField*>::const_iterator q = *iter;
+ scanner->SaveCursor();
// The form owns the following variables, so they should not be deleted.
- AutofillField* parsed_fields[FIELD_MAX];
+ const AutofillField* parsed_fields[FIELD_MAX];
for (size_t i = 0; i < arraysize(phone_field_grammars_); ++i) {
memset(parsed_fields, 0, sizeof(parsed_fields));
- q = *iter;
- // Attempt to parse next possible match.
+ scanner->Rewind();
+ scanner->SaveCursor();
+
+ // Attempt to parse according to the next grammar.
for (; i < arraysize(phone_field_grammars_) &&
phone_field_grammars_[i].regex != REGEX_SEPARATOR; ++i) {
- if (!ParseText(&q, phone_field->GetRegExp(phone_field_grammars_[i].regex),
+ if (!ParseText(scanner,
+ phone_field->GetRegExp(phone_field_grammars_[i].regex),
&parsed_fields[phone_field_grammars_[i].phone_part]))
break;
if (phone_field_grammars_[i].max_size &&
@@ -287,19 +277,30 @@ bool PhoneField::ParseInternal(
break;
}
}
- if (i >= arraysize(phone_field_grammars_))
+
+ if (i >= arraysize(phone_field_grammars_)) {
+ scanner->Rewind();
return false; // Parsing failed.
+ }
if (phone_field_grammars_[i].regex == REGEX_SEPARATOR)
break; // Parsing succeeded.
+
+ // Proceed to the next grammar.
do {
++i;
} while (i < arraysize(phone_field_grammars_) &&
phone_field_grammars_[i].regex != REGEX_SEPARATOR);
- if (i + 1 == arraysize(phone_field_grammars_))
+
+ if (i + 1 == arraysize(phone_field_grammars_)) {
+ scanner->Rewind();
return false; // Tried through all the possibilities - did not match.
+ }
}
- if (!parsed_fields[FIELD_PHONE])
+
+ if (!parsed_fields[FIELD_PHONE]) {
+ scanner->Rewind();
return false;
+ }
for (int i = 0; i < FIELD_MAX; ++i)
phone_field->parsed_phone_fields_[i] = parsed_fields[i];
@@ -308,18 +309,17 @@ bool PhoneField::ParseInternal(
// Look for a third text box.
if (!phone_field->parsed_phone_fields_[FIELD_SUFFIX]) {
- if (!ParseText(&q, phone_field->GetSuffixRegex(),
+ if (!ParseText(scanner, phone_field->GetSuffixRegex(),
&phone_field->parsed_phone_fields_[FIELD_SUFFIX])) {
- ParseText(&q, phone_field->GetSuffixSeparatorRegex(),
+ ParseText(scanner, phone_field->GetSuffixSeparatorRegex(),
&phone_field->parsed_phone_fields_[FIELD_SUFFIX]);
}
}
// Now look for an extension.
- ParseText(&q, phone_field->GetExtensionRegex(),
+ ParseText(scanner, phone_field->GetExtensionRegex(),
&phone_field->parsed_phone_fields_[FIELD_EXTENSION]);
- *iter = q;
return true;
}
diff --git a/chrome/browser/autofill/phone_field.h b/chrome/browser/autofill/phone_field.h
index e79809f..de1181f 100644
--- a/chrome/browser/autofill/phone_field.h
+++ b/chrome/browser/autofill/phone_field.h
@@ -8,12 +8,14 @@
#include <vector>
+#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/form_field.h"
#include "chrome/browser/autofill/phone_number.h"
class AutofillField;
+class AutofillScanner;
// A phone number in one of the following formats:
// - area code, prefix, suffix
@@ -23,12 +25,10 @@ class PhoneField : public FormField {
public:
virtual ~PhoneField();
- static PhoneField* Parse(std::vector<AutofillField*>::const_iterator* iter,
- bool is_ecml);
- static PhoneField* ParseECML(
- std::vector<AutofillField*>::const_iterator* iter);
+ virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const OVERRIDE;
- virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const;
+ static PhoneField* Parse(AutofillScanner* scanner, bool is_ecml);
+ static PhoneField* ParseECML(AutofillScanner* scanner);
private:
PhoneField();
@@ -83,7 +83,7 @@ class PhoneField : public FormField {
// |regular_phone| - true if the parsed phone is a HOME phone, false
// otherwise.
static bool ParseInternal(PhoneField* field,
- std::vector<AutofillField*>::const_iterator* iter,
+ AutofillScanner* scanner,
bool regular_phone);
void SetPhoneType(PhoneType phone_type);
@@ -108,7 +108,7 @@ class PhoneField : public FormField {
// FIELD_PHONE is always present; holds suffix if prefix is present.
// The rest could be NULL.
- AutofillField* parsed_phone_fields_[FIELD_MAX];
+ const AutofillField* parsed_phone_fields_[FIELD_MAX];
static struct Parser {
RegexType regex; // Field matching reg-ex.
diff --git a/chrome/browser/autofill/phone_field_unittest.cc b/chrome/browser/autofill/phone_field_unittest.cc
index daa598b..d8cfba7 100644
--- a/chrome/browser/autofill/phone_field_unittest.cc
+++ b/chrome/browser/autofill/phone_field_unittest.cc
@@ -6,6 +6,7 @@
#include "base/memory/scoped_vector.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
+#include "chrome/browser/autofill/autofill_scanner.h"
#include "chrome/browser/autofill/phone_field.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/glue/form_field.h"
@@ -27,17 +28,15 @@ class PhoneFieldTest : public testing::Test {
};
TEST_F(PhoneFieldTest, Empty) {
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, false));
ASSERT_EQ(static_cast<PhoneField*>(NULL), field_.get());
}
TEST_F(PhoneFieldTest, NonParse) {
list_.push_back(new AutofillField);
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, false));
ASSERT_EQ(static_cast<PhoneField*>(NULL), field_.get());
}
@@ -50,9 +49,8 @@ TEST_F(PhoneFieldTest, ParseOneLinePhone) {
0,
false),
ASCIIToUTF16("phone1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, false));
ASSERT_NE(static_cast<PhoneField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -69,9 +67,8 @@ TEST_F(PhoneFieldTest, ParseOneLinePhoneEcml) {
0,
false),
ASCIIToUTF16("phone1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, true));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, true));
ASSERT_NE(static_cast<PhoneField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -96,9 +93,8 @@ TEST_F(PhoneFieldTest, ParseTwoLinePhone) {
0,
false),
ASCIIToUTF16("phone1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, false));
ASSERT_NE(static_cast<PhoneField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -127,9 +123,8 @@ TEST_F(PhoneFieldTest, ParseTwoLinePhoneEcmlShipTo) {
0,
false),
ASCIIToUTF16("phone1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, false));
ASSERT_NE(static_cast<PhoneField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -158,9 +153,8 @@ TEST_F(PhoneFieldTest, ParseTwoLinePhoneEcmlBillTo) {
0,
false),
ASCIIToUTF16("phone1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, false));
ASSERT_NE(static_cast<PhoneField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -209,9 +203,8 @@ TEST_F(PhoneFieldTest, ThreePartPhoneNumber) {
0,
false),
ASCIIToUTF16("ext1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, false));
ASSERT_NE(static_cast<PhoneField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -253,9 +246,8 @@ TEST_F(PhoneFieldTest, ThreePartPhoneNumberPrefixSuffix) {
0,
false),
ASCIIToUTF16("suffix1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, false));
ASSERT_NE(static_cast<PhoneField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -278,9 +270,8 @@ TEST_F(PhoneFieldTest, ParseOneLineFax) {
0,
false),
ASCIIToUTF16("fax1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, false));
ASSERT_NE(static_cast<PhoneField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -305,9 +296,8 @@ TEST_F(PhoneFieldTest, ParseTwoLineFax) {
0,
false),
ASCIIToUTF16("fax1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, false));
ASSERT_NE(static_cast<PhoneField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
@@ -344,9 +334,8 @@ TEST_F(PhoneFieldTest, ThreePartFaxNumberPrefixSuffix) {
0,
false),
ASCIIToUTF16("suffix1")));
- list_.push_back(NULL);
- iter_ = list_.begin();
- field_.reset(PhoneField::Parse(&iter_, false));
+ AutofillScanner scanner(list_.get());
+ field_.reset(PhoneField::Parse(&scanner, false));
ASSERT_NE(static_cast<PhoneField*>(NULL), field_.get());
ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
ASSERT_TRUE(
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 7eef26e..9ace239 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -159,6 +159,8 @@
'browser/autofill/autofill_metrics.h',
'browser/autofill/autofill_profile.cc',
'browser/autofill/autofill_profile.h',
+ 'browser/autofill/autofill_scanner.cc',
+ 'browser/autofill/autofill_scanner.h',
'browser/autofill/autofill_type.cc',
'browser/autofill/autofill_type.h',
'browser/autofill/autofill_xml_parser.cc',
@@ -169,6 +171,8 @@
'browser/autofill/credit_card.h',
'browser/autofill/credit_card_field.cc',
'browser/autofill/credit_card_field.h',
+ 'browser/autofill/email_field.cc',
+ 'browser/autofill/email_field.h',
'browser/autofill/fax_number.cc',
'browser/autofill/fax_number.h',
'browser/autofill/field_types.h',