| // 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 |