Files
Jungfraujoch/gemmi_gph/gemmi/fileutil.hpp
T
leonarski_f fc68a9baed
Build Packages / Unit tests (push) Skipped
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 8m34s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 10m0s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 10m23s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 10m23s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 11m16s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 11m49s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 8m32s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 9m15s
Build Packages / XDS test (durin plugin) (push) Successful in 7m16s
Build Packages / Generate python client (push) Successful in 16s
Build Packages / build:rpm (rocky9) (push) Successful in 10m12s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 47s
Build Packages / DIALS test (push) Successful in 10m18s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 5m46s
Build Packages / build:rpm (rocky8) (push) Successful in 1h41m2s
Build Packages / XDS test (neggia plugin) (push) Successful in 1h59m18s
v1.0.0-rc.146 (#56)
This is an UNSTABLE release. The release has significant modifications for data processing - in case of troubles go back to 1.0.0-rc.144.

jfjoch_process: Generate a dedicated file (_process.h5), which can be used as a replacement for the _master.h5 file for a reanalyzed dataset.
jfjoch_process: Improve the performance of scaling and merging, implement on the fly scaling.
jfjoch_writer: All final data analysis results are repopulated in the _master.h5 file.
jfjoch_scale: Dedicated tool for rescaling/merging existing data.
jfjoch_viewer: Fix bugs where pixel labels where displayed on a wrong pixel.

WARNING! Scaling and merging are experimental at the moment, and may not provide reasonable results for the time being.

Reviewed-on: #56
2026-05-28 18:48:35 +02:00

174 lines
4.8 KiB
C++

// Copyright 2018 Global Phasing Ltd.
//
// File-related utilities.
#ifndef GEMMI_FILEUTIL_HPP_
#define GEMMI_FILEUTIL_HPP_
#include <cassert>
#include <cstdio> // for FILE, fopen, fclose
#include <cstdint>
#include <cstdlib> // for malloc, realloc
#include <cstring> // for strlen
#include <initializer_list>
#include <memory> // for unique_ptr
#include "fail.hpp" // for sys_fail
#if defined(_WIN32) && !defined(GEMMI_USE_FOPEN)
#include "utf.hpp"
#endif
namespace gemmi {
// strip directory and suffixes from filename
inline std::string path_basename(const std::string& path,
std::initializer_list<const char*> exts) {
size_t pos = path.find_last_of("\\/");
std::string basename = pos == std::string::npos ? path : path.substr(pos + 1);
for (const char* ext : exts) {
size_t len = std::strlen(ext);
if (basename.size() > len &&
basename.compare(basename.length() - len, len, ext, len) == 0)
basename.resize(basename.length() - len);
}
return basename;
}
// file operations
/// deleter for fileptr_t
struct needs_fclose {
bool use_fclose;
void operator()(std::FILE* f) const noexcept {
if (use_fclose)
std::fclose(f);
}
};
typedef std::unique_ptr<std::FILE, needs_fclose> fileptr_t;
inline fileptr_t file_open(const char* path, const char* mode) {
std::FILE* file;
#if defined(_WIN32) && !defined(GEMMI_USE_FOPEN)
std::wstring wpath = UTF8_to_wchar(path);
std::wstring wmode = UTF8_to_wchar(mode);
if ((file = ::_wfopen(wpath.c_str(), wmode.c_str())) == nullptr)
#else
if ((file = std::fopen(path, mode)) == nullptr)
#endif
sys_fail(std::string("Failed to open ") + path +
(*mode == 'w' ? " for writing" : ""));
return fileptr_t(file, needs_fclose{true});
}
// helper function for treating "-" as stdin or stdout
inline fileptr_t file_open_or(const char* path, const char* mode,
std::FILE* dash_stream) {
if (path[0] == '-' && path[1] == '\0')
return fileptr_t(dash_stream, needs_fclose{false});
return file_open(path, mode);
}
inline std::size_t file_size(std::FILE* f, const std::string& path) {
if (std::fseek(f, 0, SEEK_END) != 0)
sys_fail(path + ": fseek failed");
long length = std::ftell(f);
if (length < 0)
sys_fail(path + ": ftell failed");
if (std::fseek(f, 0, SEEK_SET) != 0)
sys_fail(path + ": fseek failed");
return length;
}
// helper function for working with binary files
inline bool is_little_endian() {
std::uint32_t x = 1;
return *reinterpret_cast<char *>(&x) == 1;
}
inline void swap_two_bytes(void* start) {
char* bytes = static_cast<char*>(start);
std::swap(bytes[0], bytes[1]);
}
inline void swap_four_bytes(void* start) {
char* bytes = static_cast<char*>(start);
std::swap(bytes[0], bytes[3]);
std::swap(bytes[1], bytes[2]);
}
inline void swap_eight_bytes(void* start) {
char* bytes = static_cast<char*>(start);
std::swap(bytes[0], bytes[7]);
std::swap(bytes[1], bytes[6]);
std::swap(bytes[2], bytes[5]);
std::swap(bytes[3], bytes[4]);
}
class CharArray {
std::unique_ptr<char, decltype(&std::free)> ptr_;
size_t size_;
public:
CharArray() : ptr_(nullptr, &std::free), size_(0) {}
explicit CharArray(size_t n) : ptr_((char*)std::malloc(n), &std::free), size_(n) {}
explicit operator bool() const { return (bool)ptr_; }
char* data() { return ptr_.get(); }
const char* data() const { return ptr_.get(); }
size_t size() const { return size_; }
void set_size(size_t n) { size_ = n; }
void resize(size_t n) {
char* new_ptr = (char*) std::realloc(ptr_.get(), n);
if (!new_ptr && n != 0)
fail("Out of memory.");
(void) ptr_.release(); // NOLINT(bugprone-unused-return-value)
ptr_.reset(new_ptr);
size_ = n;
}
// Remove first n bytes making space for more text at the returned position.
char* roll(size_t n) {
assert(n <= size());
std::memmove(data(), data() + n, n);
return data() + n;
}
};
/// reading file into a memory buffer (optimized: uses fseek to determine file size)
inline CharArray read_file_into_buffer(const std::string& path) {
fileptr_t f = file_open(path.c_str(), "rb");
size_t size = file_size(f.get(), path);
CharArray buffer(size);
if (std::fread(buffer.data(), size, 1, f.get()) != 1)
sys_fail(path + ": fread failed");
return buffer;
}
inline CharArray read_stdin_into_buffer() {
size_t n = 0;
CharArray buffer(16 * 1024);
for (;;) {
n += std::fread(buffer.data() + n, 1, buffer.size() - n, stdin);
if (n != buffer.size()) {
buffer.set_size(n);
break;
}
buffer.resize(2*n);
}
return buffer;
}
template<typename T>
inline CharArray read_into_buffer(T&& input) {
if (input.is_compressed())
return input.uncompress_into_buffer();
if (input.is_stdin())
return read_stdin_into_buffer();
return read_file_into_buffer(input.path());
}
} // namespace gemmi
#endif