blob: 3f7e6094087c5f90c924698fa519b32f0a166ace [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 "src/lib/util/file_util.h"
#include <fstream>
#include <streambuf>
#include <string>
#include "src/lib/util/status.h"
#include "src/lib/util/status_codes.h"
#include "src/logging.h"
#include "third_party/abseil-cpp/absl/strings/ascii.h"
#include "third_party/abseil-cpp/absl/strings/escaping.h"
namespace cobalt::util {
namespace {
constexpr int kMaxFileSize = 100000;
}
lib::statusor::StatusOr<std::string> ReadTextFile(const std::string& file_path) {
std::string file_contents;
if (file_path.empty()) {
return Status(INVALID_ARGUMENT, "ReadTextFile: file_path is empty.");
}
std::ifstream stream(file_path, std::ifstream::in);
if (!stream.good()) {
return Status(NOT_FOUND, "Unable to open file at " + file_path);
}
stream.seekg(0, std::ios::end);
if (!stream.good()) {
return Status(INTERNAL, "Error reading file at " + file_path);
}
int64_t file_size = stream.tellg();
if (file_size == 0) {
return std::string("");
}
// Don't try to read a file that's too big.
if (!stream.good() || file_size < 0 || file_size > kMaxFileSize) {
return Status(FAILED_PRECONDITION, "Invalid file length for " + file_path);
}
file_contents.reserve(static_cast<uint64_t>(file_size));
stream.seekg(0, std::ios::beg);
if (!stream.good()) {
return Status(NOT_FOUND, "Error reading file at " + file_path);
}
file_contents.assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
if (!stream.good()) {
return Status(NOT_FOUND, "Error reading file at " + file_path);
}
VLOG(3) << "Successfully read file at " << file_path;
return file_contents;
}
lib::statusor::StatusOr<std::string> ReadNonEmptyTextFile(const std::string& file_path) {
auto read_file_result = ReadTextFile(file_path);
if (!read_file_result.ok()) {
return read_file_result;
}
if (read_file_result.ValueOrDie().empty()) {
return Status(FAILED_PRECONDITION, "File was empty: " + file_path);
}
return read_file_result;
}
lib::statusor::StatusOr<std::string> ReadHexFile(const std::string& file_path) {
auto read_file_result = ReadNonEmptyTextFile(file_path);
if (!read_file_result.ok()) {
return read_file_result;
}
auto hex = absl::StripAsciiWhitespace(read_file_result.ValueOrDie());
if (hex.size() % 2 == 1) {
return Status(FAILED_PRECONDITION, "Hex file has invalid size: " + file_path);
}
if (std::find_if_not(hex.begin(), hex.end(), absl::ascii_isxdigit) != hex.end()) {
return Status(FAILED_PRECONDITION, "Hex file has non-hex characters: " + file_path);
}
return absl::HexStringToBytes(hex);
}
std::string ReadHexFileOrDefault(const std::string& file_path, const std::string& default_string) {
auto read_hex_file_result = ReadHexFile(file_path);
if (!read_hex_file_result.ok()) {
VLOG(1) << "Failed to read hex file: " << read_hex_file_result.status().error_message();
return default_string;
}
return read_hex_file_result.ValueOrDie();
}
} // namespace cobalt::util