| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/ftp/ftp_directory_listing_parser_vms.h" | 5 #include "net/ftp/ftp_directory_listing_parser_vms.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/string_number_conversions.h" | 9 #include "base/string_number_conversions.h" |
| 10 #include "base/string_split.h" | 10 #include "base/string_split.h" |
| 11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 13 #include "net/ftp/ftp_util.h" | 13 #include "net/ftp/ftp_util.h" |
| 14 | 14 |
| 15 namespace { | 15 namespace { |
| 16 | 16 |
| 17 // Converts the filename component in listing to the filename we can display. | 17 // Converts the filename component in listing to the filename we can display. |
| 18 // Returns true on success. | 18 // Returns true on success. |
| 19 bool ParseVmsFilename(const string16& raw_filename, string16* parsed_filename, | 19 bool ParseVmsFilename(const string16& raw_filename, string16* parsed_filename, |
| 20 bool* is_directory) { | 20 bool* is_directory) { |
| 21 // On VMS, the files and directories are versioned. The version number is | 21 // On VMS, the files and directories are versioned. The version number is |
| 22 // separated from the file name by a semicolon. Example: ANNOUNCE.TXT;2. | 22 // separated from the file name by a semicolon. Example: ANNOUNCE.TXT;2. |
| 23 std::vector<string16> listing_parts; | 23 std::vector<string16> listing_parts; |
| 24 SplitString(raw_filename, ';', &listing_parts); | 24 base::SplitString(raw_filename, ';', &listing_parts); |
| 25 if (listing_parts.size() != 2) | 25 if (listing_parts.size() != 2) |
| 26 return false; | 26 return false; |
| 27 int version_number; | 27 int version_number; |
| 28 if (!base::StringToInt(listing_parts[1], &version_number)) | 28 if (!base::StringToInt(listing_parts[1], &version_number)) |
| 29 return false; | 29 return false; |
| 30 if (version_number < 0) | 30 if (version_number < 0) |
| 31 return false; | 31 return false; |
| 32 | 32 |
| 33 // Even directories have extensions in the listings. Don't display extensions | 33 // Even directories have extensions in the listings. Don't display extensions |
| 34 // for directories; it's awkward for non-VMS users. Also, VMS is | 34 // for directories; it's awkward for non-VMS users. Also, VMS is |
| 35 // case-insensitive, but generally uses uppercase characters. This may look | 35 // case-insensitive, but generally uses uppercase characters. This may look |
| 36 // awkward, so we convert them to lower case. | 36 // awkward, so we convert them to lower case. |
| 37 std::vector<string16> filename_parts; | 37 std::vector<string16> filename_parts; |
| 38 SplitString(listing_parts[0], '.', &filename_parts); | 38 base::SplitString(listing_parts[0], '.', &filename_parts); |
| 39 if (filename_parts.size() != 2) | 39 if (filename_parts.size() != 2) |
| 40 return false; | 40 return false; |
| 41 if (EqualsASCII(filename_parts[1], "DIR")) { | 41 if (EqualsASCII(filename_parts[1], "DIR")) { |
| 42 *parsed_filename = StringToLowerASCII(filename_parts[0]); | 42 *parsed_filename = StringToLowerASCII(filename_parts[0]); |
| 43 *is_directory = true; | 43 *is_directory = true; |
| 44 } else { | 44 } else { |
| 45 *parsed_filename = StringToLowerASCII(listing_parts[0]); | 45 *parsed_filename = StringToLowerASCII(listing_parts[0]); |
| 46 *is_directory = false; | 46 *is_directory = false; |
| 47 } | 47 } |
| 48 return true; | 48 return true; |
| 49 } | 49 } |
| 50 | 50 |
| 51 bool ParseVmsFilesize(const string16& input, int64* size) { | 51 bool ParseVmsFilesize(const string16& input, int64* size) { |
| 52 // VMS's directory listing gives us file size in blocks. We assume that | 52 // VMS's directory listing gives us file size in blocks. We assume that |
| 53 // the block size is 512 bytes. It doesn't give accurate file size, but is the | 53 // the block size is 512 bytes. It doesn't give accurate file size, but is the |
| 54 // best information we have. | 54 // best information we have. |
| 55 const int kBlockSize = 512; | 55 const int kBlockSize = 512; |
| 56 | 56 |
| 57 if (base::StringToInt64(input, size)) { | 57 if (base::StringToInt64(input, size)) { |
| 58 *size *= kBlockSize; | 58 *size *= kBlockSize; |
| 59 return true; | 59 return true; |
| 60 } | 60 } |
| 61 | 61 |
| 62 std::vector<string16> parts; | 62 std::vector<string16> parts; |
| 63 SplitString(input, '/', &parts); | 63 base::SplitString(input, '/', &parts); |
| 64 if (parts.size() != 2) | 64 if (parts.size() != 2) |
| 65 return false; | 65 return false; |
| 66 | 66 |
| 67 int64 blocks_used, blocks_allocated; | 67 int64 blocks_used, blocks_allocated; |
| 68 if (!base::StringToInt64(parts[0], &blocks_used)) | 68 if (!base::StringToInt64(parts[0], &blocks_used)) |
| 69 return false; | 69 return false; |
| 70 if (!base::StringToInt64(parts[1], &blocks_allocated)) | 70 if (!base::StringToInt64(parts[1], &blocks_allocated)) |
| 71 return false; | 71 return false; |
| 72 if (blocks_used > blocks_allocated) | 72 if (blocks_used > blocks_allocated) |
| 73 return false; | 73 return false; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 94 | 94 |
| 95 bool LooksLikeVmsFileProtectionListing(const string16& input) { | 95 bool LooksLikeVmsFileProtectionListing(const string16& input) { |
| 96 if (input.length() < 2) | 96 if (input.length() < 2) |
| 97 return false; | 97 return false; |
| 98 if (input[0] != '(' || input[input.length() - 1] != ')') | 98 if (input[0] != '(' || input[input.length() - 1] != ')') |
| 99 return false; | 99 return false; |
| 100 | 100 |
| 101 // We expect four parts of the file protection listing: for System, Owner, | 101 // We expect four parts of the file protection listing: for System, Owner, |
| 102 // Group, and World. | 102 // Group, and World. |
| 103 std::vector<string16> parts; | 103 std::vector<string16> parts; |
| 104 SplitString(input.substr(1, input.length() - 2), ',', &parts); | 104 base::SplitString(input.substr(1, input.length() - 2), ',', &parts); |
| 105 if (parts.size() != 4) | 105 if (parts.size() != 4) |
| 106 return false; | 106 return false; |
| 107 | 107 |
| 108 return LooksLikeVmsFileProtectionListingPart(parts[0]) && | 108 return LooksLikeVmsFileProtectionListingPart(parts[0]) && |
| 109 LooksLikeVmsFileProtectionListingPart(parts[1]) && | 109 LooksLikeVmsFileProtectionListingPart(parts[1]) && |
| 110 LooksLikeVmsFileProtectionListingPart(parts[2]) && | 110 LooksLikeVmsFileProtectionListingPart(parts[2]) && |
| 111 LooksLikeVmsFileProtectionListingPart(parts[3]); | 111 LooksLikeVmsFileProtectionListingPart(parts[3]); |
| 112 } | 112 } |
| 113 | 113 |
| 114 bool LooksLikeVmsUserIdentificationCode(const string16& input) { | 114 bool LooksLikeVmsUserIdentificationCode(const string16& input) { |
| 115 if (input.length() < 2) | 115 if (input.length() < 2) |
| 116 return false; | 116 return false; |
| 117 return input[0] == '[' && input[input.length() - 1] == ']'; | 117 return input[0] == '[' && input[input.length() - 1] == ']'; |
| 118 } | 118 } |
| 119 | 119 |
| 120 bool VmsDateListingToTime(const std::vector<string16>& columns, | 120 bool VmsDateListingToTime(const std::vector<string16>& columns, |
| 121 base::Time* time) { | 121 base::Time* time) { |
| 122 DCHECK_EQ(3U, columns.size()); | 122 DCHECK_EQ(3U, columns.size()); |
| 123 | 123 |
| 124 base::Time::Exploded time_exploded = { 0 }; | 124 base::Time::Exploded time_exploded = { 0 }; |
| 125 | 125 |
| 126 // Date should be in format DD-MMM-YYYY. | 126 // Date should be in format DD-MMM-YYYY. |
| 127 std::vector<string16> date_parts; | 127 std::vector<string16> date_parts; |
| 128 SplitString(columns[1], '-', &date_parts); | 128 base::SplitString(columns[1], '-', &date_parts); |
| 129 if (date_parts.size() != 3) | 129 if (date_parts.size() != 3) |
| 130 return false; | 130 return false; |
| 131 if (!base::StringToInt(date_parts[0], &time_exploded.day_of_month)) | 131 if (!base::StringToInt(date_parts[0], &time_exploded.day_of_month)) |
| 132 return false; | 132 return false; |
| 133 if (!net::FtpUtil::ThreeLetterMonthToNumber(date_parts[1], | 133 if (!net::FtpUtil::ThreeLetterMonthToNumber(date_parts[1], |
| 134 &time_exploded.month)) | 134 &time_exploded.month)) |
| 135 return false; | 135 return false; |
| 136 if (!base::StringToInt(date_parts[2], &time_exploded.year)) | 136 if (!base::StringToInt(date_parts[2], &time_exploded.year)) |
| 137 return false; | 137 return false; |
| 138 | 138 |
| 139 // Time can be in format HH:MM, HH:MM:SS, or HH:MM:SS.mm. Try to recognize the | 139 // Time can be in format HH:MM, HH:MM:SS, or HH:MM:SS.mm. Try to recognize the |
| 140 // last type first. Do not parse the seconds, they will be ignored anyway. | 140 // last type first. Do not parse the seconds, they will be ignored anyway. |
| 141 string16 time_column(columns[2]); | 141 string16 time_column(columns[2]); |
| 142 if (time_column.length() == 11 && time_column[8] == '.') | 142 if (time_column.length() == 11 && time_column[8] == '.') |
| 143 time_column = time_column.substr(0, 8); | 143 time_column = time_column.substr(0, 8); |
| 144 if (time_column.length() == 8 && time_column[5] == ':') | 144 if (time_column.length() == 8 && time_column[5] == ':') |
| 145 time_column = time_column.substr(0, 5); | 145 time_column = time_column.substr(0, 5); |
| 146 if (time_column.length() != 5) | 146 if (time_column.length() != 5) |
| 147 return false; | 147 return false; |
| 148 std::vector<string16> time_parts; | 148 std::vector<string16> time_parts; |
| 149 SplitString(time_column, ':', &time_parts); | 149 base::SplitString(time_column, ':', &time_parts); |
| 150 if (time_parts.size() != 2) | 150 if (time_parts.size() != 2) |
| 151 return false; | 151 return false; |
| 152 if (!base::StringToInt(time_parts[0], &time_exploded.hour)) | 152 if (!base::StringToInt(time_parts[0], &time_exploded.hour)) |
| 153 return false; | 153 return false; |
| 154 if (!base::StringToInt(time_parts[1], &time_exploded.minute)) | 154 if (!base::StringToInt(time_parts[1], &time_exploded.minute)) |
| 155 return false; | 155 return false; |
| 156 | 156 |
| 157 // We don't know the time zone of the server, so just use local time. | 157 // We don't know the time zone of the server, so just use local time. |
| 158 *time = base::Time::FromLocalExploded(time_exploded); | 158 *time = base::Time::FromLocalExploded(time_exploded); |
| 159 return true; | 159 return true; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 } | 222 } |
| 223 | 223 |
| 224 FtpDirectoryListingEntry FtpDirectoryListingParserVms::PopEntry() { | 224 FtpDirectoryListingEntry FtpDirectoryListingParserVms::PopEntry() { |
| 225 FtpDirectoryListingEntry entry = entries_.front(); | 225 FtpDirectoryListingEntry entry = entries_.front(); |
| 226 entries_.pop(); | 226 entries_.pop(); |
| 227 return entry; | 227 return entry; |
| 228 } | 228 } |
| 229 | 229 |
| 230 bool FtpDirectoryListingParserVms::ConsumeEntryLine(const string16& line) { | 230 bool FtpDirectoryListingParserVms::ConsumeEntryLine(const string16& line) { |
| 231 std::vector<string16> columns; | 231 std::vector<string16> columns; |
| 232 SplitString(CollapseWhitespace(line, false), ' ', &columns); | 232 base::SplitString(CollapseWhitespace(line, false), ' ', &columns); |
| 233 | 233 |
| 234 if (columns.size() == 1) { | 234 if (columns.size() == 1) { |
| 235 if (!last_filename_.empty()) | 235 if (!last_filename_.empty()) |
| 236 return false; | 236 return false; |
| 237 return ParseVmsFilename(columns[0], &last_filename_, &last_is_directory_); | 237 return ParseVmsFilename(columns[0], &last_filename_, &last_is_directory_); |
| 238 } | 238 } |
| 239 | 239 |
| 240 // Recognize listing entries which generate "access denied" message even when | 240 // Recognize listing entries which generate "access denied" message even when |
| 241 // trying to list them. We don't display them in the final listing. | 241 // trying to list them. We don't display them in the final listing. |
| 242 static const char* kAccessDeniedMessages[] = { | 242 static const char* kAccessDeniedMessages[] = { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 if (entry.type != FtpDirectoryListingEntry::FILE) | 289 if (entry.type != FtpDirectoryListingEntry::FILE) |
| 290 entry.size = -1; | 290 entry.size = -1; |
| 291 if (!VmsDateListingToTime(columns, &entry.last_modified)) | 291 if (!VmsDateListingToTime(columns, &entry.last_modified)) |
| 292 return false; | 292 return false; |
| 293 | 293 |
| 294 entries_.push(entry); | 294 entries_.push(entry); |
| 295 return true; | 295 return true; |
| 296 } | 296 } |
| 297 | 297 |
| 298 } // namespace net | 298 } // namespace net |
| OLD | NEW |