Echo Writes Code

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include "crucible/boba/metadata.hpp"

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <optional>
#include <string>
#include <vector>

#ifdef CRUCIBLE_UNIX
#include "crucible/unix/fs.hpp"
namespace platform_fs = crucible::unix::fs;
#endif

#ifdef CRUCIBLE_WINDOWS
#include "crucible/windows/fs.hpp"
namespace platform_fs = crucible::windows::fs;
#endif

[[nodiscard]]
auto read_boba_container(std::string const &boba_file_path) -> std::optional<crucible::boba::metadata::Container> {
  auto const is_file_result = platform_fs::is_file(boba_file_path);

  if (is_file_result.has_failure()) {
    std::cerr << "Filesystem error: " << is_file_result.get_failure().format() << "\n";
    return std::nullopt;
  }

  bool const is_file = is_file_result.get_success();

  if (!is_file) {
    std::cerr
      << "Path '" << boba_file_path << "' does not refer to a regular file\n";

    return std::nullopt;
  }

  auto read_file_data_result = platform_fs::read_file_data(boba_file_path);

  if (read_file_data_result.has_failure()) {
    std::cerr << "Filesystem error: " << read_file_data_result.get_failure().format() << "\n";
    return std::nullopt;
  }

  auto const file_contents = std::move(read_file_data_result).get_success();
  auto from_bytes_result = crucible::boba::metadata::from_bytes(file_contents);

  if (from_bytes_result.has_failure()) {
    std::cerr << "Failed to parse BOBA metadata: " << from_bytes_result.get_failure().format() << "\n";
    return std::nullopt;
  }

  return std::move(from_bytes_result).get_success();
}

auto dump_boba_container(crucible::boba::metadata::Container const &metadata) -> void {
  auto const schema = metadata.get_schema();

  std::cout
    << "• Schema block:\n"
    << "  • Full header count: " << schema.get_full_header_count() << "\n"
    << "  • User header count: " << schema.get_user_header_count() << "\n"
    << "  • Size of each header: " << schema.get_header_size() << " bytes\n"
    << "  • Schema entry count: " << schema.get_entry_count() << "\n"
    << "  • Size of each schema entry: " << schema.get_entry_size() << " bytes\n";

  std::cout << "\n";

  std::size_t index = 0;
  for (const auto &header : metadata) {
    std::cout << "• User block " << index << ":\n";
    std::cout
      << "  • Signature: 0x" << std::hex << header.signature << std::dec << "\n"
      << "  • Data size: " << header.data_size << " bytes\n"
      << "  • User data[0]: 0x" << std::hex << header.user_data[0] << std::dec << "\n"
      << "  • User data[1]: 0x" << std::hex << header.user_data[1] << std::dec << "\n"
      << "  • Data starts at offset: " << header.offset << "\n";

    ++index;
  }
}

auto main(int argc, char *argv[]) -> int {
  std::vector<std::string> const arguments(argv + 1, argv + argc);
  std::optional<std::string> boba_file_path {};

  auto current = arguments.begin();
  auto const end = arguments.end();

  while (current != end) {
    if (!boba_file_path.has_value()) {
      boba_file_path = *current++;
      continue;
    }

    std::cerr
      << "Unrecognized option or argument '" << *current << "'\n"
      << "Usage: " << argv[0] << " BOBA_FILE\n";

    return EXIT_FAILURE;
  }

  if (!boba_file_path.has_value()) {
    std::cerr
      << "Missing argument BOBA_FILE\n"
      << "Usage: " << argv[0] << " BOBA_FILE\n";

    return EXIT_FAILURE;
  }

  auto const container = read_boba_container(boba_file_path.value());
  if (!container.has_value()) {
    std::cerr << "Usage: " << argv[0] << " BOBA_FILE\n";
    return EXIT_FAILURE;
  }

  dump_boba_container(container.value());
  return EXIT_SUCCESS;
}