Add CFile wrapper

This commit is contained in:
Georg Hagen
2025-11-15 17:33:11 +01:00
parent a1955cfb59
commit c6d23886be
2 changed files with 146 additions and 27 deletions

131
openVulkanoCpp/IO/CFile.hpp Normal file
View File

@@ -0,0 +1,131 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <array>
#include <cstdio>
#include <filesystem>
namespace OpenVulkano
{
class CFile
{
static constexpr std::array<char[4], 12> MODE_STRINGS = { "r", "rb", "w", "wb", "a", "ab", "r+", "rb+", "w+", "wb+", "a+", "ab+" };
static constexpr std::array<wchar_t[4], 12> MODE_STRINGS_W = { L"r", L"rb", L"w", L"wb", L"a", L"ab", L"r+", L"rb+", L"w+", L"wb+", L"a+", L"ab+" };
public:
enum Mode
{
READ = 0,
READ_BINARY,
WRITE,
WRITE_BINARY,
APPEND,
APPEND_BINARY,
READ_WRITE, // Null if file does not exist
READ_WRITE_BINARY, // Null if file does not exist
WRITE_READ, // Creates file if not exists
WRITE_READ_BINARY, // Creates file if not exists
APPEND_READ,
APPEND_READ_BINARY,
};
FILE* f = nullptr;
CFile() = default;
CFile(const std::filesystem::path& path, const Mode mode) : CFile(path.c_str(), mode)
{}
template<typename T>
CFile(const T* path, Mode mode) requires std::is_same_v<T, char> || std::is_same_v<T, wchar_t> : f(FOpen(path, mode))
{}
CFile(const CFile&) = delete;
CFile& operator=(const CFile&) = delete;
CFile(CFile&& other) noexcept : f(other.f)
{
other.f = nullptr;
}
CFile& operator=(CFile&& other) noexcept
{
Close();
f = other.f;
other.f = nullptr;
return *this;
}
~CFile()
{
Close();
}
void Close()
{
if (f)
{
fclose(f);
f = nullptr;
}
}
void Open(const std::filesystem::path& path, const Mode mode)
{
Close(); // Close current
f = FOpen(path.c_str(), mode);
}
template<typename T>
void Open(const T* path, const Mode mode) requires std::is_same_v<T, char> || std::is_same_v<T, wchar_t>
{
f = FOpen(path, mode);
}
size_t Read(void* data, const size_t elementSize, const size_t elementCount = 1) const
{
return fread(data, elementSize, elementCount, f);
}
size_t Write(const void* data, const size_t elementSize, const size_t elementCount = 1) const
{
return fwrite(data, elementSize, elementCount, f);
}
int Put(const char c) const
{
return fputc(c, f);
}
void Seek(const long position, const int mode = SEEK_SET) const
{
fseek(f, position, mode);
}
[[nodiscard]] long Tell() const
{
return ftell(f);
}
FILE* FilePtr() const { return f; }
[[nodiscard]] operator bool() const noexcept { return f != nullptr; }
[[nodiscard]] operator FILE*() const noexcept { return f; }
// Helper function, might be used outside off class
template<typename T>
[[nodiscard]] static FILE* FOpen(const T* path, const Mode mode) requires std::is_same_v<T, char> || std::is_same_v<T, wchar_t>
{
if constexpr (std::is_same_v<T, char>)
return fopen(path, MODE_STRINGS[mode]);
else
return _wfopen(path, MODE_STRINGS_W[mode]);
}
};
}

View File

