Home | History | Annotate | Download | only in ftp
      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