/* * libfud * Copyright 2024 Dominick Allen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "fud_c_file.hpp" namespace fud { CBinaryFile::CBinaryFile(const String& filename, CFileMode mode) : m_filename{filename}, m_mode{CBinaryFileModeFromFlags(mode)}, m_modeFlags{mode} { } CBinaryFile::CBinaryFile(const String& filename, CFileMode mode, const String& extraFlags) : m_filename{filename}, m_extraFlags{extraFlags}, m_mode{String(CBinaryFileModeFromFlags(mode)).append(extraFlags)}, m_modeFlags{mode} { } CBinaryFile::~CBinaryFile() { close(); } FileStatus CBinaryFile::open() { if (!m_filename.valid()) { return FileStatus::InvalidName; } m_file = fopen(m_filename.c_str(), m_mode.c_str()); return m_file != nullptr ? FileStatus::Success : FileStatus::Error; } void CBinaryFile::close() { if (m_file != nullptr) { fclose(m_file); m_file = nullptr; } } const FILE* CBinaryFile::file() const { return m_file; } FILE* CBinaryFile::file() { return m_file; } bool CBinaryFile::isOpen() const { return m_file != nullptr; } Result CBinaryFile::size() const { using RetType = Result; if (!isOpen()) { return RetType::error(FileStatus::InvalidState); } auto seekStatus = fseek(m_file, 0, SEEK_END); if (seekStatus != 0) { return RetType::error(FileStatus::Error); } auto fileSizeResult = ftell(m_file); if (fileSizeResult < 0) { return RetType::error(FileStatus::Error); } auto fileSize = static_cast(fileSizeResult); auto resetStatus = reset(); if (resetStatus != FileStatus::Success) { return RetType::error(resetStatus); } return RetType::okay(fileSize); } FileStatus CBinaryFile::read(void* destination, size_t destinationSize, size_t length) { return read(destination, destinationSize, length, 0); } FileStatus CBinaryFile::read(void* destination, size_t destinationSize, size_t length, size_t offset) { if (length == 0) { return FileStatus::Success; } if (destination == nullptr) { return FileStatus::NullPointer; } if (offset > LONG_MAX || SIZE_MAX - offset < length || destinationSize < length) { return FileStatus::InvalidArgument; } auto fileSizeResult = size(); if (fileSizeResult.isError()) { return fileSizeResult.getError(); } auto fileSize = fileSizeResult.getOkay(); if (offset + length > fileSize) { return FileStatus::InvalidArgument; } auto seekResult = fseek(m_file, static_cast(offset), SEEK_SET); if (seekResult != 0) { return FileStatus::Error; } auto* destPtr = static_cast(destination); auto readResult = fread(destPtr, length, 1, m_file); if (readResult != 1) { static_cast(reset()); return FileStatus::Error; } return FileStatus::Success; } FileStatus CBinaryFile::reset() const { if (!isOpen()) { return FileStatus::InvalidState; } auto result = fseek(m_file, 0, SEEK_SET); return result == 0 ? FileStatus::Success : FileStatus::Error; } } // namespace fud