Port BSAFile to istream, remove OGRE bsa resource system

c++11
scrawl 10 years ago
parent 1124343e0d
commit d4dff6ed55

@ -570,10 +570,10 @@ if(WIN32)
endif(WIN32) endif(WIN32)
# Extern # Extern
add_subdirectory (extern/shiny) #add_subdirectory (extern/shiny)
add_subdirectory (extern/ogre-ffmpeg-videoplayer) #add_subdirectory (extern/ogre-ffmpeg-videoplayer)
add_subdirectory (extern/oics) #add_subdirectory (extern/oics)
add_subdirectory (extern/sdl4ogre) #add_subdirectory (extern/sdl4ogre)
# Components # Components
add_subdirectory (components) add_subdirectory (components)

@ -79,7 +79,7 @@ IF(NOT WIN32 AND NOT APPLE)
ENDIF() ENDIF()
add_component_dir (files add_component_dir (files
linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager
constrainedfiledatastream lowlevelfile constrainedfiledatastream lowlevelfile constrainedfilestream
) )
add_component_dir (compiler add_component_dir (compiler

@ -1,385 +0,0 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008-2010 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.sourceforge.net/
This file (cpp_bsaarchive.cpp) is part of the OpenMW package.
OpenMW is distributed as free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 3, as published by the Free Software Foundation.
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
version 3 along with this program. If not, see
http://www.gnu.org/licenses/ .
*/
#include "bsa_archive.hpp"
#include <boost/filesystem.hpp>
#include <OgreFileSystem.h>
#include <OgreArchive.h>
#include <OgreArchiveFactory.h>
#include <OgreArchiveManager.h>
#include <OgreResourceGroupManager.h>
#include "bsa_file.hpp"
#include "../files/constrainedfiledatastream.hpp"
using namespace Ogre;
static bool fsstrict = false;
static char strict_normalize_char(char ch)
{
return ch == '\\' ? '/' : ch;
}
static char nonstrict_normalize_char(char ch)
{
return ch == '\\' ? '/' : std::tolower(ch,std::locale::classic());
}
template<typename T1, typename T2>
static std::string normalize_path(T1 begin, T2 end)
{
std::string normalized;
normalized.reserve(std::distance(begin, end));
char (*normalize_char)(char) = fsstrict ? &strict_normalize_char : &nonstrict_normalize_char;
std::transform(begin, end, std::back_inserter(normalized), normalize_char);
return normalized;
}
/// An OGRE Archive wrapping a BSAFile archive
class DirArchive: public Ogre::Archive
{
typedef std::map <std::string, std::string> index;
index mIndex;
index::const_iterator lookup_filename (std::string const & filename) const
{
std::string normalized = normalize_path (filename.begin (), filename.end ());
return mIndex.find (normalized);
}
public:
DirArchive(const String& name)
: Archive(name, "Dir")
{
typedef boost::filesystem::recursive_directory_iterator directory_iterator;
directory_iterator end;
size_t prefix = name.size ();
if (name.size () > 0 && name [prefix - 1] != '\\' && name [prefix - 1] != '/')
++prefix;
for (directory_iterator i (name); i != end; ++i)
{
if(boost::filesystem::is_directory (*i))
continue;
std::string proper = i->path ().string ();
std::string searchable = normalize_path (proper.begin () + prefix, proper.end ());
mIndex.insert (std::make_pair (searchable, proper));
}
}
bool isCaseSensitive() const { return fsstrict; }
// The archive is loaded in the constructor, and never unloaded.
void load() {}
void unload() {}
DataStreamPtr open(const String& filename, bool readonly = true) const
{
index::const_iterator i = lookup_filename (filename);
if (i == mIndex.end ())
{
std::ostringstream os;
os << "The file '" << filename << "' could not be found.";
throw std::runtime_error (os.str ());
}
return openConstrainedFileDataStream (i->second.c_str ());
}
StringVectorPtr list(bool recursive = true, bool dirs = false)
{
return find ("*", recursive, dirs);
}
FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false)
{
return findFileInfo ("*", recursive, dirs);
}
StringVectorPtr find(const String& pattern, bool recursive = true,
bool dirs = false)
{
std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end());
StringVectorPtr ptr = StringVectorPtr(new StringVector());
for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();++iter)
{
if(Ogre::StringUtil::match(iter->first, normalizedPattern) ||
(recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern)))
ptr->push_back(iter->first);
}
return ptr;
}
bool exists(const String& filename)
{
return lookup_filename(filename) != mIndex.end ();
}
time_t getModifiedTime(const String&) { return 0; }
FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true,
bool dirs = false) const
{
std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end());
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
index::const_iterator i = mIndex.find(normalizedPattern);
if(i != mIndex.end())
{
std::string::size_type pt = i->first.rfind('/');
if(pt == std::string::npos)
pt = 0;
FileInfo fi;
fi.archive = const_cast<DirArchive*>(this);
fi.path = i->first.substr(0, pt);
fi.filename = i->first.substr((i->first[pt]=='/') ? pt+1 : pt);
fi.compressedSize = fi.uncompressedSize = 0;
ptr->push_back(fi);
}
else
{
for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();++iter)
{
if(Ogre::StringUtil::match(iter->first, normalizedPattern) ||
(recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern)))
{
std::string::size_type pt = iter->first.rfind('/');
if(pt == std::string::npos)
pt = 0;
FileInfo fi;
fi.archive = const_cast<DirArchive*>(this);
fi.path = iter->first.substr(0, pt);
fi.filename = iter->first.substr((iter->first[pt]=='/') ? pt+1 : pt);
fi.compressedSize = fi.uncompressedSize = 0;
ptr->push_back(fi);
}
}
}
return ptr;
}
};
class BSAArchive : public Archive
{
Bsa::BSAFile arc;
static const char *extractFilename(const Bsa::BSAFile::FileStruct &entry)
{
return entry.name;
}
public:
BSAArchive(const String& name)
: Archive(name, "BSA")
{ arc.open(name); }
bool isCaseSensitive() const { return false; }
// The archive is loaded in the constructor, and never unloaded.
void load() {}
void unload() {}
DataStreamPtr open(const String& filename, bool readonly = true) const
{
// Get a non-const reference to arc. This is a hack and it's all
// OGRE's fault. You should NOT expect an open() command not to
// have any side effects on the archive, and hence this function
// should not have been declared const in the first place.
Bsa::BSAFile *narc = const_cast<Bsa::BSAFile*>(&arc);
// Open the file
return narc->getFile(filename.c_str());
}
bool exists(const String& filename) {
return arc.exists(filename.c_str());
}
time_t getModifiedTime(const String&) { return 0; }
// This is never called as far as I can see.
StringVectorPtr list(bool recursive = true, bool dirs = false)
{
return find ("*", recursive, dirs);
}
// Also never called.
FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false)
{
return findFileInfo ("*", recursive, dirs);
}
StringVectorPtr find(const String& pattern, bool recursive = true,
bool dirs = false)
{
std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end());
const Bsa::BSAFile::FileList &filelist = arc.getList();
StringVectorPtr ptr = StringVectorPtr(new StringVector());
for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();++iter)
{
std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name));
if(Ogre::StringUtil::match(ent, normalizedPattern) ||
(recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern)))
ptr->push_back(iter->name);
}
return ptr;
}
FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true,
bool dirs = false) const
{
std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end());
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
const Bsa::BSAFile::FileList &filelist = arc.getList();
for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();++iter)
{
std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name));
if(Ogre::StringUtil::match(ent, normalizedPattern) ||
(recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern)))
{
std::string::size_type pt = ent.rfind('/');
if(pt == std::string::npos)
pt = 0;
FileInfo fi;
fi.archive = const_cast<BSAArchive*>(this);
fi.path = std::string(iter->name, pt);
fi.filename = std::string(iter->name + ((ent[pt]=='/') ? pt+1 : pt));
fi.compressedSize = fi.uncompressedSize = iter->fileSize;
ptr->push_back(fi);
}
}
return ptr;
}
};
// An archive factory for BSA archives
class BSAArchiveFactory : public ArchiveFactory
{
public:
const String& getType() const
{
static String name = "BSA";
return name;
}
Archive *createInstance( const String& name )
{
return new BSAArchive(name);
}
virtual Archive* createInstance(const String& name, bool readOnly)
{
return new BSAArchive(name);
}
void destroyInstance( Archive* arch) { delete arch; }
};
class DirArchiveFactory : public ArchiveFactory
{
public:
const String& getType() const
{
static String name = "Dir";
return name;
}
Archive *createInstance( const String& name )
{
return new DirArchive(name);
}
virtual Archive* createInstance(const String& name, bool readOnly)
{
return new DirArchive(name);
}
void destroyInstance( Archive* arch) { delete arch; }
};
static bool init = false;
static bool init2 = false;
static void insertBSAFactory()
{
if(!init)
{
ArchiveManager::getSingleton().addArchiveFactory( new BSAArchiveFactory );
init = true;
}
}
static void insertDirFactory()
{
if(!init2)
{
ArchiveManager::getSingleton().addArchiveFactory( new DirArchiveFactory );
init2 = true;
}
}
namespace Bsa
{
// The function below is the only publicly exposed part of this file
void addBSA(const std::string& name, const std::string& group)
{
insertBSAFactory();
ResourceGroupManager::getSingleton().
addResourceLocation(name, "BSA", group, true);
}
void addDir(const std::string& name, const bool& fs, const std::string& group)
{
fsstrict = fs;
insertDirFactory();
ResourceGroupManager::getSingleton().
addResourceLocation(name, "Dir", group, true);
}
}

