Enigma  3.2.0
A Simple, Reliable and Efficient Encryption Tool
FileUtils.hpp
Go to the documentation of this file.
1 #pragma once
2 #ifndef ENIGMA_FILE_UTILS_H
3 #define ENIGMA_FILE_UTILS_H
4 
5 #include <Core/Core.hpp>
6 #include <Logger/Logger.hpp>
7 #include <version> // version include has yvals_core.h include so we can use __cpp_lib_filesystem & __cpp_lib_experimental_filesystem defines
8 
9 #include <fstream>
10 #if defined(__cpp_lib_filesystem)
11 #include <filesystem>
12 namespace fs = std::filesystem;
13 #elif defined(__cpp_lib_experimental_filesystem)
14 #include <experimental/filesystem>
15 namespace fs = std::experimental::filesystem;
16 #else
17 #error compiler does not support std::filesystem
18 #endif
19 #include "FinalAction.hpp"
20 
22 class FileUtils final {
23  ENIGMA_STATIC_CLASS(FileUtils);
24 
25  public:
26  static bool Read(const fs::path& filename, std::vector<byte>& buffer) {
27  if (std::ifstream ifs{filename, std::ios::binary | std::ios::ate}) // ate: open at the end
28  {
29  const std::size_t file_size = static_cast<std::size_t>(ifs.tellg());
30  buffer.resize(file_size, '\000');
31  ifs.seekg(0, std::ios::beg);
32  ifs.read(reinterpret_cast<char *>(buffer.data()), file_size);
33  ifs.close();
34  return true;
35  } else {
36  ENIGMA_ERROR("Failed to read file {}", filename.string());
37  return false;
38  }
39  }
40 
41  static bool ReadString(const fs::path& filename, std::string& buffer) {
42  if (std::ifstream ifs{filename, std::ios::binary | std::ios::ate}) // ate: open at the end
43  {
44  const std::size_t file_size = static_cast<std::size_t>(ifs.tellg());
45  buffer.resize(file_size, '\000');
46  ifs.seekg(0, std::ios::beg);
47  ifs.read(reinterpret_cast<char *>(buffer.data()), file_size);
48  ifs.close();
49  return true;
50  } else {
51  ENIGMA_ERROR("Failed to read file {}", filename.string());
52  return false;
53  }
54  }
55 
56  static bool Write(const fs::path& filename, const std::vector<byte>& buffer) {
57  if (std::ofstream ofs{filename, std::ios::binary}) {
58  ofs.write(reinterpret_cast<const char *>(buffer.data()), buffer.size());
59  ofs.close();
60  return true;
61  } else {
62  ENIGMA_ERROR("Failed to write file {}", filename.string());
63  return false;
64  }
65  }
66 
67  static bool WriteString(const fs::path& filename, const std::string& buffer) {
68  if (std::ofstream ofs{filename, std::ios::binary}) {
69  ofs.write(reinterpret_cast<const char *>(buffer.data()), buffer.size());
70  ofs.close();
71  return true;
72  } else {
73  ENIGMA_ERROR("Failed to write file {}", filename.string());
74  return false;
75  }
76  }
77 
78  /*
79  * Reads a file chunk by chunk
80  */
81  static void ReadChunksFstream(const fs::path& filename, const std::size_t max_chunk_size, const std::function<bool(std::vector<byte>&&)>& callback) {
82  if (std::ifstream ifs{filename, std::ios::binary}) {
83  while (!ifs.eof()) {
84  std::vector<Enigma::byte> chunk(max_chunk_size, '\000');
85  ifs.read(reinterpret_cast<char *>(chunk.data()), chunk.size());
86 
87  // resize chunk if we read bytes less than max_chunk_size
88  const auto bytes_read = static_cast<std::size_t>(ifs.gcount());
89  if (bytes_read < max_chunk_size)
90  chunk.resize(bytes_read);
91 
92  // serve chunk and see if false was returned from callback to stop reading loop.
93  if (!callback(std::move(chunk))) break;
94  }
95  ifs.close();
96  } else {
97  ENIGMA_ERROR("Failed to read file chunks {}", filename.string());
98  }
99  }
100 
101  /*
102  * Reads a file chunk by chunk
103  */
104  static void ReadChunks(const fs::path& filename, const std::size_t max_chunk_size, const std::function<bool(std::vector<byte>&&)>& callback) {
105  // Open file to read from
106  std::FILE *file = std::fopen(filename.string().c_str(), "rb");
107  if (!file) {
108  ENIGMA_ERROR("Failed to read file chunks {}", filename.string());
109  return;
110  }
111  FinalAction fileCloser([&file] {
112  std::fclose(file);
113  });
114 
115  // While end of file not reached...
116  while (!std::feof(file)) {
117  // Make some memory for chunk
118  std::vector<Enigma::byte> chunk(max_chunk_size, '\000');
119 
120  // Read chunk and get back how many bytes were read
121  const std::size_t bytes_read = std::fread(chunk.data(), sizeof(Enigma::byte), max_chunk_size, file);
122  // resize chunk if we read bytes less than max_chunk_size
123  if (bytes_read < max_chunk_size)
124  chunk.resize(bytes_read);
125 
126  // Serve chunk
127  if (!callback(std::move(chunk))) break;
128  }
129  }
130 };
132 
133 #endif // !ENIGMA_FILE_UTILS_H
#define ENIGMA_ERROR(...)
Definition: Logger.hpp:43
#define NS_ENIGMA_BEGIN
Enable/Disable Assertions.
Definition: Macros.hpp:13
#define NS_ENIGMA_END
Definition: Macros.hpp:14
static bool WriteString(const fs::path &filename, const std::string &buffer)
Definition: FileUtils.hpp:67
static bool Write(const fs::path &filename, const std::vector< byte > &buffer)
Definition: FileUtils.hpp:56
static void ReadChunks(const fs::path &filename, const std::size_t max_chunk_size, const std::function< bool(std::vector< byte > &&)> &callback)
Definition: FileUtils.hpp:104
static bool ReadString(const fs::path &filename, std::string &buffer)
Definition: FileUtils.hpp:41
static void ReadChunksFstream(const fs::path &filename, const std::size_t max_chunk_size, const std::function< bool(std::vector< byte > &&)> &callback)
Definition: FileUtils.hpp:81
static bool Read(const fs::path &filename, std::vector< byte > &buffer)
Definition: FileUtils.hpp:26
Executes a function at the end of the scope (deferred) using RAII gsl libs.
Definition: FinalAction.hpp:9
std::uint8_t byte
Definition: Types.hpp:12