blob: b3ea46bf65076a6f5f836e718b58a6081d9af5f4 [file] [log] [blame]
// Copyright 2014 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 "components/password_manager/core/browser/export/csv_writer.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
namespace {
// Encapsulates formatting and outputting values to a CSV file row by row. Takes
// care of escaping and adding the appropriate separators.
class CSVFormatter {
public:
explicit CSVFormatter(std::string* output)
: output_(output), at_beginning_of_line_(true) {}
// Escapes the |raw_value| if needed, adds a field separator unless we are at
// the beginning of a line, and appends the escaped value to |output_|.
void AppendValue(const std::string& raw_value);
// Appends the platform-specific EOL terminator to |output_|.
void EndLine();
private:
std::string* output_;
bool at_beginning_of_line_;
};
void CSVFormatter::AppendValue(const std::string& raw_value) {
// Append the field separator unless this is the first field on the line.
if (!at_beginning_of_line_)
output_->push_back(',');
at_beginning_of_line_ = false;
// Fields containing line breaks (CRLF), double quotes, and commas should be
// enclosed in double-quotes. If double-quotes are used to enclose fields,
// then double-quotes appearing inside a field must be escaped by preceding
// them with another double quote.
if (raw_value.find_first_of("\r\n\",") != std::string::npos) {
output_->push_back('\"');
output_->append(raw_value);
base::ReplaceSubstringsAfterOffset(
output_, output_->size() - raw_value.size(), "\"", "\"\"");
output_->push_back('\"');
} else {
output_->append(raw_value);
}
}
void CSVFormatter::EndLine() {
#if defined(OS_WIN)
const char kLineEnding[] = "\r\n";
#else
const char kLineEnding[] = "\n";
#endif
output_->append(kLineEnding);
at_beginning_of_line_ = true;
}
} // namespace
namespace password_manager {
void WriteCSV(const std::vector<std::string>& column_names,
const std::vector<std::map<std::string, std::string>>& records,
std::string* csv) {
DCHECK(csv);
csv->clear();
// Append header row.
CSVFormatter formatter(csv);
for (const auto& column_name : column_names) {
formatter.AppendValue(column_name);
}
formatter.EndLine();
// Append every other data record row.
for (const auto& row : records) {
for (const auto& column_name : column_names) {
auto it_field = row.find(column_name);
formatter.AppendValue(it_field != row.end() ?
it_field->second : std::string());
}
formatter.EndLine();
}
}
} // namespace password_manager