1#if !defined( _GNU_SOURCE )
7#include "MemoryBufferBackedFileContents.h"
9#include "../Logging/Logger.h"
24void Cogs::IO::readFileAsync(
const std::string & fileName,
const FileContents::Callback& callback, uint64_t offset, uint64_t size, FileContentsHints hints)
26 if (size == 0 && offset != 0) {
27 LOG_ERROR(envLogger,
"readFileAsync: Illegal range, trying to read zero bytes from offset (%" PRIu64
")", offset);
28 callback(std::unique_ptr<FileContents>());
32 std::ifstream file(fileName, std::ios::binary | std::ios::in | std::ios::ate);
33 if (!file.is_open()) {
34 LOG_ERROR(envLogger,
"readFileAsync: Failed to open file %s", fileName.c_str());
35 callback(std::unique_ptr<FileContents>());
39 file.seekg(0, std::ios::end);
41 std::streampos fileSize = file.tellg();
43 LOG_ERROR(envLogger,
"readFileAsync: tellg returned an error.");
46 uint64_t readOffset = 0;
47 uint64_t readSize =
static_cast<uint64_t
>(fileSize);
49 if (readSize < offset) {
50 LOG_ERROR(envLogger,
"readFileAsync: offset (%" PRIu64
") is greater than filesize (%" PRIu64
")", offset,
static_cast<uint64_t
>(fileSize));
54 readSize -= readOffset;
55 if (readSize < size) {
56 LOG_ERROR(envLogger,
"readFileAsync: offset (%" PRIu64
") + size(%" PRIu64
") is greater than filesize (%" PRIu64
")", offset, size,
static_cast<uint64_t
>(fileSize));
62 if (
static_cast<uint64_t
>(std::numeric_limits<size_t>::max()) <
static_cast<uint64_t
>(readSize)) {
63 LOG_ERROR(envLogger,
"readFileAsync: offset (%" PRIu64
") + size(%" PRIu64
") is greater than max size_t (>4GB read on 32bit?)", offset, size);
67 auto contents = std::make_unique<MemoryBufferBackedFileContents>(readSize, fileName, hints);
68 file.seekg(
static_cast<std::streamoff
>(readOffset), std::ios::beg);
69 file.read((
char*)contents->bytes.data(), contents->bytes.size());
71 callback(std::move(contents));
77 callback(std::unique_ptr<FileContents>());
81std::unique_ptr<Cogs::FileContents> Cogs::IO::readFileSync(
const std::string & fileName, uint64_t offset, uint64_t size, FileContentsHints hints)
83 if (size == 0 && offset != 0) {
84 LOG_ERROR(envLogger,
"readFileAsync: Illegal range, trying to read zero bytes from offset (%" PRIu64
")", offset);
85 return std::unique_ptr<FileContents>();
88 std::ifstream file(fileName, std::ios::binary | std::ios::in | std::ios::ate);
89 if (!file.is_open()) {
90 LOG_ERROR(envLogger,
"readFileAsync: Failed to open file %s", fileName.c_str());
91 return std::unique_ptr<FileContents>();
94 file.seekg(0, std::ios::end);
95 std::streampos fileSize = file.tellg();
97 LOG_ERROR(envLogger,
"readFileAsync: tellg returned an error.");
98 return std::unique_ptr<FileContents>();
100 uint64_t readOffset = 0;
101 uint64_t readSize =
static_cast<uint64_t
>(fileSize);
103 if (readSize < offset) {
104 LOG_ERROR(envLogger,
"readFileAsync: offset (%" PRIu64
") is greater than filesize (%" PRIu64
")", offset,
static_cast<uint64_t
>(fileSize));
105 return std::unique_ptr<FileContents>();
108 readSize -= readOffset;
109 if (readSize < size) {
110 LOG_ERROR(envLogger,
"readFileAsync: offset (%" PRIu64
") + size(%" PRIu64
") is greater than filesize (%" PRIu64
")", offset, size,
static_cast<uint64_t
>(fileSize));
111 return std::unique_ptr<FileContents>();
116 if (
static_cast<uint64_t
>(std::numeric_limits<size_t>::max()) < readSize) {
117 LOG_ERROR(envLogger,
"readFileAsync: offset (%" PRIu64
") + size(%" PRIu64
") is greater than max size_t (>4GB read on 32bit?)", offset, size);
118 return std::unique_ptr<FileContents>();
121 auto contents = std::make_unique<MemoryBufferBackedFileContents>(readSize, fileName, hints);
122 file.seekg(
static_cast<std::streamoff
>(readOffset), std::ios::beg);
123 file.read((
char*)contents->bytes.data(), contents->bytes.size());
128bool Cogs::IO::readTextFile(std::string& content,
const std::string & fileName)
130 std::ifstream in(fileName);
133 content = std::string((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
139void Cogs::IO::autoExpandEnvironmentVariables(std::string & text)
141 static std::regex env(
"%([0-9A-Za-z\\/]*)%");
144 while (std::regex_search(text, match, env)) {
145 const char * s = std::getenv(match[1].str().c_str());
146 const std::string environmentVariable(s ==
nullptr ?
"" : s);
148 text.replace(match[0].first, match[0].second, environmentVariable);
152std::string Cogs::IO::expandEnvironmentVariables(
const std::string& input) {
153 std::string text = input;
154 autoExpandEnvironmentVariables(text);
158std::string Cogs::IO::expandEnvironmentVariable(
const std::string& name) {
159 const char *tmp = getenv(name.c_str());
161 return std::string(tmp ? tmp :
"");
164char Cogs::IO::pathSeparator() {
168bool Cogs::IO::exists(std::string_view path) {
169 return fs::exists(path);
172bool Cogs::IO::isFile(std::string_view path) {
173 return fs::is_regular_file(path);
176bool Cogs::IO::isDirectory(std::string_view path) {
177 return fs::is_directory(path);
180std::string Cogs::IO::absolute(std::string_view path) {
181 return fs::absolute(fs::path(path)).string();
184std::string Cogs::IO::canonical(std::string_view path) {
186 return fs::canonical(fs::path(path), ec).string();
189bool Cogs::IO::remove(std::string_view path) {
190 return fs::remove(path);
193std::string Cogs::IO::combine(std::string_view path, std::string_view extensionPath) {
194 return (fs::path(path).append(extensionPath)).string();
197std::string Cogs::IO::expandPath(std::string_view fileName) {
198 return expandEnvironmentVariables(fs::path(fileName).
string());
201std::string Cogs::IO::parentPath(std::string_view str) {
202 return fs::path(str.begin(), str.end()).parent_path().string();
205std::string Cogs::IO::relativePath(std::string_view str) {
206 return fs::path(str).relative_path().string();
209std::string Cogs::IO::relativePath(std::string_view str, std::string_view base) {
210 auto dir = fs::path(base);
211 auto p = fs::path(str);
213 dir = fs::absolute(dir);
216 auto beginA = p.begin();
217 auto beginB = dir.begin();
219 while (beginA != p.end() && beginB != dir.end()) {
220 if (*beginA != *beginB)
break;
227 for (; beginB != dir.end(); ++beginB) {
231 for (; beginA != p.end(); ++beginA) {
235 return relative.string();
238std::string Cogs::IO::getPathToExe() {
241 readlink(
"/proc/self/exe", path,
sizeof(path) - 1);
245std::string Cogs::IO::getPathRelativeToDll(
const std::string& fileName,
void* handle) {
247 std::string fullPath;
249 if (!dladdr(handle, &info)) {
252 fullPath = info.dli_fname;
253 fullPath = fullPath.substr(0, fullPath.find_last_of(
'/') + 1);
254 fullPath += fileName;
259std::string Cogs::IO::getTempPath() {
263std::string Cogs::IO::getAppDataPath() {
264 return getOrgLocalDataPath() +
"/Cogs/";
267std::string Cogs::IO::getOrgLocalDataPath() {
269 mkdir(
"/etc/Kongsberg", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
270 return std::string(
"/etc/Kongsberg Digital/");
273 std::string path = expandEnvironmentVariable(
"HOME");
274 path +=
"/.local/share/Kongsberg Digital/";
279bool Cogs::IO::isAbsolute(std::string_view str) {
280 return (str.size() >= 1) && (str[0] ==
'/');
283bool Cogs::IO::isRelative(std::string_view str) {
284 return !isAbsolute(str);
287std::string Cogs::IO::fileName(std::string_view str) {
288 size_t lastSep = str.find_last_of(
"/\\");
289 if (lastSep != std::string_view::npos) {
290 str = str.substr(lastSep + 1);
293 return std::string(str);
296std::string Cogs::IO::extension(std::string_view str) {
297 size_t lastSep = str.find_last_of(
"/\\");
298 if (lastSep != std::string_view::npos) {
299 str = str.substr(lastSep + 1);
302 return fs::path(str).extension().string();
305std::string Cogs::IO::stem(std::string_view str) {
306 size_t lastSep = str.find_last_of(
"/\\");
307 if (lastSep != std::string_view::npos) {
308 str = str.substr(lastSep + 1);
311 return fs::path(str.begin(), str.end()).stem().string();
314void Cogs::IO::replaceAll(std::string& str, std::string_view from, std::string_view to) {
315 if (from.empty())
return;
318 while ((startPos = str.find(from, startPos)) != std::string::npos) {
319 str.replace(startPos, from.length(), to);
320 startPos += to.length();
324Cogs::IO::FileTimeType Cogs::IO::getFileTime(std::string_view path) {
326 return fs::last_write_time(fs::path(path.begin(), path.end()), ec);
329uint64_t Cogs::IO::getFileSize(std::string_view path) {
331 if(::stat(std::string(path).c_str(), &st) != 0) {
334 return static_cast<uint64_t
>(st.st_size);
337bool Cogs::IO::writeBinaryFile(
const std::string & fileName,
const void * content,
size_t contentSize) {
338 fs::path path(fileName);
340 if (path.has_parent_path() && !fs::exists(path.parent_path()) && !fs::create_directories(path.parent_path())) {
344 int fd = open(path.string().c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0664);
345 if(fd == -1)
return false;
347 const uint8_t *src =
static_cast<const uint8_t*
>(content);
348 size_t remaining = contentSize;
350 size_t write_size = remaining;
351 ssize_t ret = write(fd, src, write_size);
352 if(ret == 0 || (ret == -1 && errno != EINTR)){
357 size_t written = ret;
359 remaining -= written;
367bool Cogs::IO::createDirectories(std::string_view fileName) {
368 fs::path path(fileName);
370 if (path.has_parent_path() && !fs::exists(path.parent_path()) && !fs::create_directories(path.parent_path())) {
376Cogs::IO::RecursiveDirIterator Cogs::IO::directoryIterator(std::string_view directory) {
377 return RecursiveDirIterator(directory);
380std::string Cogs::IO::getPath(
const DirectoryEntry& entry) {
381 return entry.path().string();
384Cogs::FileHandle::Ptr Cogs::IO::openFile(std::string_view path, FileHandle::OpenMode openMode, FileHandle::AccessMode accessMode) {
385 return FileHandle::open(path, openMode, accessMode);
388void Cogs::IO::closeFile(
const FileHandle::Ptr& handle) {
389 if (handle) handle->close();
392size_t Cogs::IO::fileSize(
const FileHandle::Ptr& handle) {
393 return handle ? handle->getSize() : 0;
396void* Cogs::IO::mapFile(
const FileHandle::Ptr& handle, FileHandle::ProtectionMode protectionMode,
size_t offset,
size_t size) {
397 return handle ? handle->map(protectionMode, offset, size) :
nullptr;
400void Cogs::IO::unmapFile(
const FileHandle::Ptr& handle) {
401 if (handle) handle->unmap();
407bool Cogs::IO::copyFile(std::string_view src, std::string_view dest)
409 int fd_in = open(src.data(), O_RDONLY);
414 if(fstat(fd_in, &s) == -1){
418 int fd_out = open(dest.data(), O_CREAT | O_WRONLY | O_TRUNC, s.st_mode&0x777);
424 size_t remaining = s.st_size;
426 ssize_t ret = copy_file_range(fd_in,
nullptr, fd_out,
nullptr, remaining, 0);
442bool Cogs::IO::copyFile(std::string_view src, std::string_view dest)
445 if(!std::filesystem::copy_file(src, dest, ec)) {
449 LOG_ERROR(envLogger,
"Failed to copy %.*s to %.*s: %s",
450 StringViewFormat(src),
451 StringViewFormat(dest),
452 ec.message().c_str());
Log implementation class.
constexpr Log getLogger(const char(&name)[LEN]) noexcept