|
|
|
/*==LICENSE==*
|
|
|
|
|
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools
|
|
|
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
|
|
|
|
|
|
|
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://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
Additional permissions under GNU GPL version 3 section 7
|
|
|
|
|
|
|
|
If you modify this Program, or any covered work, by linking or
|
|
|
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
|
|
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
|
|
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
|
|
|
(or a modified version of those libraries),
|
|
|
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
|
|
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
|
|
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
|
|
|
licensors of this Program grant you additional
|
|
|
|
permission to convey the resulting work. Corresponding Source for a
|
|
|
|
non-source form of such a combination shall include the source code for
|
|
|
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
|
|
|
work.
|
|
|
|
|
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
|
|
|
or by snail mail at:
|
|
|
|
Cyan Worlds, Inc.
|
|
|
|
14617 N Newport Hwy
|
|
|
|
Mead, WA 99021
|
|
|
|
|
|
|
|
*==LICENSE==*/
|
|
|
|
#include "hsUtils.h"
|
|
|
|
#include "hsFiles.h"
|
|
|
|
#include "plStreamSource.h"
|
|
|
|
#include "plSecureStream.h"
|
|
|
|
#include "plEncryptedStream.h"
|
|
|
|
#include "plFileUtils.h"
|
|
|
|
|
|
|
|
void ToLower(std::wstring& str)
|
|
|
|
{
|
|
|
|
for (unsigned i = 0; i < str.length(); i++)
|
|
|
|
str[i] = towlower(str[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReplaceSlashes(std::wstring& path, wchar replaceWith)
|
|
|
|
{
|
|
|
|
for (unsigned i = 0; i < path.length(); i++)
|
|
|
|
{
|
|
|
|
if ((path[i] == L'\\') || (path[i] == L'/'))
|
|
|
|
path[i] = replaceWith;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plStreamSource::ICleanup()
|
|
|
|
{
|
|
|
|
// loop through all the file data records, and delete the streams
|
|
|
|
std::map<std::wstring, fileData>::iterator curData;
|
|
|
|
for (curData = fFileData.begin(); curData != fFileData.end(); curData++)
|
|
|
|
{
|
|
|
|
curData->second.fStream->Close();
|
|
|
|
delete curData->second.fStream;
|
|
|
|
curData->second.fStream = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
fFileData.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void plStreamSource::IBreakupFilename(std::wstring filename, std::wstring& dir, std::wstring& ext)
|
|
|
|
{
|
|
|
|
// break the filename up into its parts
|
|
|
|
char* temp = hsWStringToString(filename.c_str());
|
|
|
|
std::string sFilename = temp;
|
|
|
|
std::string sExt = plFileUtils::GetFileExt(temp);
|
|
|
|
plFileUtils::StripFile(temp);
|
|
|
|
std::string sDir = temp;
|
|
|
|
delete [] temp;
|
|
|
|
|
|
|
|
if (sDir == sFilename) // no directory
|
|
|
|
sDir = "";
|
|
|
|
if (sDir != "")
|
|
|
|
if ((sDir[sDir.length()-1] == '/') || (sDir[sDir.length()-1] == '\\'))
|
|
|
|
sDir = sDir.substr(0, sDir.length() - 1); // trim the slash, if it has one
|
|
|
|
|
|
|
|
wchar_t* wTemp;
|
|
|
|
wTemp = hsStringToWString(sDir.c_str());
|
|
|
|
dir = wTemp;
|
|
|
|
delete [] wTemp;
|
|
|
|
wTemp = hsStringToWString(sExt.c_str());
|
|
|
|
ext = wTemp;
|
|
|
|
delete [] wTemp;
|
|
|
|
}
|
|
|
|
|
|
|
|
hsStream* plStreamSource::GetFile(std::wstring filename)
|
|
|
|
{
|
|
|
|
ToLower(filename);
|
|
|
|
ReplaceSlashes(filename, L'/');
|
|
|
|
|
|
|
|
if (fFileData.find(filename) == fFileData.end())
|
|
|
|
{
|
|
|
|
#ifndef PLASMA_EXTERNAL_RELEASE
|
|
|
|
// internal releases can pull from disk
|
|
|
|
char* temp = hsWStringToString(filename.c_str());
|
|
|
|
std::string sFilename = temp;
|
|
|
|
delete [] temp;
|
|
|
|
|
|
|
|
if (plFileUtils::FileExists(sFilename.c_str()))
|
|
|
|
{
|
|
|
|
// file exists on disk, cache it
|
|
|
|
std::wstring dir, ext;
|
|
|
|
IBreakupFilename(filename, dir, ext);
|
|
|
|
fFileData[filename].fFilename = filename;
|
|
|
|
fFileData[filename].fDir = dir;
|
|
|
|
fFileData[filename].fExt = ext;
|
|
|
|
if (plSecureStream::IsSecureFile(sFilename.c_str()))
|
|
|
|
{
|
|
|
|
UInt32 encryptionKey[4];
|
|
|
|
plFileUtils::GetSecureEncryptionKey(sFilename.c_str(), encryptionKey, 4);
|
|
|
|
fFileData[filename].fStream = plSecureStream::OpenSecureFile(sFilename.c_str(), 0, encryptionKey);
|
|
|
|
}
|
|
|
|
else // otherwise it is an encrypted or plain stream, this call handles both
|
|
|
|
fFileData[filename].fStream = plEncryptedStream::OpenEncryptedFile(sFilename.c_str());
|
|
|
|
|
|
|
|
return fFileData[filename].fStream;
|
|
|
|
}
|
|
|
|
#endif // PLASMA_EXTERNAL_RELEASE
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
return fFileData[filename].fStream;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::wstring> plStreamSource::GetListOfNames(std::wstring dir, std::wstring ext)
|
|
|
|
{
|
|
|
|
ToLower(ext);
|
|
|
|
ToLower(dir);
|
|
|
|
ReplaceSlashes(dir, L'/');
|
|
|
|
|
|
|
|
if (ext[0] == L'.')
|
|
|
|
ext = ext.substr(1, ext.length()); // trim the dot, if it has one
|
|
|
|
if (dir != L"")
|
|
|
|
if ((dir[dir.length()-1] == L'/') || (dir[dir.length()-1] == L'\\'))
|
|
|
|
dir = dir.substr(0, dir.length() - 1); // trim the slash, if it has one
|
|
|
|
|
|
|
|
// loop through all the file data records, and create the list
|
|
|
|
std::vector<std::wstring> retVal;
|
|
|
|
std::map<std::wstring, fileData>::iterator curData;
|
|
|
|
for (curData = fFileData.begin(); curData != fFileData.end(); curData++)
|
|
|
|
{
|
|
|
|
if ((curData->second.fDir == dir.c_str()) && (curData->second.fExt == ext))
|
|
|
|
retVal.push_back(curData->second.fFilename);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef PLASMA_EXTERNAL_RELEASE
|
|
|
|
// in internal releases, we can use on-disk files if they exist
|
|
|
|
// Build the search string as "dir/*.ext"
|
|
|
|
std::wstring wSearchStr = dir + L"/*." + ext;
|
|
|
|
char* temp = hsWStringToString(wSearchStr.c_str());
|
|
|
|
std::string searchStr = temp;
|
|
|
|
delete [] temp;
|
|
|
|
|
|
|
|
hsFolderIterator folderIter(searchStr.c_str(), true);
|
|
|
|
while (folderIter.NextFile())
|
|
|
|
{
|
|
|
|
const char* filename = folderIter.GetFileName();
|
|
|
|
wchar_t* wTemp = hsStringToWString(filename);
|
|
|
|
std::wstring wFilename = dir + L"/" + wTemp;
|
|
|
|
delete [] wTemp;
|
|
|
|
ToLower(wFilename);
|
|
|
|
|
|
|
|
if (fFileData.find(wFilename) == fFileData.end()) // we haven't added it yet
|
|
|
|
retVal.push_back(wFilename);
|
|
|
|
}
|
|
|
|
#endif // PLASMA_EXTERNAL_RELEASE
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool plStreamSource::InsertFile(std::wstring filename, hsStream* stream)
|
|
|
|
{
|
|
|
|
ToLower(filename);
|
|
|
|
ReplaceSlashes(filename, L'/');
|
|
|
|
|
|
|
|
if (fFileData.find(filename) != fFileData.end())
|
|
|
|
return false; // duplicate entry, return failure
|
|
|
|
|
|
|
|
// break the filename up into its parts
|
|
|
|
std::wstring dir, ext;
|
|
|
|
IBreakupFilename(filename, dir, ext);
|
|
|
|
|
|
|
|
// copy the data over (takes ownership of the stream!)
|
|
|
|
fFileData[filename].fFilename = filename;
|
|
|
|
fFileData[filename].fDir = dir;
|
|
|
|
fFileData[filename].fExt = ext;
|
|
|
|
fFileData[filename].fStream = stream;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
plStreamSource* plStreamSource::GetInstance()
|
|
|
|
{
|
|
|
|
static plStreamSource source;
|
|
|
|
return &source;
|
|
|
|
}
|