This source file includes following definitions.
- UnixFilePathToVMS
- UnixDirectoryPathToVMS
- VMSPathToUnix
- GetInstance
- GetMonthNumber
- AbbreviatedMonthToNumber
- LsDateListingToTime
- WindowsDateListingToTime
- GetStringPartAfterColumns
#include "net/ftp/ftp_util.h"
#include <map>
#include <vector>
#include "base/i18n/case_conversion.h"
#include "base/i18n/char_iterator.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "third_party/icu/source/common/unicode/uchar.h"
#include "third_party/icu/source/i18n/unicode/datefmt.h"
#include "third_party/icu/source/i18n/unicode/dtfmtsym.h"
using base::ASCIIToUTF16;
using base::StringPiece16;
namespace net {
std::string FtpUtil::UnixFilePathToVMS(const std::string& unix_path) {
if (unix_path.empty())
return std::string();
base::StringTokenizer tokenizer(unix_path, "/");
std::vector<std::string> tokens;
while (tokenizer.GetNext())
tokens.push_back(tokenizer.token());
if (unix_path[0] == '/') {
if (tokens.empty()) {
DCHECK_EQ(1U, unix_path.length());
return "[]";
}
if (tokens.size() == 1)
return unix_path.substr(1);
std::string result(tokens[0] + ":[");
if (tokens.size() == 2) {
result.append("000000");
} else {
result.append(tokens[1]);
for (size_t i = 2; i < tokens.size() - 1; i++)
result.append("." + tokens[i]);
}
result.append("]" + tokens[tokens.size() - 1]);
return result;
}
if (tokens.size() == 1)
return unix_path;
std::string result("[");
for (size_t i = 0; i < tokens.size() - 1; i++)
result.append("." + tokens[i]);
result.append("]" + tokens[tokens.size() - 1]);
return result;
}
std::string FtpUtil::UnixDirectoryPathToVMS(const std::string& unix_path) {
if (unix_path.empty())
return std::string();
std::string path(unix_path);
if (path[path.length() - 1] != '/')
path.append("/");
path.append("x");
path = UnixFilePathToVMS(path);
return path.substr(0, path.length() - 1);
}
std::string FtpUtil::VMSPathToUnix(const std::string& vms_path) {
if (vms_path.empty())
return ".";
if (vms_path[0] == '/') {
return vms_path;
}
if (vms_path == "[]")
return "/";
std::string result(vms_path);
if (vms_path[0] == '[') {
ReplaceFirstSubstringAfterOffset(&result, 0, "[.", std::string());
} else {
result.insert(0, "/");
ReplaceSubstringsAfterOffset(&result, 0, ":[000000]", "/");
ReplaceSubstringsAfterOffset(&result, 0, ":[", "/");
}
std::replace(result.begin(), result.end(), '.', '/');
std::replace(result.begin(), result.end(), ']', '/');
if (result.length() && result[result.length() - 1] == '/')
result = result.substr(0, result.length() - 1);
return result;
}
namespace {
class AbbreviatedMonthsMap {
public:
static AbbreviatedMonthsMap* GetInstance() {
return Singleton<AbbreviatedMonthsMap>::get();
}
bool GetMonthNumber(const base::string16& text, int* number) {
base::string16 text_lower(base::i18n::ToLower(text));
if (map_.find(text_lower) == map_.end())
return false;
*number = map_[text_lower];
return true;
}
private:
friend struct DefaultSingletonTraits<AbbreviatedMonthsMap>;
AbbreviatedMonthsMap() {
int32_t locales_count;
const icu::Locale* locales =
icu::DateFormat::getAvailableLocales(locales_count);
for (int32_t locale = 0; locale < locales_count; locale++) {
UErrorCode status(U_ZERO_ERROR);
icu::DateFormatSymbols format_symbols(locales[locale], status);
if (U_FAILURE(status))
continue;
int32_t months_count;
const icu::UnicodeString* months =
format_symbols.getShortMonths(months_count);
for (int32_t month = 0; month < months_count; month++) {
base::string16 month_name(months[month].getBuffer(),
static_cast<size_t>(months[month].length()));
month_name = base::i18n::ToLower(month_name);
map_[month_name] = month + 1;
map_[month_name.substr(0, 3)] = month + 1;
}
}
CHECK_EQ(1, map_[ASCIIToUTF16("jan")]);
CHECK_EQ(2, map_[ASCIIToUTF16("feb")]);
CHECK_EQ(3, map_[ASCIIToUTF16("mar")]);
CHECK_EQ(4, map_[ASCIIToUTF16("apr")]);
CHECK_EQ(5, map_[ASCIIToUTF16("may")]);
CHECK_EQ(6, map_[ASCIIToUTF16("jun")]);
CHECK_EQ(7, map_[ASCIIToUTF16("jul")]);
CHECK_EQ(8, map_[ASCIIToUTF16("aug")]);
CHECK_EQ(9, map_[ASCIIToUTF16("sep")]);
CHECK_EQ(10, map_[ASCIIToUTF16("oct")]);
CHECK_EQ(11, map_[ASCIIToUTF16("nov")]);
CHECK_EQ(12, map_[ASCIIToUTF16("dec")]);
}
std::map<base::string16, int> map_;
DISALLOW_COPY_AND_ASSIGN(AbbreviatedMonthsMap);
};
}
bool FtpUtil::AbbreviatedMonthToNumber(const base::string16& text,
int* number) {
return AbbreviatedMonthsMap::GetInstance()->GetMonthNumber(text, number);
}
bool FtpUtil::LsDateListingToTime(const base::string16& month,
const base::string16& day,
const base::string16& rest,
const base::Time& current_time,
base::Time* result) {
base::Time::Exploded time_exploded = { 0 };
if (!AbbreviatedMonthToNumber(month, &time_exploded.month)) {
if (month.length() < 3 ||
!AbbreviatedMonthToNumber(month.substr(month.length() - 3),
&time_exploded.month)) {
return false;
}
}
if (!base::StringToInt(day, &time_exploded.day_of_month))
return false;
if (time_exploded.day_of_month > 31)
return false;
if (!base::StringToInt(rest, &time_exploded.year)) {
if (rest.length() > 5)
return false;
size_t colon_pos = rest.find(':');
if (colon_pos == base::string16::npos)
return false;
if (colon_pos > 2)
return false;
if (!base::StringToInt(
StringPiece16(rest.begin(), rest.begin() + colon_pos),
&time_exploded.hour)) {
return false;
}
if (!base::StringToInt(
StringPiece16(rest.begin() + colon_pos + 1, rest.end()),
&time_exploded.minute)) {
return false;
}
base::Time::Exploded current_exploded;
current_time.LocalExplode(¤t_exploded);
if (time_exploded.month > current_exploded.month ||
(time_exploded.month == current_exploded.month &&
time_exploded.day_of_month > current_exploded.day_of_month)) {
time_exploded.year = current_exploded.year - 1;
} else {
time_exploded.year = current_exploded.year;
}
}
*result = base::Time::FromLocalExploded(time_exploded);
return true;
}
bool FtpUtil::WindowsDateListingToTime(const base::string16& date,
const base::string16& time,
base::Time* result) {
base::Time::Exploded time_exploded = { 0 };
std::vector<base::string16> date_parts;
base::SplitString(date, '-', &date_parts);
if (date_parts.size() != 3)
return false;
if (!base::StringToInt(date_parts[0], &time_exploded.month))
return false;
if (!base::StringToInt(date_parts[1], &time_exploded.day_of_month))
return false;
if (!base::StringToInt(date_parts[2], &time_exploded.year))
return false;
if (time_exploded.year < 0)
return false;
if (time_exploded.year < 80)
time_exploded.year += 2000;
else if (time_exploded.year < 100)
time_exploded.year += 1900;
if (time.length() < 5)
return false;
std::vector<base::string16> time_parts;
base::SplitString(time.substr(0, 5), ':', &time_parts);
if (time_parts.size() != 2)
return false;
if (!base::StringToInt(time_parts[0], &time_exploded.hour))
return false;
if (!base::StringToInt(time_parts[1], &time_exploded.minute))
return false;
if (!time_exploded.HasValidValues())
return false;
if (time.length() > 5) {
if (time.length() != 7)
return false;
base::string16 am_or_pm(time.substr(5, 2));
if (EqualsASCII(am_or_pm, "PM")) {
if (time_exploded.hour < 12)
time_exploded.hour += 12;
} else if (EqualsASCII(am_or_pm, "AM")) {
if (time_exploded.hour == 12)
time_exploded.hour = 0;
} else {
return false;
}
}
*result = base::Time::FromLocalExploded(time_exploded);
return true;
}
base::string16 FtpUtil::GetStringPartAfterColumns(const base::string16& text,
int columns) {
base::i18n::UTF16CharIterator iter(&text);
for (int i = 0; i < columns; i++) {
while (!iter.end() && u_isspace(iter.get()))
iter.Advance();
while (!iter.end() && !u_isspace(iter.get()))
iter.Advance();
}
base::string16 result(text.substr(iter.array_pos()));
base::TrimWhitespace(result, base::TRIM_ALL, &result);
return result;
}
}