@@ -6,8 +6,8 @@
#pragma once #pragma once
#include "IO/CFile.hpp"
#include <algorithm> #include <algorithm>
#include <filesystem>
#include <span> #include <span>
#include <string_view> #include <string_view>
@@ -15,7 +15,7 @@ namespace OpenVulkano
{ {
class JpegWithTagsWriter final class JpegWithTagsWriter final
{ {
FILE* file; CFile file;
template<typename T> static T EndianSwap(T value) template<typename T> static T EndianSwap(T value)
{ {
@@ -30,7 +30,7 @@ namespace OpenVulkano
void Check() const void Check() const
{ {
if (file == nullptr) throw std::runtime_error("Can't append to jpeg file, it has already been completed."); if (!file) throw std::runtime_error("Can't append to jpeg file, it has already been closed.");
} }
// ReSharper disable once CppDFAConstantParameter // ReSharper disable once CppDFAConstantParameter
@@ -39,36 +39,26 @@ namespace OpenVulkano
Check(); Check();
// ReSharper disable once CppDFAConstantConditions // ReSharper disable once CppDFAConstantConditions
if (app > 0xF) [[unlikely]] throw std::runtime_error("App marker is out of range."); if (app > 0xF) [[unlikely]] throw std::runtime_error("App marker is out of range.");
fputc(0xFF, file); file.Put(0xFF);
fputc(0xE0 + app, file); file.Put(0xE0 + app);
} }
void Write16(uint16_t value) const void Write16(uint16_t value) const
{ {
value = EndianSwap(value); value = EndianSwap(value);
fwrite(&value, sizeof(value), 1, file); file.Write(&value, sizeof(value));
} }
void Write32(uint32_t value) const void Write32(uint32_t value) const
{ {
value = EndianSwap(value); value = EndianSwap(value);
fwrite(&value, sizeof(value), 1, file); file.Write(&value, sizeof(value));
}
template<typename T>
static FILE* FOpen(const T* path)
{
if constexpr (std::is_same_v<T, char>)
return fopen(path, "wb");
else
return _wfopen(path, L"wb");
} }
public: public:
JpegWithTagsWriter(const std::filesystem::path& filePath) JpegWithTagsWriter(const std::filesystem::path& filePath) : file(filePath, CFile::WRITE_BINARY)
{ {
file = FOpen(filePath.c_str()); if (!file) throw std::runtime_error("Can't open file.");
if (file == nullptr) throw std::runtime_error("Can't open file.");
// Write soi marker // Write soi marker
fputc(0xFF, file); fputc(0xFF, file);
fputc(0xD8, file); fputc(0xD8, file);
@@ -81,16 +71,14 @@ namespace OpenVulkano
void Close() void Close()
{ {
if (!file) throw std::runtime_error("Jpeg file alreay closed!"); file.Close();
fclose(file);
file = nullptr;
} }
void WriteExifTag(const std::span<const uint8_t>& exifTag) const void WriteExifTag(const std::span<const uint8_t>& exifTag) const
{ {
WriteAppMarker(); WriteAppMarker();
Write16(exifTag.size() + 2); // 2 byte extra for the size value itself Write16(exifTag.size() + 2); // 2 byte extra for the size value itself
fwrite(exifTag.data(), sizeof(uint8_t), exifTag.size(), file); file.Write(exifTag.data(), sizeof(uint8_t), exifTag.size());
} }
void WriteXmpTag(const std::string& xmpTag) const void WriteXmpTag(const std::string& xmpTag) const
@@ -98,9 +86,9 @@ namespace OpenVulkano
constexpr std::string_view XMP_MARKER = "http://ns.adobe.com/xap/1.0/"; constexpr std::string_view XMP_MARKER = "http://ns.adobe.com/xap/1.0/";
WriteAppMarker(1); WriteAppMarker(1);
Write16(xmpTag.size() + XMP_MARKER.size() + 3); // 1 byte extra for null termination, 2 byte extra for the size value itself Write16(xmpTag.size() + XMP_MARKER.size() + 3); // 1 byte extra for null termination, 2 byte extra for the size value itself
fwrite(XMP_MARKER.data(), XMP_MARKER.size(), 1, file); file.Write(XMP_MARKER.data(), XMP_MARKER.size());
fputc(0, file); // Null terminate string fputc(0, file); // Null terminate string
fwrite(xmpTag.c_str(), 1, xmpTag.size(), file); file.Write(xmpTag.c_str(), 1, xmpTag.size());
} }
// Must be called as last function, as this will finalize the image writing and will close the file // Must be called as last function, as this will finalize the image writing and will close the file
@@ -112,9 +100,9 @@ namespace OpenVulkano
if (close) Close(); if (close) Close();
} }
operator bool() const { return file != nullptr; } operator bool() const { return file; }
[[nodiscard]] bool IsOpen() const { return file != nullptr; } [[nodiscard]] bool IsOpen() const { return file; }
[[nodiscard]] FILE* GetFilePtr() const { return file; } [[nodiscard]] FILE* GetFilePtr() const { return file; }
}; };