blob: 763563220bd66c079cf4e0efa597d893a330cf1e [file] [log] [blame]
// Copyright (c) 2012 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 "chromeos/system/name_value_pairs_parser.h"
#include <stddef.h>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/process/launch.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/system/sys_info.h"
namespace chromeos { // NOLINT
namespace system {
namespace {
bool GetToolOutput(int argc, const char* argv[], std::string* output) {
DCHECK_GE(argc, 1);
if (!base::PathExists(base::FilePath(argv[0]))) {
LOG(WARNING) << "Tool for statistics not found: " << argv[0];
return false;
}
std::vector<std::string> args;
for (int argn = 0; argn < argc; ++argn)
args.push_back(argv[argn]);
if (!base::GetAppOutput(args, output)) {
LOG(WARNING) << "Error executing " << argv[0];
return false;
}
return true;
}
} // namespace
NameValuePairsParser::NameValuePairsParser(NameValueMap* map)
: map_(map) {
}
bool NameValuePairsParser::GetNameValuePairsFromFile(
const base::FilePath& file_path,
const std::string& eq,
const std::string& delim) {
std::string contents;
if (base::ReadFileToString(file_path, &contents)) {
return ParseNameValuePairs(contents, eq, delim);
} else {
if (base::SysInfo::IsRunningOnChromeOS())
VLOG(1) << "Statistics file not present: " << file_path.value();
return false;
}
}
bool NameValuePairsParser::ParseNameValuePairsFromTool(
int argc,
const char* argv[],
const std::string& eq,
const std::string& delim,
const std::string& comment_delim) {
std::string output_string;
if (!GetToolOutput(argc, argv, &output_string))
return false;
return ParseNameValuePairsWithComments(output_string, eq, delim,
comment_delim);
}
void NameValuePairsParser::DeletePairsWithValue(const std::string& value) {
auto it = map_->begin();
while (it != map_->end()) {
if (it->second == value) {
it = map_->erase(it);
} else {
it++;
}
}
}
void NameValuePairsParser::AddNameValuePair(const std::string& key,
const std::string& value) {
const auto it = map_->find(key);
if (it == map_->end()) {
(*map_)[key] = value;
VLOG(1) << "name: " << key << ", value: " << value;
} else if (it->second != value) {
LOG(WARNING) << "Key " << key << " already has value " << it->second
<< ", ignoring new value: " << value;
}
}
bool NameValuePairsParser::ParseNameValuePairs(const std::string& in_string,
const std::string& eq,
const std::string& delim) {
return ParseNameValuePairsWithComments(in_string, eq, delim, "");
}
bool NameValuePairsParser::ParseNameValuePairsWithComments(
const std::string& in_string,
const std::string& eq,
const std::string& delim,
const std::string& comment_delim) {
bool all_valid = true;
// Set up the pair tokenizer.
base::StringTokenizer pair_toks(in_string, delim);
pair_toks.set_quote_chars("\"");
// Process token pairs.
while (pair_toks.GetNext()) {
std::string pair(pair_toks.token());
// Anything before the first |eq| is the key, anything after is the value.
// |eq| must exist.
size_t eq_pos = pair.find(eq);
if (eq_pos != std::string::npos) {
// First |comment_delim| after |eq_pos| starts the comment.
// A value of |std::string::npos| means that the value spans to the end
// of |pair|.
size_t value_size = std::string::npos;
if (!comment_delim.empty()) {
size_t comment_pos = pair.find(comment_delim, eq_pos + 1);
if (comment_pos != std::string::npos)
value_size = comment_pos - eq_pos - 1;
}
static const char kTrimChars[] = "\" ";
std::string key;
std::string value;
base::TrimString(pair.substr(0, eq_pos), kTrimChars, &key);
base::TrimString(pair.substr(eq_pos + 1, value_size), kTrimChars, &value);
if (!key.empty()) {
AddNameValuePair(key, value);
continue;
}
}
LOG(WARNING) << "Invalid token pair: " << pair << ". Ignoring.";
all_valid = false;
}
return all_valid;
}
} // namespace system
} // namespace chromeos