1// Copyright (c) 2009 The Chromium Authors. All rights reserved.  Use of this
2// source code is governed by a BSD-style license that can be found in the
3// LICENSE file.
4
5#include "net/ftp/ftp_directory_listing_parser_windows.h"
6
7#include <vector>
8
9#include "base/string_util.h"
10#include "net/ftp/ftp_util.h"
11
12namespace {
13
14bool WindowsDateListingToTime(const std::vector<string16>& columns,
15                              base::Time* time) {
16  DCHECK_LE(4U, columns.size());
17
18  base::Time::Exploded time_exploded = { 0 };
19
20  // Date should be in format MM-DD-YY[YY].
21  std::vector<string16> date_parts;
22  SplitString(columns[0], '-', &date_parts);
23  if (date_parts.size() != 3)
24    return false;
25  if (!StringToInt(date_parts[0], &time_exploded.month))
26    return false;
27  if (!StringToInt(date_parts[1], &time_exploded.day_of_month))
28    return false;
29  if (!StringToInt(date_parts[2], &time_exploded.year))
30    return false;
31  if (time_exploded.year < 0)
32    return false;
33  // If year has only two digits then assume that 00-79 is 2000-2079,
34  // and 80-99 is 1980-1999.
35  if (time_exploded.year < 80)
36    time_exploded.year += 2000;
37  else if (time_exploded.year < 100)
38    time_exploded.year += 1900;
39
40  // Time should be in format HH:MM(AM|PM)
41  if (columns[1].length() != 7)
42    return false;
43  std::vector<string16> time_parts;
44  SplitString(columns[1].substr(0, 5), ':', &time_parts);
45  if (time_parts.size() != 2)
46    return false;
47  if (!StringToInt(time_parts[0], &time_exploded.hour))
48    return false;
49  if (!StringToInt(time_parts[1], &time_exploded.minute))
50    return false;
51  string16 am_or_pm(columns[1].substr(5, 2));
52  if (EqualsASCII(am_or_pm, "PM"))
53    time_exploded.hour += 12;
54  else if (!EqualsASCII(am_or_pm, "AM"))
55    return false;
56
57  // We don't know the time zone of the server, so just use local time.
58  *time = base::Time::FromLocalExploded(time_exploded);
59  return true;
60}
61
62}  // namespace
63
64namespace net {
65
66FtpDirectoryListingParserWindows::FtpDirectoryListingParserWindows() {
67}
68
69bool FtpDirectoryListingParserWindows::ConsumeLine(const string16& line) {
70  std::vector<string16> columns;
71  SplitString(CollapseWhitespace(line, false), ' ', &columns);
72
73  // We may receive file names containing spaces, which can make the number of
74  // columns arbitrarily large. We will handle that later. For now just make
75  // sure we have all the columns that should normally be there.
76  if (columns.size() < 4)
77    return false;
78
79  FtpDirectoryListingEntry entry;
80  entry.name = FtpUtil::GetStringPartAfterColumns(line, 3);
81
82  if (EqualsASCII(columns[2], "<DIR>")) {
83    entry.type = FtpDirectoryListingEntry::DIRECTORY;
84    entry.size = -1;
85  } else {
86    entry.type = FtpDirectoryListingEntry::FILE;
87    if (!StringToInt64(columns[2], &entry.size))
88      return false;
89    if (entry.size < 0)
90      return false;
91  }
92
93  if (!WindowsDateListingToTime(columns, &entry.last_modified))
94    return false;
95
96  entries_.push(entry);
97  return true;
98}
99
100bool FtpDirectoryListingParserWindows::OnEndOfInput() {
101  return true;
102}
103
104bool FtpDirectoryListingParserWindows::EntryAvailable() const {
105  return !entries_.empty();
106}
107
108FtpDirectoryListingEntry FtpDirectoryListingParserWindows::PopEntry() {
109  FtpDirectoryListingEntry entry = entries_.front();
110  entries_.pop();
111  return entry;
112}
113
114}  // namespace net
115