@ -1,40 +0,0 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008-2010 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.sourceforge.net/
This file (cpp_bsaarchive.h) is part of the OpenMW package.
OpenMW is distributed as free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 3, as published by the Free Software Foundation.
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
version 3 along with this program. If not, see
http://www.gnu.org/licenses/ .
*/
#include <string>
#include <algorithm>
#ifndef BSA_BSA_ARCHIVE_H
#define BSA_BSA_ARCHIVE_H
namespace Bsa
{
/// Add the given BSA file as an input archive in the Ogre resource
/// system.
void addBSA(const std::string& file, const std::string& group="General");
void addDir(const std::string& file, const bool& fs, const std::string& group="General");
}
#endif

@ -28,7 +28,7 @@
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
#include "../files/constrainedfiledatastream.hpp" #include "../files/constrainedfilestream.hpp"
using namespace std; using namespace std;
using namespace Bsa; using namespace Bsa;
@ -168,7 +168,7 @@ void BSAFile::open(const string &file)
readHeader(); readHeader();
} }
Ogre::DataStreamPtr BSAFile::getFile(const char *file) Files::IStreamPtr BSAFile::getFile(const char *file)
{ {
assert(file); assert(file);
int i = getIndex(file); int i = getIndex(file);
@ -176,5 +176,6 @@ Ogre::DataStreamPtr BSAFile::getFile(const char *file)
fail("File not found: " + string(file)); fail("File not found: " + string(file));
const FileStruct &fs = files[i]; const FileStruct &fs = files[i];
return openConstrainedFileDataStream (filename.c_str (), fs.offset, fs.fileSize);
return Files::openConstrainedFileStream (filename.c_str (), fs.offset, fs.fileSize);
} }

