retdec
file_io.h
Go to the documentation of this file.
1 
7 #ifndef RETDEC_UTILS_FILE_IO_H
8 #define RETDEC_UTILS_FILE_IO_H
9 
10 #include <fstream>
11 #include <vector>
12 
13 namespace retdec {
14 namespace utils {
15 
16 namespace {
17 
21 const std::size_t FILE_BURST_READ_LENGTH = 0x100000;
22 
23 template <typename N> bool readBytes(
24  std::istream& fileStream,
25  std::vector<N>& result,
26  std::size_t desiredSize)
27 {
28  // We can read directly from the file without any conversions.
29  if (sizeof(N) == 1)
30  {
31  // Prepare buffer where to store result
32  std::size_t previousSize = result.size();
33  result.resize(result.size() + desiredSize);
34  char* buffer = reinterpret_cast<char*>(result.data()) + previousSize;
35 
36  // Read and check for error bits
37  // If badbit is set, then something bad happened and data are not valid.
38  // If EOF bit is not set and fail bit is set, then there was some other
39  // problem with reading data.
40  // If EOF bit and failbit are set, then it just means the file was
41  // truncated, but we should not report it as error. Instead, we just
42  // shrink the result buffer to the number of bytes we have read.
43  fileStream.read(buffer, desiredSize);
44  if (fileStream.bad() || (!fileStream.eof() && fileStream.fail()))
45  return false;
46 
47  // We may have read less bytes than requested, so check it
48  // and resize output buffer to match the number of bytes
49  // that were actually read.
50  std::size_t charsRead = fileStream.gcount();
51  if (result.size() != previousSize + charsRead)
52  result.resize(previousSize + charsRead);
53  }
54  else
55  {
56  std::vector<std::uint8_t> temp;
57  if (!readBytes<std::uint8_t>(fileStream, temp, desiredSize))
58  return false;
59 
60  result.reserve(result.size() + temp.size());
61 
62  for (const auto& val : temp)
63  result.push_back(val & 0xFF);
64  }
65 
66  return true;
67 }
68 
69 template <typename N> bool writeBytes(
70  std::ostream& fileStream,
71  const std::vector<N>& data,
72  std::size_t desiredSize)
73 {
74  // We can write directly to the file without any conversions.
75  if (sizeof(N) == 1)
76  {
77  fileStream.write(
78  reinterpret_cast<const char*>(data.data()),
79  desiredSize
80  );
81  return fileStream.good();
82  }
83  else
84  {
85  // Copy lowest bytes from this templated values.
86  std::vector<std::uint8_t> bytesData;
87  for (std::size_t i = 0; i < desiredSize; ++i)
88  bytesData.push_back(data[i] & 0xFF);
89 
90  return writeBytes<std::uint8_t>(fileStream, bytesData, desiredSize);
91  }
92 }
93 
94 } // anonymous namespace
95 
109 template <typename N> bool readFile(
110  std::istream& fileStream,
111  std::vector<N>& result,
112  std::size_t start = 0,
113  std::size_t desiredSize = 0)
114 {
115  // Seek to the given offset and check if nothing bad happened
116  fileStream.seekg(start, std::ios::beg);
117  if (!fileStream.good())
118  return false;
119 
120  const bool untilEof = !desiredSize;
121  if (untilEof)
122  desiredSize = FILE_BURST_READ_LENGTH;
123 
124  result.clear();
125  std::size_t alreadyRead = 0;
126  while ((alreadyRead < desiredSize || untilEof) && !fileStream.eof())
127  {
128  if (!readBytes(fileStream, result, desiredSize))
129  {
130  result.clear();
131  return false;
132  }
133 
134  alreadyRead += result.size();
135  }
136 
137  return true;
138 }
139 
153 template <typename N> bool readFile(
154  const std::string& fileName,
155  std::vector<N>& result,
156  std::size_t start = 0,
157  std::size_t desiredSize = 0)
158 {
159  result.clear();
160 
161  std::ifstream file(fileName, std::ios::in | std::ios::binary);
162  if (!file.is_open())
163  return false;
164 
165  return readFile(file, result, start, desiredSize);
166 }
167 
179 template <typename N> bool writeFile(
180  std::ostream& fileStream,
181  const std::vector<N>& data,
182  std::size_t start = 0,
183  std::size_t desiredSize = 0)
184 {
185  fileStream.seekp(start, std::ios::beg);
186  if (!fileStream.good())
187  return false;
188 
189  // If no size specified, write the whole data.
190  if (!desiredSize)
191  desiredSize = data.size();
192 
193  return writeBytes(fileStream, data, desiredSize);
194 }
195 
207 template <typename N> bool writeFile(
208  const std::string& fileName,
209  const std::vector<N>& data,
210  std::size_t start = 0,
211  std::size_t desiredSize = 0)
212 {
213  std::ofstream file(
214  fileName,
215  std::ios::out | std::ios::trunc | std::ios::binary
216  );
217  if (!file.is_open())
218  return false;
219 
220  bool ret = writeFile(file, data, start, desiredSize);
221  file.close();
222  return ret;
223 }
224 
225 } // namespace utils
226 } // namespace retdec
227 
228 #endif
bool writeFile(std::ostream &fileStream, const std::vector< N > &data, std::size_t start=0, std::size_t desiredSize=0)
Definition: file_io.h:179
bool readFile(std::istream &fileStream, std::vector< N > &result, std::size_t start=0, std::size_t desiredSize=0)
Definition: file_io.h:109
Definition: archive_wrapper.h:19