/* * This file is part of the Colobot: Gold Edition source code * Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsitec.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://gnu.org/licenses */ #include "common/resources/sdl_file_wrapper.h" #include "common/logger.h" #include CSDLFileWrapper::CSDLFileWrapper(const std::string& filename) : m_rwops(nullptr) { if (!PHYSFS_isInit()) { GetLogger()->Error("PHYSFS not initialized!\n"); return; } PHYSFS_File *file = PHYSFS_openRead(filename.c_str()); if (file == nullptr) { GetLogger()->Error("Error opening file with PHYSFS: \"%s\"\n", filename.c_str()); return; } m_rwops = SDL_AllocRW(); if (m_rwops == nullptr) { GetLogger()->Error("Unable to allocate SDL_RWops for \"%s\"\n", filename.c_str()); return; } m_rwops->type = SDL_RWOPS_UNKNOWN; m_rwops->hidden.unknown.data1 = file; m_rwops->seek = SDLSeek; m_rwops->read = SDLRead; m_rwops->write = SDLWrite; m_rwops->size = SDLSize; // This is safe because SDL_FreeRW will be called in destructor m_rwops->close = SDLCloseWithoutFreeRW; } CSDLFileWrapper::~CSDLFileWrapper() { SDLCloseWithFreeRW(m_rwops); } SDL_RWops* CSDLFileWrapper::GetHandler() { return m_rwops; } bool CSDLFileWrapper::IsOpen() const { return m_rwops != nullptr; } int CSDLFileWrapper::SDLClose(SDL_RWops *context, bool freeRW) { if (context == nullptr) return 0; if (!CheckSDLContext(context)) return 1; if (context->hidden.unknown.data1 != nullptr) { PHYSFS_close(static_cast(context->hidden.unknown.data1)); context->hidden.unknown.data1 = nullptr; } if (freeRW) SDL_FreeRW(context); return 0; } int CSDLFileWrapper::SDLCloseWithoutFreeRW(SDL_RWops *context) { return SDLClose(context, false); } int CSDLFileWrapper::SDLCloseWithFreeRW(SDL_RWops *context) { return SDLClose(context, true); } bool CSDLFileWrapper::CheckSDLContext(SDL_RWops *context) { if (context->type != SDL_RWOPS_UNKNOWN) { SDL_SetError("Wrong kind of RWops"); return false; } return true; } Sint64 CSDLFileWrapper::SDLSeek(SDL_RWops *context, Sint64 offset, int whence) { if (CheckSDLContext(context)) { PHYSFS_File *file = static_cast(context->hidden.unknown.data1); switch (whence) { default: case RW_SEEK_SET: { auto result = PHYSFS_seek(file, offset); return (result != 0) ? offset : -1; } case RW_SEEK_CUR: { int position = offset + PHYSFS_tell(file); auto result = PHYSFS_seek(file, position); return (result != 0) ? position : -1; } case RW_SEEK_END: { int position = PHYSFS_fileLength(file) - offset; auto result = PHYSFS_seek(file, position); return (result != 0) ? position : -1; } } } return -1; } Sint64 CSDLFileWrapper::SDLSize(SDL_RWops *context) { return -1; // Not needed for now } size_t CSDLFileWrapper::SDLRead(SDL_RWops *context, void *ptr, size_t size, size_t maxnum) { if (CheckSDLContext(context)) { PHYSFS_File *file = static_cast(context->hidden.unknown.data1); SDL_memset(ptr, 0, size * maxnum); auto result = PHYSFS_read(file, ptr, size, maxnum); return (result >= 0) ? result : 0; } return 0; } size_t CSDLFileWrapper::SDLWrite(SDL_RWops *context, const void *ptr, size_t size, size_t num) { assert(!!"Writing to CSDLFileWrapper is currently not supported"); return 0; }