Fix crash related to TTF and PHYSFS

TTF fonts will be loaded to memory instead of file pointers

Added new class CSDLMemoryWrapper that loads data from PHYSFS into memory block
and closes file after. This closes issues #519, #708 and #619
dev-time-step
Krzysztof Dermont 2016-02-11 16:12:16 +01:00
parent b6faadca03
commit c780148b77
7 changed files with 132 additions and 9 deletions

View File

@ -98,6 +98,7 @@ set(BASE_SOURCES
common/resources/outputstreambuffer.cpp
common/resources/resourcemanager.cpp
common/resources/sdl_file_wrapper.cpp
common/resources/sdl_memory_wrapper.cpp
common/resources/sndfile_wrapper.cpp
common/restext.cpp
common/settings.cpp

View File

@ -114,6 +114,11 @@ std::unique_ptr<CSDLFileWrapper> CResourceManager::GetSDLFileHandler(const std::
return MakeUnique<CSDLFileWrapper>(CleanPath(filename));
}
std::unique_ptr<CSDLMemoryWrapper> CResourceManager::GetSDLMemoryHandler(const std::string &filename)
{
return MakeUnique<CSDLMemoryWrapper>(CleanPath(filename));
}
std::unique_ptr<CSNDFileWrapper> CResourceManager::GetSNDFileHandler(const std::string &filename)
{
return MakeUnique<CSNDFileWrapper>(CleanPath(filename));

View File

@ -20,6 +20,7 @@
#pragma once
#include "common/resources/sdl_file_wrapper.h"
#include "common/resources/sdl_memory_wrapper.h"
#include "common/resources/sndfile_wrapper.h"
#include <memory>
@ -41,6 +42,7 @@ public:
static std::string GetSaveLocation();
static std::unique_ptr<CSDLFileWrapper> GetSDLFileHandler(const std::string &filename);
static std::unique_ptr<CSDLMemoryWrapper> GetSDLMemoryHandler(const std::string &filename);
static std::unique_ptr<CSNDFileWrapper> GetSNDFileHandler(const std::string &filename);
//! Check if file exists

View File

@ -24,10 +24,6 @@
#include <physfs.h>
namespace
{
const Uint32 PHYSFS_RWOPS_TYPE = 0xc010b04f;
}
CSDLFileWrapper::CSDLFileWrapper(const std::string& filename)
: m_rwops(nullptr)
@ -52,7 +48,7 @@ CSDLFileWrapper::CSDLFileWrapper(const std::string& filename)
return;
}
m_rwops->type = PHYSFS_RWOPS_TYPE; //TODO: Documentation recommends to leave SDL_RWOPS_UNKNOWN here for application-defined RWops. Did that change in SDL2?
m_rwops->type = SDL_RWOPS_UNKNOWN;
m_rwops->hidden.unknown.data1 = file;
m_rwops->seek = SDLSeek;
m_rwops->read = SDLRead;
@ -109,7 +105,7 @@ int CSDLFileWrapper::SDLCloseWithFreeRW(SDL_RWops *context)
bool CSDLFileWrapper::CheckSDLContext(SDL_RWops *context)
{
if (context->type != PHYSFS_RWOPS_TYPE)
if (context->type != SDL_RWOPS_UNKNOWN)
{
SDL_SetError("Wrong kind of RWops");
return false;

View File

@ -0,0 +1,77 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2015, 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_memory_wrapper.h"
#include "common/logger.h"
#include <physfs.h>
CSDLMemoryWrapper::CSDLMemoryWrapper(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;
}
PHYSFS_sint64 length = PHYSFS_fileLength(file);
m_buffer = new char[length];
if (PHYSFS_read(file, m_buffer, 1, length) != length)
{
GetLogger()->Error("Unable to read data for \"%s\"\n", filename.c_str());
PHYSFS_close(file);
return;
}
PHYSFS_close(file);
m_rwops = SDL_RWFromMem(m_buffer, length);
if (m_rwops == nullptr)
{
GetLogger()->Error("Unable to allocate SDL_RWops for \"%s\"\n", filename.c_str());
return;
}
}
CSDLMemoryWrapper::~CSDLMemoryWrapper()
{
SDL_FreeRW(m_rwops);
delete []m_buffer;
}
SDL_RWops* CSDLMemoryWrapper::GetHandler()
{
return m_rwops;
}
bool CSDLMemoryWrapper::IsOpen() const
{
return m_rwops != nullptr;
}

View File

@ -0,0 +1,42 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2015, 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
*/
#pragma once
#include <string>
#include <SDL.h>
class CSDLMemoryWrapper
{
public:
CSDLMemoryWrapper(const std::string& filename);
~CSDLMemoryWrapper();
CSDLMemoryWrapper(const CSDLMemoryWrapper&) = delete;
CSDLMemoryWrapper& operator=(const CSDLMemoryWrapper&) = delete;
bool IsOpen() const;
SDL_RWops* GetHandler();
private:
SDL_RWops* m_rwops;
char *m_buffer;
};

View File

@ -60,11 +60,11 @@ struct MultisizeFont
*/
struct CachedFont
{
std::unique_ptr<CSDLFileWrapper> fontFile;
std::unique_ptr<CSDLMemoryWrapper> fontFile;
TTF_Font* font = nullptr;
std::map<UTF8Char, CharTexture> cache;
CachedFont(std::unique_ptr<CSDLFileWrapper> fontFile, int pointSize)
CachedFont(std::unique_ptr<CSDLMemoryWrapper> fontFile, int pointSize)
: fontFile(std::move(fontFile))
{
font = TTF_OpenFontRW(this->fontFile->GetHandler(), 0, pointSize);
@ -980,7 +980,7 @@ CachedFont* CText::GetOrOpenFont(FontType font, float size)
return m_lastCachedFont;
}
auto file = CResourceManager::GetSDLFileHandler(mf->fileName);
auto file = CResourceManager::GetSDLMemoryHandler(mf->fileName);
if (!file->IsOpen())
{
m_error = std::string("Unable to open file");