Loading Resources From PhysFS
From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Written for CEGUI 0.7
Works with versions 0.7.x (obsolete)
To load GUI resources via icculus' PhysFS [1] file system abstraction library, use the following ResourceProvider instead of the default. This was tested with CEGUI 0.7.7 and works with Linux and Windows.
File CEGUIPhysFSResourceProvider.h:
/*********************************************************************** filename: CEGUIPhysFSResourceProvider.h created: 8/7/2004 author: James '_mental_' O'Sullivan with minor changes by Marek 'Wansti' Moeckel purpose: Load GUI resources via PhysFS *************************************************************************/ /*************************************************************************** * Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. ***************************************************************************/ #ifndef _CEGUIPhysFSResourceProvider_h_ #define _CEGUIPhysFSResourceProvider_h_ #include "CEGUI/CEGUIBase.h" #include "CEGUI/CEGUIResourceProvider.h" #include <map> #if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable : 4251) #endif // Start of CEGUI namespace section namespace CEGUI { //! CEGUI Resource Provider for the PhysFS File System. /*! This is an auxiliary class (based on the DefaultResourceProvider from CEGUI) * that provides file access via PhysFS. This is used to load GUI resources * via PhysFS. * Check the CEGUI documentation for further information on Resource Providers. * PhysFS must be initialized before this class can be used! Currently, the * Resource Provider blindly assumes that this has been done which might cause * errors. */ class PhysFSResourceProvider : public ResourceProvider { public: /************************************************************************* Construction and Destruction *************************************************************************/ PhysFSResourceProvider() {} ~PhysFSResourceProvider(void) {} /*! \brief Set the directory associated with a given resource group identifier. \param resourceGroup The resource group identifier whose directory is to be set. \param directory The directory to be associated with resource group identifier \a resourceGroup \return Nothing. */ void setResourceGroupDirectory(const String& resourceGroup, const String& directory); /*! \brief Return the directory associated with the specified resource group identifier. \param resourceGroup The resource group identifier for which the associated directory is to be returned. \return String object describing the directory currently associated with resource group identifier \a resourceGroup. \note This member is not defined as being const because it may cause creation of an 'empty' directory specification for the resourceGroup if the resourceGroup has not previously been accessed. */ const String& getResourceGroupDirectory(const String& resourceGroup); /*! \brief clears any currently set directory for the specified resource group identifier. \param resourceGroup The resource group identifier for which the associated directory is to be cleared. */ void clearResourceGroupDirectory(const String& resourceGroup); void loadRawDataContainer(const String& filename, RawDataContainer& output, const String& resourceGroup); void unloadRawDataContainer(RawDataContainer& data); size_t getResourceGroupFileNames(std::vector<String>& out_vec, const String& file_pattern, const String& resource_group); protected: /*! \brief Return the final path and filename, taking into account the given resource group identifier that should be used when attempting to load the data. */ String getFinalFilename(const String& filename, const String& resourceGroup) const; typedef std::map<String, String, String::FastLessCompare> ResourceGroupMap; ResourceGroupMap d_resourceGroups; }; } // End of CEGUI namespace section #if defined(_MSC_VER) # pragma warning(pop) #endif #endif // end of guard _CEGUIPhysFSResourceProvider_h_
File CEGUIPhysFSResourceProvider.cpp
/*********************************************************************** filename: CEGUIPhysFSResourceProvider.cpp created: 8/7/2004 author: James '_mental_' O'Sullivan with minor changes by Marek 'Wansti' Moeckel *************************************************************************/ /*************************************************************************** * Copyright (C) 2004 - 2010 Paul D Turner & The CEGUI Development Team * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. ***************************************************************************/ #include "CEGUIPhysFSResourceProvider.h" #include "CEGUI/CEGUIExceptions.h" #include <stdio.h> #include <physfs.h> #if defined(__WIN32__) || defined(_WIN32) # include <io.h> # include <windows.h> # include <string> //----------------------------------------------------------------------------// std::wstring Utf8ToUtf16(const std::string& utf8text) { const int textLen = MultiByteToWideChar(CP_UTF8, 0, utf8text.c_str(), utf8text.size() + 1, 0, 0); if (textLen == 0) CEGUI_THROW(CEGUI::InvalidRequestException( "Utf8ToUtf16 - MultiByteToWideChar failed")); std::wstring wideStr(textLen, 0); MultiByteToWideChar(CP_UTF8, 0, utf8text.c_str(), utf8text.size() + 1, &wideStr[0], wideStr.size()); return wideStr; } //----------------------------------------------------------------------------// CEGUI::String Utf16ToString(const wchar_t* const utf16text) { const int len = WideCharToMultiByte(CP_UTF8, 0, utf16text, -1, 0, 0, 0, 0); if (!len) CEGUI_THROW(CEGUI::InvalidRequestException( "Utf16ToUtf8 - WideCharToMultiByte failed")); CEGUI::utf8* buff = new CEGUI::utf8[len + 1]; WideCharToMultiByte(CP_UTF8, 0, utf16text, -1, reinterpret_cast<char*>(buff), len, 0, 0); const CEGUI::String result(buff); delete[] buff; return result; } //----------------------------------------------------------------------------// #else # include <sys/types.h> # include <sys/stat.h> # include <dirent.h> # include <fnmatch.h> #endif // Start of CEGUI namespace section namespace CEGUI { //----------------------------------------------------------------------------// void PhysFSResourceProvider::loadRawDataContainer(const String& filename, RawDataContainer& output, const String& resourceGroup) { // Make sure PhysFS has been initialized before this point! const String final_filename(getFinalFilename(filename, resourceGroup)); if (!PHYSFS_exists(final_filename.c_str())) CEGUI_THROW(InvalidRequestException("PhysFSResourceProvider::load: " "Filename supplied for data loading must be valid")); PHYSFS_file* file = PHYSFS_openRead(final_filename.c_str()); if (file == NULL) CEGUI_THROW(InvalidRequestException("PhysFSResourceProvider::load: " + final_filename + " does not exist. " + PHYSFS_getLastError())); const size_t size = PHYSFS_fileLength(file); unsigned char* const buffer = new unsigned char[size]; const size_t size_read = PHYSFS_read(file, buffer, 1, size); PHYSFS_close(file); if (size_read != size) { delete[] buffer; CEGUI_THROW(GenericException( "PhysFSResourceProvider::loadRawDataContainer: " "A problem occurred while reading file: " + final_filename)); } output.setData(buffer); output.setSize(size); } //----------------------------------------------------------------------------// void PhysFSResourceProvider::unloadRawDataContainer(RawDataContainer& data) { uint8* const ptr = data.getDataPtr(); delete[] ptr; data.setData(0); data.setSize(0); } //----------------------------------------------------------------------------// void PhysFSResourceProvider::setResourceGroupDirectory( const String& resourceGroup, const String& directory) { if (directory.length() == 0) return; #if defined(_WIN32) || defined(__WIN32__) // while we rarely use the unportable '\', the user may have const String separators("\\/"); #else const String separators("/"); #endif if (String::npos == separators.find(directory[directory.length() - 1])) d_resourceGroups[resourceGroup] = directory + '/'; else d_resourceGroups[resourceGroup] = directory; } //----------------------------------------------------------------------------// const String& PhysFSResourceProvider::getResourceGroupDirectory( const String& resourceGroup) { return d_resourceGroups[resourceGroup]; } //----------------------------------------------------------------------------// void PhysFSResourceProvider::clearResourceGroupDirectory( const String& resourceGroup) { ResourceGroupMap::iterator iter = d_resourceGroups.find(resourceGroup); if (iter != d_resourceGroups.end()) d_resourceGroups.erase(iter); } //----------------------------------------------------------------------------// String PhysFSResourceProvider::getFinalFilename( const String& filename, const String& resourceGroup) const { String final_filename; // look up resource group directory ResourceGroupMap::const_iterator iter = d_resourceGroups.find(resourceGroup.empty() ? d_defaultResourceGroup : resourceGroup); // if there was an entry for this group, use it's directory as the // first part of the filename if (iter != d_resourceGroups.end()) final_filename = (*iter).second; // append the filename part that we were passed final_filename += filename; // return result return final_filename; } //----------------------------------------------------------------------------// size_t PhysFSResourceProvider::getResourceGroupFileNames( std::vector<String>& out_vec, const String& file_pattern, const String& resource_group) { // look-up resource group name ResourceGroupMap::const_iterator iter = d_resourceGroups.find(resource_group.empty() ? d_defaultResourceGroup : resource_group); // get directory that's set for the resource group const String dir_name( iter != d_resourceGroups.end() ? (*iter).second : "./"); size_t entries = 0; // Win32 code. #if defined(__WIN32__) || defined(_WIN32) intptr_t f; struct _wfinddata_t fd; if ((f = _wfindfirst(Utf8ToUtf16((dir_name + file_pattern).c_str()).c_str(), &fd)) != -1) { do { if ((fd.attrib & _A_SUBDIR)) continue; out_vec.push_back(Utf16ToString(fd.name)); ++entries; } while (_wfindnext(f, &fd) == 0); _findclose(f); } // Everybody else #else DIR* dirp; if ((dirp = opendir(dir_name.c_str()))) { struct dirent* dp; while ((dp = readdir(dirp))) { const String filename(dir_name + dp->d_name); struct stat s; if ((stat(filename.c_str(), &s) == 0) && S_ISREG(s.st_mode) && (fnmatch(file_pattern.c_str(), dp->d_name, 0) == 0)) { out_vec.push_back(dp->d_name); ++entries; } } closedir(dirp); } #endif return entries; } //----------------------------------------------------------------------------// } // End of CEGUI namespace section
In your main code, initialize CEGUI with your custom Resource Provider. Load resources as usual.
#include "CEGUIPhysFSResourceProvider.h" void Gui::init() { OpenGLRenderer& myRenderer = OpenGLRenderer::create(); PhysFSResourceProvider* rp = new PhysFSResourceProvider(); System::create(myRenderer, static_cast<ResourceProvider*>(rp), NULL, NULL, NULL, "", "log.txt"); //set Resource Group directories and load data //... }