Electroneum
file_io_utils.h
Go to the documentation of this file.
1 // Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in the
10 // documentation and/or other materials provided with the distribution.
11 // * Neither the name of the Andrey N. Sabelnikov nor the
12 // names of its contributors may be used to endorse or promote products
13 // derived from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
19 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 //
26 
27 
28 #ifndef _FILE_IO_UTILS_H_
29 #define _FILE_IO_UTILS_H_
30 
31 #include <fstream>
32 #include <boost/filesystem/path.hpp>
33 #include <boost/filesystem/operations.hpp>
34 #ifdef WIN32
35 #include <windows.h>
36 #include "string_tools.h"
37 #endif
38 
39 // On Windows there is a problem with non-ASCII characters in path and file names
40 // as far as support by the standard components used is concerned:
41 
42 // The various file stream classes, e.g. std::ifstream and std::ofstream, are
43 // part of the GNU C++ Library / libstdc++. On the most basic level they use the
44 // fopen() call as defined / made accessible to programs compiled within MSYS2
45 // by the stdio.h header file maintained by the MinGW project.
46 
47 // The critical point: The implementation of fopen() is part of MSVCRT, the
48 // Microsoft Visual C/C++ Runtime Library, and this method does NOT offer any
49 // Unicode support.
50 
51 // Electroneum code that would want to continue to use the normal file stream classes
52 // but WITH Unicode support could therefore not solve this problem on its own,
53 // but 2 different projects from 2 different maintaining groups would need changes
54 // in this particular direction - something probably difficult to achieve and
55 // with a long time to wait until all new versions / releases arrive.
56 
57 // Implemented solution approach: Circumvent the problem by stopping to use std
58 // file stream classes on Windows and directly use Unicode-capable WIN32 API
59 // calls. Most of the code doing so is concentrated in this header file here.
60 
61 namespace epee
62 {
63 namespace file_io_utils
64 {
65  inline
66  bool is_file_exist(const std::string& path)
67  {
68  boost::filesystem::path p(path);
69  return boost::filesystem::exists(p);
70  }
71 
72  inline
73  bool save_string_to_file(const std::string& path_to_file, const std::string& str)
74  {
75 #ifdef WIN32
76  std::wstring wide_path;
77  try { wide_path = string_tools::utf8_to_utf16(path_to_file); } catch (...) { return false; }
78  HANDLE file_handle = CreateFileW(wide_path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
79  if (file_handle == INVALID_HANDLE_VALUE)
80  return false;
81  DWORD bytes_written;
82  DWORD bytes_to_write = (DWORD)str.size();
83  BOOL result = WriteFile(file_handle, str.data(), bytes_to_write, &bytes_written, NULL);
84  CloseHandle(file_handle);
85  if (bytes_written != bytes_to_write)
86  result = FALSE;
87  return result;
88 #else
89  try
90  {
91  std::ofstream fstream;
92  fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
93  fstream.open(path_to_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
94  fstream << str;
95  fstream.close();
96  return true;
97  }
98 
99  catch(...)
100  {
101  return false;
102  }
103 #endif
104  }
105 
106  inline
107  bool get_file_time(const std::string& path_to_file, time_t& ft)
108  {
109  boost::system::error_code ec;
110  ft = boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ec);
111  if(!ec)
112  return true;
113  else
114  return false;
115  }
116 
117  inline
118  bool set_file_time(const std::string& path_to_file, const time_t& ft)
119  {
120  boost::system::error_code ec;
121  boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ft, ec);
122  if(!ec)
123  return true;
124  else
125  return false;
126  }
127 
128 
129  inline
130  bool load_file_to_string(const std::string& path_to_file, std::string& target_str, size_t max_size = 1000000000)
131  {
132 #ifdef WIN32
133  std::wstring wide_path;
134  try { wide_path = string_tools::utf8_to_utf16(path_to_file); } catch (...) { return false; }
135  HANDLE file_handle = CreateFileW(wide_path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
136  if (file_handle == INVALID_HANDLE_VALUE)
137  return false;
138  DWORD file_size = GetFileSize(file_handle, NULL);
139  if ((file_size == INVALID_FILE_SIZE) || (uint64_t)file_size > (uint64_t)max_size) {
140  CloseHandle(file_handle);
141  return false;
142  }
143  target_str.resize(file_size);
144  DWORD bytes_read;
145  BOOL result = ReadFile(file_handle, &target_str[0], file_size, &bytes_read, NULL);
146  CloseHandle(file_handle);
147  if (bytes_read != file_size)
148  result = FALSE;
149  return result;
150 #else
151  try
152  {
153  std::ifstream fstream;
154  fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
155  fstream.open(path_to_file, std::ios_base::binary | std::ios_base::in | std::ios::ate);
156 
157  std::ifstream::pos_type file_size = fstream.tellg();
158 
159  if((uint64_t)file_size > (uint64_t)max_size) // ensure a large domain for comparison, and negative -> too large
160  return false;//don't go crazy
161  size_t file_size_t = static_cast<size_t>(file_size);
162 
163  target_str.resize(file_size_t);
164 
165  fstream.seekg (0, std::ios::beg);
166  fstream.read((char*)target_str.data(), target_str.size());
167  fstream.close();
168  return true;
169  }
170 
171  catch(...)
172  {
173  return false;
174  }
175 #endif
176  }
177 
178  inline
179  bool append_string_to_file(const std::string& path_to_file, const std::string& str)
180  {
181  // No special Windows implementation because so far not used in Electroneum code
182  try
183  {
184  std::ofstream fstream;
185  fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
186  fstream.open(path_to_file.c_str(), std::ios_base::binary | std::ios_base::out | std::ios_base::app);
187  fstream << str;
188  fstream.close();
189  return true;
190  }
191 
192  catch(...)
193  {
194  return false;
195  }
196  }
197 
198  inline
199  bool get_file_size(const std::string& path_to_file, uint64_t &size)
200  {
201 #ifdef WIN32
202  std::wstring wide_path;
203  try { wide_path = string_tools::utf8_to_utf16(path_to_file); } catch (...) { return false; }
204  HANDLE file_handle = CreateFileW(wide_path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
205  if (file_handle == INVALID_HANDLE_VALUE)
206  return false;
207  LARGE_INTEGER file_size;
208  BOOL result = GetFileSizeEx(file_handle, &file_size);
209  CloseHandle(file_handle);
210  if (result) {
211  size = file_size.QuadPart;
212  }
213  return size;
214 #else
215  try
216  {
217  std::ifstream fstream;
218  fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
219  fstream.open(path_to_file, std::ios_base::binary | std::ios_base::in | std::ios::ate);
220  size = fstream.tellg();
221  fstream.close();
222  return true;
223  }
224 
225  catch(...)
226  {
227  return false;
228  }
229 #endif
230  }
231 
232 }
233 }
234 
235 #endif //_FILE_IO_UTILS_H_
::std::string string
Definition: gtest-port.h:1097
bool load_file_to_string(const std::string &path_to_file, std::string &target_str, size_t max_size=1000000000)
bool is_file_exist(const std::string &path)
Definition: file_io_utils.h:66
GTEST_API_ size_t GetFileSize(FILE *file)
bool append_string_to_file(const std::string &path_to_file, const std::string &str)
bool get_file_time(const std::string &path_to_file, time_t &ft)
::std::wstring wstring
Definition: gtest-port.h:1103
unsigned __int64 uint64_t
Definition: stdint.h:136
bool save_string_to_file(const std::string &path_to_file, const std::string &str)
Definition: file_io_utils.h:73
bool set_file_time(const std::string &path_to_file, const time_t &ft)
bool get_file_size(const std::string &path_to_file, uint64_t &size)