blob: 2ff3cd2a82dc32f2a3dc550c3a4af305d7d002cd [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/ftp/ftp_directory_listing_parser_windows.h"
#include <vector>
#include "base/string_number_conversions.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "net/ftp/ftp_util.h"
namespace {
bool WindowsDateListingToTime(const std::vector<string16>& columns,
base::Time* time) {
DCHECK_LE(4U, columns.size());
base::Time::Exploded time_exploded = { 0 };
// Date should be in format MM-DD-YY[YY].
std::vector<string16> date_parts;
SplitString(columns[0], '-', &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 year has only two digits then assume that 00-79 is 2000-2079,
// and 80-99 is 1980-1999.
if (time_exploded.year < 80)
time_exploded.year += 2000;
else if (time_exploded.year < 100)
time_exploded.year += 1900;
// Time should be in format HH:MM(AM|PM)
if (columns[1].length() != 7)
return false;
std::vector<string16> time_parts;
SplitString(columns[1].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;
string16 am_or_pm(columns[1].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;
}
// We don't know the time zone of the server, so just use local time.
*time = base::Time::FromLocalExploded(time_exploded);
return true;
}
} // namespace
namespace net {
FtpDirectoryListingParserWindows::FtpDirectoryListingParserWindows() {
}
bool FtpDirectoryListingParserWindows::ConsumeLine(const string16& line) {
std::vector<string16> columns;
SplitString(CollapseWhitespace(line, false), ' ', &columns);
// We may receive file names containing spaces, which can make the number of
// columns arbitrarily large. We will handle that later. For now just make
// sure we have all the columns that should normally be there.
if (columns.size() < 4)
return false;
FtpDirectoryListingEntry entry;
entry.name = FtpUtil::GetStringPartAfterColumns(line, 3);
if (EqualsASCII(columns[2], "<DIR>")) {
entry.type = FtpDirectoryListingEntry::DIRECTORY;
entry.size = -1;
} else {
entry.type = FtpDirectoryListingEntry::FILE;
if (!base::StringToInt64(columns[2], &entry.size))
return false;
if (entry.size < 0)
return false;
}
if (!WindowsDateListingToTime(columns, &entry.last_modified))
return false;
entries_.push(entry);
return true;
}
bool FtpDirectoryListingParserWindows::OnEndOfInput() {
return true;
}
bool FtpDirectoryListingParserWindows::EntryAvailable() const {
return !entries_.empty();
}
FtpDirectoryListingEntry FtpDirectoryListingParserWindows::PopEntry() {
FtpDirectoryListingEntry entry = entries_.front();
entries_.pop();
return entry;
}
} // namespace net