| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this |
| 2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
| 3 // LICENSE file. | 3 // LICENSE file. |
| 4 | 4 |
| 5 #include "net/ftp/ftp_directory_listing_parser_ls.h" | 5 #include "net/ftp/ftp_directory_listing_parser_ls.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "net/ftp/ftp_util.h" | 10 #include "net/ftp/ftp_util.h" |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 last = i; | 50 last = i; |
| 51 if (++columns_so_far == columns) | 51 if (++columns_so_far == columns) |
| 52 break; | 52 break; |
| 53 } | 53 } |
| 54 } | 54 } |
| 55 string16 result(text.substr(last)); | 55 string16 result(text.substr(last)); |
| 56 TrimWhitespace(result, TRIM_ALL, &result); | 56 TrimWhitespace(result, TRIM_ALL, &result); |
| 57 return result; | 57 return result; |
| 58 } | 58 } |
| 59 | 59 |
| 60 bool DetectColumnOffset(const std::vector<string16>& columns, int* offset) { |
| 61 base::Time time; |
| 62 |
| 63 if (columns.size() >= 8 && |
| 64 net::FtpUtil::LsDateListingToTime(columns[5], columns[6], columns[7], |
| 65 &time)) { |
| 66 // Standard listing, exactly like ls -l. |
| 67 *offset = 1; |
| 68 return true; |
| 69 } |
| 70 |
| 71 if (columns.size() >= 7 && |
| 72 net::FtpUtil::LsDateListingToTime(columns[4], columns[5], columns[6], |
| 73 &time)) { |
| 74 // wu-ftpd listing, no "number of links" column. |
| 75 *offset = 0; |
| 76 return true; |
| 77 } |
| 78 |
| 79 // Unrecognized listing style. |
| 80 return false; |
| 81 } |
| 82 |
| 60 } // namespace | 83 } // namespace |
| 61 | 84 |
| 62 namespace net { | 85 namespace net { |
| 63 | 86 |
| 64 FtpDirectoryListingParserLs::FtpDirectoryListingParserLs() | 87 FtpDirectoryListingParserLs::FtpDirectoryListingParserLs() |
| 65 : received_nonempty_line_(false), | 88 : received_nonempty_line_(false), |
| 66 received_total_line_(false) { | 89 received_total_line_(false), |
| 90 column_offset_(-1) { |
| 67 } | 91 } |
| 68 | 92 |
| 69 bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) { | 93 bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) { |
| 94 std::vector<string16> columns; |
| 95 SplitString(CollapseWhitespace(line, false), ' ', &columns); |
| 96 |
| 70 if (line.empty() && !received_nonempty_line_) { | 97 if (line.empty() && !received_nonempty_line_) { |
| 71 // Allow empty lines only at the beginning of the listing. For example VMS | 98 // Allow empty lines only at the beginning of the listing. For example VMS |
| 72 // systems in Unix emulation mode add an empty line before the first listing | 99 // systems in Unix emulation mode add an empty line before the first listing |
| 73 // entry. | 100 // entry. |
| 74 return true; | 101 return true; |
| 75 } | 102 } |
| 76 received_nonempty_line_ = true; | |
| 77 | |
| 78 std::vector<string16> columns; | |
| 79 SplitString(CollapseWhitespace(line, false), ' ', &columns); | |
| 80 | |
| 81 // Some FTP servers put a "total n" line at the beginning of the listing | 103 // Some FTP servers put a "total n" line at the beginning of the listing |
| 82 // (n is an integer). Allow such a line, but only once, and only if it's | 104 // (n is an integer). Allow such a line, but only once, and only if it's |
| 83 // the first non-empty line. Do not match the word exactly, because it may be | 105 // the first non-empty line. Do not match the word exactly, because it may be |
| 84 // in different languages (at least English and German have been seen in the | 106 // in different languages (at least English and German have been seen in the |
| 85 // field). | 107 // field). |
| 86 if (columns.size() == 2 && !received_total_line_) { | 108 if (columns.size() == 2 && !received_total_line_) { |
| 87 received_total_line_ = true; | 109 received_total_line_ = true; |
| 88 | 110 |
| 89 int total_number; | 111 int total_number; |
| 90 if (!StringToInt(columns[1], &total_number)) | 112 if (!StringToInt(columns[1], &total_number)) |
| 91 return false; | 113 return false; |
| 92 if (total_number < 0) | 114 if (total_number < 0) |
| 93 return false; | 115 return false; |
| 94 | 116 |
| 95 return true; | 117 return true; |
| 96 } | 118 } |
| 119 if (!received_nonempty_line_ && !DetectColumnOffset(columns, &column_offset_)) |
| 120 return false; |
| 121 received_nonempty_line_ = true; |
| 97 | 122 |
| 98 // We may receive file names containing spaces, which can make the number of | 123 // We may receive file names containing spaces, which can make the number of |
| 99 // columns arbitrarily large. We will handle that later. For now just make | 124 // columns arbitrarily large. We will handle that later. For now just make |
| 100 // sure we have all the columns that should normally be there. | 125 // sure we have all the columns that should normally be there. |
| 101 if (columns.size() < 9) | 126 if (columns.size() < 8U + column_offset_) |
| 102 return false; | 127 return false; |
| 103 | 128 |
| 104 if (!LooksLikeUnixPermissionsListing(columns[0])) | 129 if (!LooksLikeUnixPermissionsListing(columns[0])) |
| 105 return false; | 130 return false; |
| 106 | 131 |
| 107 FtpDirectoryListingEntry entry; | 132 FtpDirectoryListingEntry entry; |
| 108 if (columns[0][0] == 'l') { | 133 if (columns[0][0] == 'l') { |
| 109 entry.type = FtpDirectoryListingEntry::SYMLINK; | 134 entry.type = FtpDirectoryListingEntry::SYMLINK; |
| 110 } else if (columns[0][0] == 'd') { | 135 } else if (columns[0][0] == 'd') { |
| 111 entry.type = FtpDirectoryListingEntry::DIRECTORY; | 136 entry.type = FtpDirectoryListingEntry::DIRECTORY; |
| 112 } else { | 137 } else { |
| 113 entry.type = FtpDirectoryListingEntry::FILE; | 138 entry.type = FtpDirectoryListingEntry::FILE; |
| 114 } | 139 } |
| 115 | 140 |
| 116 int number_of_links; | 141 if (!StringToInt64(columns[3 + column_offset_], &entry.size)) |
| 117 if (!StringToInt(columns[1], &number_of_links)) | |
| 118 return false; | |
| 119 if (number_of_links < 0) | |
| 120 return false; | |
| 121 | |
| 122 if (!StringToInt64(columns[4], &entry.size)) | |
| 123 return false; | 142 return false; |
| 124 if (entry.size < 0) | 143 if (entry.size < 0) |
| 125 return false; | 144 return false; |
| 126 if (entry.type != FtpDirectoryListingEntry::FILE) | 145 if (entry.type != FtpDirectoryListingEntry::FILE) |
| 127 entry.size = -1; | 146 entry.size = -1; |
| 128 | 147 |
| 129 if (!FtpUtil::LsDateListingToTime(columns[5], columns[6], columns[7], | 148 if (!FtpUtil::LsDateListingToTime(columns[4 + column_offset_], |
| 149 columns[5 + column_offset_], |
| 150 columns[6 + column_offset_], |
| 130 &entry.last_modified)) { | 151 &entry.last_modified)) { |
| 131 return false; | 152 return false; |
| 132 } | 153 } |
| 133 | 154 |
| 134 entry.name = GetStringPartAfterColumns(line, 8); | 155 entry.name = GetStringPartAfterColumns(line, 7 + column_offset_); |
| 135 if (entry.type == FtpDirectoryListingEntry::SYMLINK) { | 156 if (entry.type == FtpDirectoryListingEntry::SYMLINK) { |
| 136 string16::size_type pos = entry.name.rfind(ASCIIToUTF16(" -> ")); | 157 string16::size_type pos = entry.name.rfind(ASCIIToUTF16(" -> ")); |
| 137 if (pos == string16::npos) | 158 if (pos == string16::npos) |
| 138 return false; | 159 return false; |
| 139 entry.name = entry.name.substr(0, pos); | 160 entry.name = entry.name.substr(0, pos); |
| 140 } | 161 } |
| 141 | 162 |
| 142 entries_.push(entry); | 163 entries_.push(entry); |
| 143 return true; | 164 return true; |
| 144 } | 165 } |
| 145 | 166 |
| 146 bool FtpDirectoryListingParserLs::OnEndOfInput() { | 167 bool FtpDirectoryListingParserLs::OnEndOfInput() { |
| 147 return true; | 168 return true; |
| 148 } | 169 } |
| 149 | 170 |
| 150 bool FtpDirectoryListingParserLs::EntryAvailable() const { | 171 bool FtpDirectoryListingParserLs::EntryAvailable() const { |
| 151 return !entries_.empty(); | 172 return !entries_.empty(); |
| 152 } | 173 } |
| 153 | 174 |
| 154 FtpDirectoryListingEntry FtpDirectoryListingParserLs::PopEntry() { | 175 FtpDirectoryListingEntry FtpDirectoryListingParserLs::PopEntry() { |
| 155 FtpDirectoryListingEntry entry = entries_.front(); | 176 FtpDirectoryListingEntry entry = entries_.front(); |
| 156 entries_.pop(); | 177 entries_.pop(); |
| 157 return entry; | 178 return entry; |
| 158 } | 179 } |
| 159 | 180 |
| 160 } // namespace net | 181 } // namespace net |
| OLD | NEW |