Gemmi C++ API
Loading...
Searching...
No Matches
fileutil.hpp
Go to the documentation of this file.
1// Copyright 2018 Global Phasing Ltd.
2//
3// File-related utilities.
4
5#ifndef GEMMI_FILEUTIL_HPP_
6#define GEMMI_FILEUTIL_HPP_
7
8#include <cassert>
9#include <cstdio> // for FILE, fopen, fclose
10#include <cstdint>
11#include <cstdlib> // for malloc, realloc
12#include <cstring> // for strlen
13#include <initializer_list>
14#include <memory> // for unique_ptr
15#include "fail.hpp" // for sys_fail
16
17#if defined(_WIN32) && !defined(GEMMI_USE_FOPEN)
18#include "utf.hpp"
19#endif
20
21namespace gemmi {
22
23// strip directory and suffixes from filename
24inline std::string path_basename(const std::string& path,
25 std::initializer_list<const char*> exts) {
26 size_t pos = path.find_last_of("\\/");
27 std::string basename = pos == std::string::npos ? path : path.substr(pos + 1);
28 for (const char* ext : exts) {
29 size_t len = std::strlen(ext);
30 if (basename.size() > len &&
31 basename.compare(basename.length() - len, len, ext, len) == 0)
32 basename.resize(basename.length() - len);
33 }
34 return basename;
35}
36
37// file operations
38
42 void operator()(std::FILE* f) const noexcept {
43 if (use_fclose)
44 std::fclose(f);
45 }
46};
47
48typedef std::unique_ptr<std::FILE, needs_fclose> fileptr_t;
49
50inline fileptr_t file_open(const char* path, const char* mode) {
51 std::FILE* file;
52#if defined(_WIN32) && !defined(GEMMI_USE_FOPEN)
53 std::wstring wpath = UTF8_to_wchar(path);
54 std::wstring wmode = UTF8_to_wchar(mode);
55 if ((file = ::_wfopen(wpath.c_str(), wmode.c_str())) == nullptr)
56#else
57 if ((file = std::fopen(path, mode)) == nullptr)
58#endif
59 sys_fail(std::string("Failed to open ") + path +
60 (*mode == 'w' ? " for writing" : ""));
61 return fileptr_t(file, needs_fclose{true});
62}
63
64// helper function for treating "-" as stdin or stdout
65inline fileptr_t file_open_or(const char* path, const char* mode,
66 std::FILE* dash_stream) {
67 if (path[0] == '-' && path[1] == '\0')
68 return fileptr_t(dash_stream, needs_fclose{false});
69 return file_open(path, mode);
70}
71
72inline std::size_t file_size(std::FILE* f, const std::string& path) {
73 if (std::fseek(f, 0, SEEK_END) != 0)
74 sys_fail(path + ": fseek failed");
75 long length = std::ftell(f);
76 if (length < 0)
77 sys_fail(path + ": ftell failed");
78 if (std::fseek(f, 0, SEEK_SET) != 0)
79 sys_fail(path + ": fseek failed");
80 return length;
81}
82
83// helper function for working with binary files
84inline bool is_little_endian() {
85 std::uint32_t x = 1;
86 return *reinterpret_cast<char *>(&x) == 1;
87}
88
89inline void swap_two_bytes(void* start) {
90 char* bytes = static_cast<char*>(start);
91 std::swap(bytes[0], bytes[1]);
92}
93
94inline void swap_four_bytes(void* start) {
95 char* bytes = static_cast<char*>(start);
96 std::swap(bytes[0], bytes[3]);
97 std::swap(bytes[1], bytes[2]);
98}
99
100inline void swap_eight_bytes(void* start) {
101 char* bytes = static_cast<char*>(start);
102 std::swap(bytes[0], bytes[7]);
103 std::swap(bytes[1], bytes[6]);
104 std::swap(bytes[2], bytes[5]);
105 std::swap(bytes[3], bytes[4]);
106}
107
108
110 std::unique_ptr<char, decltype(&std::free)> ptr_;
111 size_t size_;
112public:
113 CharArray() : ptr_(nullptr, &std::free), size_(0) {}
114 explicit CharArray(size_t n) : ptr_((char*)std::malloc(n), &std::free), size_(n) {}
115 explicit operator bool() const { return (bool)ptr_; }
116 char* data() { return ptr_.get(); }
117 const char* data() const { return ptr_.get(); }
118 size_t size() const { return size_; }
119 void set_size(size_t n) { size_ = n; }
120
121 void resize(size_t n) {
122 char* new_ptr = (char*) std::realloc(ptr_.get(), n);
123 if (!new_ptr && n != 0)
124 fail("Out of memory.");
125 (void) ptr_.release(); // NOLINT(bugprone-unused-return-value)
126 ptr_.reset(new_ptr);
127 size_ = n;
128 }
129
130 // Remove first n bytes making space for more text at the returned position.
131 char* roll(size_t n) {
132 assert(n <= size());
133 std::memmove(data(), data() + n, n);
134 return data() + n;
135 }
136};
137
138
140inline CharArray read_file_into_buffer(const std::string& path) {
141 fileptr_t f = file_open(path.c_str(), "rb");
142 size_t size = file_size(f.get(), path);
143 CharArray buffer(size);
144 if (std::fread(buffer.data(), size, 1, f.get()) != 1)
145 sys_fail(path + ": fread failed");
146 return buffer;
147}
148
150 size_t n = 0;
151 CharArray buffer(16 * 1024);
152 for (;;) {
153 n += std::fread(buffer.data() + n, 1, buffer.size() - n, stdin);
154 if (n != buffer.size()) {
155 buffer.set_size(n);
156 break;
157 }
158 buffer.resize(2*n);
159 }
160 return buffer;
161}
162
163template<typename T>
165 if (input.is_compressed())
166 return input.uncompress_into_buffer();
167 if (input.is_stdin())
168 return read_stdin_into_buffer();
169 return read_file_into_buffer(input.path());
170}
171
172} // namespace gemmi
173#endif
void resize(size_t n)
Definition fileutil.hpp:121
size_t size() const
Definition fileutil.hpp:118
void set_size(size_t n)
Definition fileutil.hpp:119
const char * data() const
Definition fileutil.hpp:117
CharArray(size_t n)
Definition fileutil.hpp:114
char * roll(size_t n)
Definition fileutil.hpp:131
fail(), unreachable() and __declspec/__attribute__ macros
void swap_eight_bytes(void *start)
Definition fileutil.hpp:100
void swap_four_bytes(void *start)
Definition fileutil.hpp:94
CharArray read_into_buffer(T &&input)
Definition fileutil.hpp:164
CharArray read_stdin_into_buffer()
Definition fileutil.hpp:149
std::size_t file_size(std::FILE *f, const std::string &path)
Definition fileutil.hpp:72
std::wstring UTF8_to_wchar(const char *in)
Definition utf.hpp:12
bool is_little_endian()
Definition fileutil.hpp:84
std::string path_basename(const std::string &path, std::initializer_list< const char * > exts)
Definition fileutil.hpp:24
fileptr_t file_open(const char *path, const char *mode)
Definition fileutil.hpp:50
void swap_two_bytes(void *start)
Definition fileutil.hpp:89
GEMMI_COLD void sys_fail(const std::string &msg)
Definition fail.hpp:71
CharArray read_file_into_buffer(const std::string &path)
reading file into a memory buffer (optimized: uses fseek to determine file size)
Definition fileutil.hpp:140
void fail(const std::string &msg)
Definition fail.hpp:59
fileptr_t file_open_or(const char *path, const char *mode, std::FILE *dash_stream)
Definition fileutil.hpp:65
std::unique_ptr< std::FILE, needs_fclose > fileptr_t
Definition fileutil.hpp:48
Definition seqid.hpp:151
deleter for fileptr_t
Definition fileutil.hpp:40
void operator()(std::FILE *f) const noexcept
Definition fileutil.hpp:42
Conversion between UTF-8 and wchar. Used only for file names on Windows.