From c6d23886be694a555e9eac387464d45f7a4d36e5 Mon Sep 17 00:00:00 2001 From: Georg Hagen Date: Sat, 15 Nov 2025 17:33:11 +0100 Subject: [PATCH] Add CFile wrapper --- openVulkanoCpp/IO/CFile.hpp | 131 ++++++++++++++++++++ openVulkanoCpp/Image/JpegWithTagsWriter.hpp | 42 +++---- 2 files changed, 146 insertions(+), 27 deletions(-) create mode 100644 openVulkanoCpp/IO/CFile.hpp diff --git a/openVulkanoCpp/IO/CFile.hpp b/openVulkanoCpp/IO/CFile.hpp new file mode 100644 index 0000000..df696c3 --- /dev/null +++ b/openVulkanoCpp/IO/CFile.hpp @@ -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 +#include +#include + +namespace OpenVulkano +{ + class CFile + { + static constexpr std::array MODE_STRINGS = { "r", "rb", "w", "wb", "a", "ab", "r+", "rb+", "w+", "wb+", "a+", "ab+" }; + static constexpr std::array 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 + CFile(const T* path, Mode mode) requires std::is_same_v || std::is_same_v : 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 + void Open(const T* path, const Mode mode) requires std::is_same_v || std::is_same_v + { + 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 + [[nodiscard]] static FILE* FOpen(const T* path, const Mode mode) requires std::is_same_v || std::is_same_v + { + if constexpr (std::is_same_v) + return fopen(path, MODE_STRINGS[mode]); + else + return _wfopen(path, MODE_STRINGS_W[mode]); + } + }; +} diff --git a/openVulkanoCpp/Image/JpegWithTagsWriter.hpp b/openVulkanoCpp/Image/JpegWithTagsWriter.hpp index cfd2985..37dfeaa 100644 --- a/openVulkanoCpp/Image/JpegWithTagsWriter.hpp +++ b/openVulkanoCpp/Image/JpegWithTagsWriter.hpp @@ -6,8 +6,8 @@ #pragma once +#include "IO/CFile.hpp" #include -#include #include #include @@ -15,7 +15,7 @@ namespace OpenVulkano { class JpegWithTagsWriter final { - FILE* file; + CFile file; template static T EndianSwap(T value) { @@ -30,7 +30,7 @@ namespace OpenVulkano 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 @@ -39,36 +39,26 @@ namespace OpenVulkano Check(); // ReSharper disable once CppDFAConstantConditions if (app > 0xF) [[unlikely]] throw std::runtime_error("App marker is out of range."); - fputc(0xFF, file); - fputc(0xE0 + app, file); + file.Put(0xFF); + file.Put(0xE0 + app); } void Write16(uint16_t value) const { value = EndianSwap(value); - fwrite(&value, sizeof(value), 1, file); + file.Write(&value, sizeof(value)); } void Write32(uint32_t value) const { value = EndianSwap(value); - fwrite(&value, sizeof(value), 1, file); - } - - template - static FILE* FOpen(const T* path) - { - if constexpr (std::is_same_v) - return fopen(path, "wb"); - else - return _wfopen(path, L"wb"); + file.Write(&value, sizeof(value)); } 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 == nullptr) throw std::runtime_error("Can't open file."); + if (!file) throw std::runtime_error("Can't open file."); // Write soi marker fputc(0xFF, file); fputc(0xD8, file); @@ -81,16 +71,14 @@ namespace OpenVulkano void Close() { - if (!file) throw std::runtime_error("Jpeg file alreay closed!"); - fclose(file); - file = nullptr; + file.Close(); } void WriteExifTag(const std::span& exifTag) const { WriteAppMarker(); 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 @@ -98,9 +86,9 @@ namespace OpenVulkano constexpr std::string_view XMP_MARKER = "http://ns.adobe.com/xap/1.0/"; WriteAppMarker(1); 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 - 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 @@ -112,9 +100,9 @@ namespace OpenVulkano 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; } };