colobot/colobot-base/common/resources/sdl_file_wrapper.cpp

175 lines
4.4 KiB
C++

/*
* 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 <physfs.h>
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<PHYSFS_File *>(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<PHYSFS_File *>(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<PHYSFS_File *>(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;
}