2008-01-09 19:21:31 +02:00
|
|
|
#include "../stdafx.h"
|
2009-04-24 00:09:10 +03:00
|
|
|
#include <fstream>
|
2007-07-07 07:30:36 +03:00
|
|
|
#include "CSndHandler.h"
|
2009-04-24 00:09:10 +03:00
|
|
|
#include <boost/iostreams/device/mapped_file.hpp>
|
2009-10-11 19:05:40 +03:00
|
|
|
#include <SDL_endian.h>
|
2007-07-07 07:30:36 +03:00
|
|
|
|
2009-04-15 17:03:31 +03:00
|
|
|
/*
|
|
|
|
* CSndHandler.cpp, part of VCMI engine
|
|
|
|
*
|
|
|
|
* Authors: listed in file AUTHORS in main folder
|
|
|
|
*
|
|
|
|
* License: GNU General Public License v2.0 or later
|
|
|
|
* Full text of license available in license.txt file, in main folder
|
|
|
|
*
|
|
|
|
*/
|
2007-07-07 07:30:36 +03:00
|
|
|
|
2011-08-07 22:14:46 +03:00
|
|
|
/* Media file are kept in container files. We map these files in
|
|
|
|
* memory, parse them and create an index of them to easily retrieve
|
|
|
|
* the data+size of the objects. */
|
|
|
|
|
2009-06-19 07:27:12 +03:00
|
|
|
CMediaHandler::~CMediaHandler()
|
2007-07-07 07:30:36 +03:00
|
|
|
{
|
2011-08-07 22:14:46 +03:00
|
|
|
std::vector<boost::iostreams::mapped_file_source *>::iterator it;
|
|
|
|
|
2007-07-07 07:30:36 +03:00
|
|
|
entries.clear();
|
2008-03-20 10:51:53 +02:00
|
|
|
fimap.clear();
|
2011-08-07 22:14:46 +03:00
|
|
|
|
|
|
|
for (it=mfiles.begin() ; it < mfiles.end(); it++ ) {
|
|
|
|
(*it)->close();
|
|
|
|
delete *it;
|
|
|
|
}
|
2007-07-07 07:30:36 +03:00
|
|
|
}
|
2009-04-22 21:28:01 +03:00
|
|
|
|
2011-08-27 01:52:02 +03:00
|
|
|
boost::iostreams::mapped_file_source *CMediaHandler::add_file(std::string fname, bool important /*= true*/)
|
2007-07-07 07:30:36 +03:00
|
|
|
{
|
2011-08-07 22:14:46 +03:00
|
|
|
boost::iostreams::mapped_file_source *mfile;
|
|
|
|
|
2009-06-10 23:48:55 +03:00
|
|
|
try //c-tor of mapped_file_source throws exception on failure
|
|
|
|
{
|
|
|
|
mfile = new boost::iostreams::mapped_file_source(fname);
|
2011-08-27 01:52:02 +03:00
|
|
|
|
|
|
|
if (!mfile->is_open()) //just in case
|
|
|
|
throw std::runtime_error("Cannot open " + fname + ": !mfile->is_open()");
|
|
|
|
}
|
|
|
|
catch(std::exception &e)
|
2009-02-14 17:00:29 +02:00
|
|
|
{
|
2011-08-27 01:52:02 +03:00
|
|
|
if(important)
|
|
|
|
tlog1 << "Cannot open " << fname << ": " << e.what() << std::endl;
|
|
|
|
throw;
|
2009-02-14 17:00:29 +02:00
|
|
|
}
|
2011-08-27 01:52:02 +03:00
|
|
|
|
|
|
|
|
|
|
|
mfiles.push_back(mfile);
|
|
|
|
return mfile;
|
2007-07-07 07:30:36 +03:00
|
|
|
}
|
2009-04-22 21:28:01 +03:00
|
|
|
|
2009-06-19 07:27:12 +03:00
|
|
|
void CMediaHandler::extract(int index, std::string dstfile) //saves selected file
|
2007-07-07 07:30:36 +03:00
|
|
|
{
|
|
|
|
std::ofstream out(dstfile.c_str(),std::ios_base::binary);
|
2011-08-07 22:14:46 +03:00
|
|
|
Entry &entry = entries[index];
|
|
|
|
|
|
|
|
out.write(entry.data, entry.size);
|
2007-07-07 07:30:36 +03:00
|
|
|
out.close();
|
|
|
|
}
|
2009-04-22 21:28:01 +03:00
|
|
|
|
2009-06-19 07:27:12 +03:00
|
|
|
void CMediaHandler::extract(std::string srcfile, std::string dstfile, bool caseSens) //saves selected file
|
2007-07-07 07:30:36 +03:00
|
|
|
{
|
2011-02-01 20:10:43 +02:00
|
|
|
srcfile.erase(srcfile.find_last_of('.'));
|
2007-07-07 07:30:36 +03:00
|
|
|
if (caseSens)
|
|
|
|
{
|
2008-12-21 21:17:35 +02:00
|
|
|
for (size_t i=0;i<entries.size();++i)
|
2007-07-07 07:30:36 +03:00
|
|
|
{
|
|
|
|
if (entries[i].name==srcfile)
|
|
|
|
extract(i,dstfile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::transform(srcfile.begin(),srcfile.end(),srcfile.begin(),tolower);
|
2008-12-21 21:17:35 +02:00
|
|
|
for (size_t i=0;i<entries.size();++i)
|
2007-07-07 07:30:36 +03:00
|
|
|
{
|
|
|
|
if (entries[i].name==srcfile)
|
|
|
|
{
|
|
|
|
std::string por = entries[i].name;
|
|
|
|
std::transform(por.begin(),por.end(),por.begin(),tolower);
|
|
|
|
if (por==srcfile)
|
|
|
|
extract(i,dstfile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-04-22 21:28:01 +03:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
// unused and not sure what it's supposed to do
|
2009-06-19 07:27:12 +03:00
|
|
|
MemberFile CMediaHandler::getFile(std::string name)
|
2007-07-31 08:24:10 +03:00
|
|
|
{
|
2008-07-16 21:26:15 +03:00
|
|
|
MemberFile ret;
|
2007-07-31 08:24:10 +03:00
|
|
|
std::transform(name.begin(),name.end(),name.begin(),tolower);
|
2008-12-21 21:17:35 +02:00
|
|
|
for (size_t i=0;i<entries.size();++i)
|
2007-07-31 08:24:10 +03:00
|
|
|
{
|
|
|
|
if (entries[i].name==name)
|
|
|
|
{
|
|
|
|
std::string por = entries[i].name;
|
|
|
|
std::transform(por.begin(),por.end(),por.begin(),tolower);
|
|
|
|
if (por==name)
|
|
|
|
{
|
|
|
|
ret.length=entries[i].size;
|
|
|
|
file.seekg(entries[i].offset,std::ios_base::beg);
|
|
|
|
ret.ifs=&file;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2009-04-22 21:28:01 +03:00
|
|
|
#endif
|
|
|
|
|
2009-06-19 07:27:12 +03:00
|
|
|
const char * CMediaHandler::extract (int index, int & size)
|
2007-07-07 07:30:36 +03:00
|
|
|
{
|
2011-08-07 22:14:46 +03:00
|
|
|
Entry &entry = entries[index];
|
2009-04-22 21:28:01 +03:00
|
|
|
|
2011-08-07 22:14:46 +03:00
|
|
|
size = entry.size;
|
|
|
|
return entry.data;
|
2007-07-31 08:24:10 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 07:27:12 +03:00
|
|
|
const char * CMediaHandler::extract (std::string srcName, int &size)
|
2008-03-20 10:51:53 +02:00
|
|
|
{
|
|
|
|
int index;
|
2011-01-17 18:07:08 +02:00
|
|
|
srcName.erase(srcName.find_last_of('.'));
|
2011-01-28 04:33:26 +02:00
|
|
|
|
2008-03-20 10:51:53 +02:00
|
|
|
std::map<std::string, int>::iterator fit;
|
|
|
|
if ((fit = fimap.find(srcName)) != fimap.end())
|
|
|
|
{
|
|
|
|
index = fit->second;
|
|
|
|
return this->extract(index, size);
|
|
|
|
}
|
|
|
|
size = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-08-27 01:52:02 +03:00
|
|
|
void CSndHandler::add_file(std::string fname, bool important /*= true*/)
|
2007-07-31 08:24:10 +03:00
|
|
|
{
|
2011-08-08 09:28:18 +03:00
|
|
|
boost::iostreams::mapped_file_source *mfile = NULL;
|
|
|
|
try
|
|
|
|
{
|
2011-08-27 01:52:02 +03:00
|
|
|
mfile = CMediaHandler::add_file(fname, important);
|
2011-08-08 09:28:18 +03:00
|
|
|
}
|
|
|
|
catch(...)
|
2011-08-27 01:52:02 +03:00
|
|
|
{
|
2011-08-07 22:14:46 +03:00
|
|
|
return;
|
2011-08-27 01:52:02 +03:00
|
|
|
}
|
2011-08-07 22:14:46 +03:00
|
|
|
|
|
|
|
const char *data = mfile->data();
|
2009-10-11 19:05:40 +03:00
|
|
|
unsigned int numFiles = SDL_SwapLE32(*(Uint32 *)&data[0]);
|
|
|
|
struct soundEntry *se = (struct soundEntry *)&data[4];
|
2009-06-19 07:27:12 +03:00
|
|
|
|
2009-10-11 19:05:40 +03:00
|
|
|
for (unsigned int i=0; i<numFiles; i++, se++)
|
2007-07-31 08:24:10 +03:00
|
|
|
{
|
|
|
|
Entry entry;
|
2009-06-19 07:27:12 +03:00
|
|
|
|
2009-10-11 19:05:40 +03:00
|
|
|
entry.name = se->filename;
|
|
|
|
entry.offset = SDL_SwapLE32(se->offset);
|
|
|
|
entry.size = SDL_SwapLE32(se->size);
|
2011-08-07 22:14:46 +03:00
|
|
|
entry.data = mfile->data() + entry.offset;
|
2009-06-19 07:27:12 +03:00
|
|
|
|
2007-07-31 08:24:10 +03:00
|
|
|
entries.push_back(entry);
|
2009-06-19 07:27:12 +03:00
|
|
|
fimap[entry.name] = i;
|
2007-07-31 08:24:10 +03:00
|
|
|
}
|
|
|
|
}
|
2009-06-19 07:27:12 +03:00
|
|
|
|
2011-08-07 22:14:46 +03:00
|
|
|
void CVidHandler::add_file(std::string fname)
|
2007-07-31 08:24:10 +03:00
|
|
|
{
|
2011-08-27 01:52:02 +03:00
|
|
|
boost::iostreams::mapped_file_source *mfile = NULL;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
mfile = CMediaHandler::add_file(fname);
|
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
2011-08-07 22:14:46 +03:00
|
|
|
return;
|
2011-08-27 01:52:02 +03:00
|
|
|
}
|
2011-08-07 22:14:46 +03:00
|
|
|
|
2011-05-26 04:03:35 +03:00
|
|
|
if(mfile->size() < 48)
|
|
|
|
{
|
|
|
|
tlog1 << fname << " doesn't contain needed data!\n";
|
|
|
|
return;
|
|
|
|
}
|
2009-06-19 07:27:12 +03:00
|
|
|
const unsigned char *data = (const unsigned char *)mfile->data();
|
2009-10-11 19:05:40 +03:00
|
|
|
unsigned int numFiles = SDL_SwapLE32(*(Uint32 *)&data[0]);
|
|
|
|
struct videoEntry *ve = (struct videoEntry *)&data[4];
|
2009-06-19 07:27:12 +03:00
|
|
|
|
2009-10-11 19:05:40 +03:00
|
|
|
for (unsigned int i=0; i<numFiles; i++, ve++)
|
2007-07-31 08:24:10 +03:00
|
|
|
{
|
2009-06-19 07:27:12 +03:00
|
|
|
Entry entry;
|
|
|
|
|
2009-10-11 19:05:40 +03:00
|
|
|
entry.name = ve->filename;
|
|
|
|
entry.offset = SDL_SwapLE32(ve->offset);
|
2011-01-17 18:07:08 +02:00
|
|
|
entry.name.erase(entry.name.find_last_of('.'));
|
2009-06-19 07:27:12 +03:00
|
|
|
|
|
|
|
// There is no size, so check where the next file is
|
|
|
|
if (i == numFiles - 1) {
|
|
|
|
entry.size = mfile->size() - entry.offset;
|
|
|
|
} else {
|
2009-10-11 19:05:40 +03:00
|
|
|
struct videoEntry *ve_next = ve+1;
|
|
|
|
|
|
|
|
entry.size = SDL_SwapLE32(ve_next->offset) - entry.offset;
|
|
|
|
}
|
2011-08-07 22:14:46 +03:00
|
|
|
entry.data = mfile->data() + entry.offset;
|
2009-06-19 07:27:12 +03:00
|
|
|
|
|
|
|
entries.push_back(entry);
|
|
|
|
fimap[entry.name] = i;
|
2007-07-31 08:24:10 +03:00
|
|
|
}
|
|
|
|
}
|