@ -32,6 +32,8 @@
#include <OgreDataStream.h> #include <OgreDataStream.h>
#include <components/files/constrainedfilestream.hpp>
namespace Bsa namespace Bsa
{ {
@ -116,7 +118,7 @@ public:
/** Open a file contained in the archive. Throws an exception if the /** Open a file contained in the archive. Throws an exception if the
file doesn't exist. file doesn't exist.
*/ */
Ogre::DataStreamPtr getFile(const char *file); Files::IStreamPtr getFile(const char *file);
/// Get a list of all files /// Get a list of all files
const FileList &getList() const const FileList &getList() const

@ -1,53 +0,0 @@
#include "resources.hpp"
#include <iostream>
#include <OgreResourceGroupManager.h>
#include <OgreStringConverter.h>
#include "bsa_archive.hpp"
void Bsa::registerResources (const Files::Collections& collections,
const std::vector<std::string>& archives, bool useLooseFiles, bool fsStrict)
{
const Files::PathContainer& dataDirs = collections.getPaths();
int i=0;
if (useLooseFiles)
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
{
// Last data dir has the highest priority
std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i, 8, '0');
Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName);
std::string dataDirectory = iter->string();
std::cout << "Data dir " << dataDirectory << std::endl;
Bsa::addDir(dataDirectory, fsStrict, groupName);
++i;
}
i=0;
for (std::vector<std::string>::const_iterator archive = archives.begin(); archive != archives.end(); ++archive)
{
if (collections.doesExist(*archive))
{
// Last BSA has the highest priority
std::string groupName = "DataBSA" + Ogre::StringConverter::toString(archives.size()-i, 8, '0');
Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName);
const std::string archivePath = collections.getPath(*archive).string();
std::cout << "Adding BSA archive " << archivePath << std::endl;
Bsa::addBSA(archivePath, groupName);
++i;
}
else
{
std::stringstream message;
message << "Archive '" << *archive << "' not found";
throw std::runtime_error(message.str());
}
}
}

@ -1,16 +0,0 @@
#ifndef BSA_BSA_RESOURCES_H
#define BSA_BSA_RESOURCES_H
#include <vector>
#include <string>
#include "../files/collections.hpp"
namespace Bsa
{
void registerResources (const Files::Collections& collections,
const std::vector<std::string>& archives, bool useLooseFiles, bool fsStrict);
///< Register resources directories and archives as OGRE resources groups
}
#endif

@ -3,6 +3,8 @@
#include <istream> #include <istream>
#include <boost/shared_ptr.hpp>
namespace Files namespace Files
{ {
@ -15,6 +17,14 @@ public:
virtual ~ConstrainedFileStream(); virtual ~ConstrainedFileStream();
}; };
typedef boost::shared_ptr<std::istream> IStreamPtr;
IStreamPtr openConstrainedFileStream(const char *filename,
size_t start=0, size_t length=0xFFFFFFFF)
{
return IStreamPtr(new ConstrainedFileStream(filename, start, length));
}
} }
#endif #endif

Loading…
Cancel
Save