1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/ftp/ftp_util.h" 6 7 #include <vector> 8 9 #include "base/logging.h" 10 #include "base/string_tokenizer.h" 11 #include "base/string_util.h" 12 #include "base/time.h" 13 14 // For examples of Unix<->VMS path conversions, see the unit test file. On VMS 15 // a path looks differently depending on whether it's a file or directory. 16 17 namespace net { 18 19 // static 20 std::string FtpUtil::UnixFilePathToVMS(const std::string& unix_path) { 21 if (unix_path.empty()) 22 return std::string(); 23 24 StringTokenizer tokenizer(unix_path, "/"); 25 std::vector<std::string> tokens; 26 while (tokenizer.GetNext()) 27 tokens.push_back(tokenizer.token()); 28 29 if (unix_path[0] == '/') { 30 // It's an absolute path. 31 32 if (tokens.empty()) { 33 DCHECK_EQ(1U, unix_path.length()); 34 return "[]"; 35 } 36 37 if (tokens.size() == 1) 38 return unix_path.substr(1); // Drop the leading slash. 39 40 std::string result(tokens[0] + ":["); 41 if (tokens.size() == 2) { 42 // Don't ask why, it just works that way on VMS. 43 result.append("000000"); 44 } else { 45 result.append(tokens[1]); 46 for (size_t i = 2; i < tokens.size() - 1; i++) 47 result.append("." + tokens[i]); 48 } 49 result.append("]" + tokens[tokens.size() - 1]); 50 return result; 51 } 52 53 if (tokens.size() == 1) 54 return unix_path; 55 56 std::string result("["); 57 for (size_t i = 0; i < tokens.size() - 1; i++) 58 result.append("." + tokens[i]); 59 result.append("]" + tokens[tokens.size() - 1]); 60 return result; 61 } 62 63 // static 64 std::string FtpUtil::UnixDirectoryPathToVMS(const std::string& unix_path) { 65 if (unix_path.empty()) 66 return std::string(); 67 68 std::string path(unix_path); 69 70 if (path[path.length() - 1] != '/') 71 path.append("/"); 72 73 // Reuse logic from UnixFilePathToVMS by appending a fake file name to the 74 // real path and removing it after conversion. 75 path.append("x"); 76 path = UnixFilePathToVMS(path); 77 return path.substr(0, path.length() - 1); 78 } 79 80 // static 81 std::string FtpUtil::VMSPathToUnix(const std::string& vms_path) { 82 if (vms_path.empty()) 83 return "."; 84 85 if (vms_path == "[]") 86 return "/"; 87 88 std::string result(vms_path); 89 if (vms_path[0] == '[') { 90 // It's a relative path. 91 ReplaceFirstSubstringAfterOffset(&result, 0, "[.", ""); 92 } else { 93 // It's an absolute path. 94 result.insert(0, "/"); 95 ReplaceSubstringsAfterOffset(&result, 0, ":[000000]", "/"); 96 ReplaceSubstringsAfterOffset(&result, 0, ":[", "/"); 97 } 98 std::replace(result.begin(), result.end(), '.', '/'); 99 std::replace(result.begin(), result.end(), ']', '/'); 100 101 // Make sure the result doesn't end with a slash. 102 if (result[result.length() - 1] == '/') 103 result = result.substr(0, result.length() - 1); 104 105 return result; 106 } 107 108 // static 109 bool FtpUtil::ThreeLetterMonthToNumber(const string16& text, int* number) { 110 const static char* months[] = { "jan", "feb", "mar", "apr", "may", "jun", 111 "jul", "aug", "sep", "oct", "nov", "dec" }; 112 113 for (size_t i = 0; i < arraysize(months); i++) { 114 if (LowerCaseEqualsASCII(text, months[i])) { 115 *number = i + 1; 116 return true; 117 } 118 } 119 120 // Special cases for directory listings in German (other three-letter month 121 // abbreviations are the same as in English). Note that we don't need to do 122 // a case-insensitive compare here. Only "ls -l" style listings may use 123 // localized month names, and they will always start capitalized. Also, 124 // converting non-ASCII characters to lowercase would be more complicated. 125 if (text == UTF8ToUTF16("M\xc3\xa4r")) { 126 // The full month name is M-(a-umlaut)-rz (March), which is M-(a-umlaut)r 127 // when abbreviated. 128 *number = 3; 129 return true; 130 } 131 if (text == ASCIIToUTF16("Mai")) { 132 *number = 5; 133 return true; 134 } 135 if (text == ASCIIToUTF16("Okt")) { 136 *number = 10; 137 return true; 138 } 139 if (text == ASCIIToUTF16("Dez")) { 140 *number = 12; 141 return true; 142 } 143 144 return false; 145 } 146 147 // static 148 bool FtpUtil::LsDateListingToTime(const string16& month, const string16& day, 149 const string16& rest, base::Time* time) { 150 base::Time::Exploded time_exploded = { 0 }; 151 152 if (!ThreeLetterMonthToNumber(month, &time_exploded.month)) 153 return false; 154 155 if (!StringToInt(day, &time_exploded.day_of_month)) 156 return false; 157 158 if (!StringToInt(rest, &time_exploded.year)) { 159 // Maybe it's time. Does it look like time (MM:HH)? 160 if (rest.length() != 5 || rest[2] != ':') 161 return false; 162 163 if (!StringToInt(rest.substr(0, 2), &time_exploded.hour)) 164 return false; 165 166 if (!StringToInt(rest.substr(3, 2), &time_exploded.minute)) 167 return false; 168 169 // Use current year. 170 base::Time::Exploded now_exploded; 171 base::Time::Now().LocalExplode(&now_exploded); 172 time_exploded.year = now_exploded.year; 173 } 174 175 // We don't know the time zone of the listing, so just use local time. 176 *time = base::Time::FromLocalExploded(time_exploded); 177 return true; 178 } 179 180 // static 181 string16 FtpUtil::GetStringPartAfterColumns(const string16& text, int columns) { 182 size_t pos = 0; 183 184 for (int i = 0; i < columns; i++) { 185 // Skip the leading whitespace. 186 while (pos < text.length() && isspace(text[pos])) 187 pos++; 188 189 // Skip the actual text of i-th column. 190 while (pos < text.length() && !isspace(text[pos])) 191 pos++; 192 } 193 194 string16 result(text.substr(pos)); 195 TrimWhitespace(result, TRIM_ALL, &result); 196 return result; 197 } 198 199 } // namespace 200