diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-07 08:52:23 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-07 08:52:23 +0000 |
commit | 8c79c2041a6131672e7241cf91caabf63ed7109b (patch) | |
tree | 0291220bacfd0c93e5afa5a837a733f3ad87ef56 /net/ftp | |
parent | 49ab5043474c2109b2dc6f6feb86a6f5d7a6dfdd (diff) | |
download | chromium_src-8c79c2041a6131672e7241cf91caabf63ed7109b.zip chromium_src-8c79c2041a6131672e7241cf91caabf63ed7109b.tar.gz chromium_src-8c79c2041a6131672e7241cf91caabf63ed7109b.tar.bz2 |
Implement Windows FTP directory listing parser.
TEST=Covered by net_unittests.
BUG=25520
Review URL: http://codereview.chromium.org/374010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31376 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/ftp')
-rw-r--r-- | net/ftp/ftp_directory_listing_buffer.cc | 1 | ||||
-rw-r--r-- | net/ftp/ftp_directory_listing_buffer_unittest.cc | 2 | ||||
-rw-r--r-- | net/ftp/ftp_directory_listing_parsers.cc | 92 | ||||
-rw-r--r-- | net/ftp/ftp_directory_listing_parsers.h | 15 | ||||
-rw-r--r-- | net/ftp/ftp_directory_listing_parsers_unittest.cc | 55 |
5 files changed, 163 insertions, 2 deletions
diff --git a/net/ftp/ftp_directory_listing_buffer.cc b/net/ftp/ftp_directory_listing_buffer.cc index d7833e8..8e3ee39 100644 --- a/net/ftp/ftp_directory_listing_buffer.cc +++ b/net/ftp/ftp_directory_listing_buffer.cc @@ -42,6 +42,7 @@ namespace net { FtpDirectoryListingBuffer::FtpDirectoryListingBuffer() : current_parser_(NULL) { parsers_.insert(new FtpLsDirectoryListingParser()); + parsers_.insert(new FtpWindowsDirectoryListingParser()); parsers_.insert(new FtpVmsDirectoryListingParser()); } diff --git a/net/ftp/ftp_directory_listing_buffer_unittest.cc b/net/ftp/ftp_directory_listing_buffer_unittest.cc index 00c37963..9cf557f 100644 --- a/net/ftp/ftp_directory_listing_buffer_unittest.cc +++ b/net/ftp/ftp_directory_listing_buffer_unittest.cc @@ -21,6 +21,8 @@ TEST(FtpDirectoryListingBufferTest, Parse) { "dir-listing-ls-2", "dir-listing-ls-3", "dir-listing-ls-4", + "dir-listing-windows-1", + "dir-listing-windows-2", "dir-listing-vms-1", "dir-listing-vms-2", "dir-listing-vms-3", diff --git a/net/ftp/ftp_directory_listing_parsers.cc b/net/ftp/ftp_directory_listing_parsers.cc index 4149390..c2679d7 100644 --- a/net/ftp/ftp_directory_listing_parsers.cc +++ b/net/ftp/ftp_directory_listing_parsers.cc @@ -88,6 +88,54 @@ bool UnixDateListingToTime(const std::vector<string16>& columns, return true; } +bool WindowsDateListingToTime(const std::vector<string16>& columns, + base::Time* time) { + DCHECK_EQ(4U, columns.size()); + + base::Time::Exploded time_exploded = { 0 }; + + // Date should be in format MM-DD-YY[YY]. + std::vector<string16> date_parts; + SplitString(columns[0], '-', &date_parts); + if (date_parts.size() != 3) + return false; + if (!StringToInt(date_parts[0], &time_exploded.month)) + return false; + if (!StringToInt(date_parts[1], &time_exploded.day_of_month)) + return false; + if (!StringToInt(date_parts[2], &time_exploded.year)) + return false; + if (time_exploded.year < 0) + return false; + // If year has only two digits then assume that 00-79 is 2000-2079, + // and 80-99 is 1980-1999. + if (time_exploded.year < 80) + time_exploded.year += 2000; + else if (time_exploded.year < 100) + time_exploded.year += 1900; + + // Time should be in format HH:MM(AM|PM) + if (columns[1].length() != 7) + return false; + std::vector<string16> time_parts; + SplitString(columns[1].substr(0, 5), ':', &time_parts); + if (time_parts.size() != 2) + return false; + if (!StringToInt(time_parts[0], &time_exploded.hour)) + return false; + if (!StringToInt(time_parts[1], &time_exploded.minute)) + return false; + string16 am_or_pm(columns[1].substr(5, 2)); + if (EqualsASCII(am_or_pm, "PM")) + time_exploded.hour += 12; + else if (!EqualsASCII(am_or_pm, "AM")) + return false; + + // We don't know the time zone of the server, so just use local time. + *time = base::Time::FromLocalExploded(time_exploded); + return true; +} + // Converts the filename component in listing to the filename we can display. // Returns true on success. bool ParseVmsFilename(const string16& raw_filename, string16* parsed_filename, @@ -109,7 +157,7 @@ bool ParseVmsFilename(const string16& raw_filename, string16* parsed_filename, SplitString(listing_parts[0], '.', &filename_parts); if (filename_parts.size() != 2) return false; - if (filename_parts[1] == ASCIIToUTF16("DIR")) { + if (EqualsASCII(filename_parts[1], "DIR")) { *parsed_filename = StringToLowerASCII(filename_parts[0]); *is_directory = true; } else { @@ -252,7 +300,7 @@ bool FtpLsDirectoryListingParser::ConsumeLine(const string16& line) { SplitString(CollapseWhitespace(line, false), ' ', &columns); if (columns.size() == 11) { // Check if it is a symlink. - if (columns[9] != ASCIIToUTF16("->")) + if (!EqualsASCII(columns[9], "->")) return false; // Drop the symlink target from columns, we don't use it. @@ -303,6 +351,46 @@ FtpDirectoryListingEntry FtpLsDirectoryListingParser::PopEntry() { return entry; } +FtpWindowsDirectoryListingParser::FtpWindowsDirectoryListingParser() { +} + +bool FtpWindowsDirectoryListingParser::ConsumeLine(const string16& line) { + std::vector<string16> columns; + SplitString(CollapseWhitespace(line, false), ' ', &columns); + if (columns.size() != 4) + return false; + + FtpDirectoryListingEntry entry; + entry.name = columns[3]; + + if (EqualsASCII(columns[2], "<DIR>")) { + entry.type = FtpDirectoryListingEntry::DIRECTORY; + entry.size = -1; + } else { + entry.type = FtpDirectoryListingEntry::FILE; + if (!StringToInt64(columns[2], &entry.size)) + return false; + if (entry.size < 0) + return false; + } + + if (!WindowsDateListingToTime(columns, &entry.last_modified)) + return false; + + entries_.push(entry); + return true; +} + +bool FtpWindowsDirectoryListingParser::EntryAvailable() const { + return !entries_.empty(); +} + +FtpDirectoryListingEntry FtpWindowsDirectoryListingParser::PopEntry() { + FtpDirectoryListingEntry entry = entries_.front(); + entries_.pop(); + return entry; +} + FtpVmsDirectoryListingParser::FtpVmsDirectoryListingParser() : state_(STATE_INITIAL), last_is_directory_(false) { diff --git a/net/ftp/ftp_directory_listing_parsers.h b/net/ftp/ftp_directory_listing_parsers.h index 2cf0c4f..62a23cf 100644 --- a/net/ftp/ftp_directory_listing_parsers.h +++ b/net/ftp/ftp_directory_listing_parsers.h @@ -62,6 +62,21 @@ class FtpLsDirectoryListingParser : public FtpDirectoryListingParser { DISALLOW_COPY_AND_ASSIGN(FtpLsDirectoryListingParser); }; +class FtpWindowsDirectoryListingParser : public FtpDirectoryListingParser { + public: + FtpWindowsDirectoryListingParser(); + + // FtpDirectoryListingParser methods: + virtual bool ConsumeLine(const string16& line); + virtual bool EntryAvailable() const; + virtual FtpDirectoryListingEntry PopEntry(); + + private: + std::queue<FtpDirectoryListingEntry> entries_; + + DISALLOW_COPY_AND_ASSIGN(FtpWindowsDirectoryListingParser); +}; + // Parser for VMS-style directory listing (including variants). class FtpVmsDirectoryListingParser : public FtpDirectoryListingParser { public: diff --git a/net/ftp/ftp_directory_listing_parsers_unittest.cc b/net/ftp/ftp_directory_listing_parsers_unittest.cc index 0d0c1f5..da5ca11 100644 --- a/net/ftp/ftp_directory_listing_parsers_unittest.cc +++ b/net/ftp/ftp_directory_listing_parsers_unittest.cc @@ -91,6 +91,61 @@ TEST_F(FtpDirectoryListingParsersTest, Ls) { } } +TEST_F(FtpDirectoryListingParsersTest, Windows) { + base::Time::Exploded now_exploded; + base::Time::Now().LocalExplode(&now_exploded); + + const struct SingleLineTestData good_cases[] = { + { "11-02-09 05:32PM <DIR> NT", + net::FtpDirectoryListingEntry::DIRECTORY, "NT", -1, + 2009, 11, 2, 17, 32 }, + { "01-06-09 02:42PM 458 Readme.txt", + net::FtpDirectoryListingEntry::FILE, "Readme.txt", 458, + 2009, 1, 6, 14, 42 }, + { "01-06-09 02:42AM 1 Readme.txt", + net::FtpDirectoryListingEntry::FILE, "Readme.txt", 1, + 2009, 1, 6, 2, 42 }, + { "01-06-01 02:42AM 458 Readme.txt", + net::FtpDirectoryListingEntry::FILE, "Readme.txt", 458, + 2001, 1, 6, 2, 42 }, + { "01-06-00 02:42AM 458 Corner1.txt", + net::FtpDirectoryListingEntry::FILE, "Corner1.txt", 458, + 2000, 1, 6, 2, 42 }, + { "01-06-99 02:42AM 458 Corner2.txt", + net::FtpDirectoryListingEntry::FILE, "Corner2.txt", 458, + 1999, 1, 6, 2, 42 }, + { "01-06-80 02:42AM 458 Corner3.txt", + net::FtpDirectoryListingEntry::FILE, "Corner3.txt", 458, + 1980, 1, 6, 2, 42 }, + { "01-06-79 02:42AM 458 Corner4", + net::FtpDirectoryListingEntry::FILE, "Corner4", 458, + 2079, 1, 6, 2, 42 }, + { "01-06-1979 02:42AM 458 Readme.txt", + net::FtpDirectoryListingEntry::FILE, "Readme.txt", 458, + 1979, 1, 6, 2, 42 }, + }; + for (size_t i = 0; i < arraysize(good_cases); i++) { + SCOPED_TRACE(StringPrintf("Test[%d]: %s", i, good_cases[i].input)); + + net::FtpWindowsDirectoryListingParser parser; + RunSingleLineTestCase(&parser, good_cases[i]); + } + + const char* bad_cases[] = { + "", + "garbage", + "11-02-09 05:32PM <GARBAGE> NT", + "11-02-09 05:32 <DIR> NT", + "11-FEB-09 05:32PM <DIR> NT", + "11-02 05:32PM <DIR> NT", + "11-02-09 05:32PM -1 NT", + }; + for (size_t i = 0; i < arraysize(bad_cases); i++) { + net::FtpWindowsDirectoryListingParser parser; + EXPECT_FALSE(parser.ConsumeLine(UTF8ToUTF16(bad_cases[i]))) << bad_cases[i]; + } +} + TEST_F(FtpDirectoryListingParsersTest, Vms) { const struct SingleLineTestData good_cases[] = { { "README.TXT;4 2 18-APR-2000 10:40:39.90", |