2
3
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-14 02:27:40 -04:00

CWE Directory Reorganization

Rearrange directory structure of CWE to be loosely equivalent to
the H'uru Plasma repository.

Part 1: Movement of directories and files.
This commit is contained in:
rarified
2021-05-15 12:49:46 -06:00
parent c3f4a640a3
commit 96903e8dca
4002 changed files with 159 additions and 644 deletions

View File

@ -0,0 +1,184 @@
/*==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 "hsFiles.h"
#include <string.h>
#include "hsUtils.h"
#include "hsExceptions.h"
#if HS_BUILD_FOR_MAC
#define kDirChar ':'
#elif HS_BUILD_FOR_WIN32
#define kDirChar '\\'
#else
#define kDirChar '/'
#endif
static const char* FindNameInPath(const char path[])
{
const char* name = ::strrchr(path, kDirChar);
if (name == nil)
name = path;
return name;
}
///////////////////////////////////////////////////////////////////////
#if !HS_BUILD_FOR_PS2
hsFile::hsFile() : fPathAndName(nil), fFILE(nil)
{
}
hsFile::hsFile(const char pathAndName[]) : fPathAndName(nil), fFILE(nil)
{
if (pathAndName)
fPathAndName = hsStrcpy(pathAndName);
}
hsFile::~hsFile()
{
this->SetPathAndName(nil);
}
const char* hsFile::GetPathAndName()
{
return fPathAndName;
}
void hsFile::SetPathAndName(const char pathAndName[])
{
this->Close();
if (fPathAndName)
{ delete[] fPathAndName;
fPathAndName = nil;
}
if (pathAndName)
fPathAndName = hsStrcpy(pathAndName);
}
const char* hsFile::GetName()
{
return FindNameInPath(this->GetPathAndName());
}
FILE* hsFile::OpenFILE(const char mode[], hsBool throwIfFailure)
{
this->Close();
// We call the virtual method here rather than using
// fPathAndName directly, allowing a subclass to construct
// the name if necessary
//
const char* name = this->GetPathAndName();
if (name)
fFILE = ::fopen(name, mode);
hsThrowIfTrue(throwIfFailure && fFILE == nil);
return fFILE;
}
hsStream* hsFile::OpenStream(const char mode[], hsBool throwIfFailure)
{
FILE* file = this->OpenFILE(mode, throwIfFailure);
if (file)
{ hsUNIXStream* stream = TRACKED_NEW hsUNIXStream;
stream->SetFILE(file);
return stream;
}
return nil;
}
void hsFile::Close()
{
if (fFILE)
{ int err = ::fflush(fFILE);
hsIfDebugMessage(err != 0, "fflush failed", err);
err = ::fclose(fFILE);
hsIfDebugMessage(err != 0, "fclose failed", err);
fFILE = nil;
}
}
#endif
///////////////////////////////////////////////////////////////////////
hsBool hsFolderIterator::NextFileSuffix(const char suffix[])
{
while (this->NextFile())
{ const char* fileSuffix = ::strrchr(this->GetFileName(), '.');
if (fileSuffix != nil && ::_stricmp(fileSuffix, suffix) == 0)
return true;
}
return false;
}
int hsFolderIterator::GetPathAndName(char pathandname[])
{
const char* name = this->GetFileName();
int pathLen = hsStrlen(fPath);
// add 1 for null terminator
int totalLen = pathLen + sizeof(kDirChar) + hsStrlen(name) + 1;
hsAssert(totalLen <= kFolderIterator_MaxPath, "Overrun kFolderIterator_MaxPath");
if (pathandname)
{ hsStrcpy(pathandname, fPath);
if (pathLen > 0 && pathandname[pathLen - 1] != kDirChar)
pathandname[pathLen++] = kDirChar;
hsStrcpy(pathandname + pathLen, name);
}
return totalLen;
}
FILE* hsFolderIterator::OpenFILE(const char mode[])
{
char fileName[kFolderIterator_MaxPath];
(void)this->GetPathAndName(fileName);
return ::fopen(fileName, mode);
}

View File

@ -0,0 +1,204 @@
/*==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==*/
#ifndef hsFiles_Defined
#define hsFiles_Defined
#include "hsStream.h"
#include <stdio.h>
#if HS_BUILD_FOR_UNIX
#include <limits.h>
#define kFolderIterator_MaxPath PATH_MAX
#include <unistd.h>
#define SetCurrentDirectory chdir
#elif !HS_BUILD_FOR_PS2
#define kFolderIterator_MaxPath _MAX_PATH
#else
#define kFolderIterator_MaxPath 255
#endif
#if HS_BUILD_FOR_MAC
#include <Files.h>
#include <Script.h>
#endif
#if HS_BUILD_FOR_WIN32
# define PATH_SEPARATOR '\\'
# define WPATH_SEPARATOR L'\\'
# define PATH_SEPARATOR_STR "\\"
# define WPATH_SEPARATOR_STR L"\\"
#elif HS_BUILD_FOR_UNIX
# define PATH_SEPARATOR '/'
# define WPATH_SEPARATOR L'/'
# define PATH_SEPARATOR_STR "/"
# define WPATH_SEPARATOR_STR L"/"
#endif
///////////////////////////////////////////////////////////////////////
#if !HS_BUILD_FOR_PS2
class hsFile {
hsFile& operator=(const hsFile&); // disallow assignment
protected:
char* fPathAndName;
FILE* fFILE;
public:
hsFile();
hsFile(const char pathAndName[]);
virtual ~hsFile();
const char* GetName();
virtual const char* GetPathAndName();
virtual void SetPathAndName(const char pathAndName[]);
virtual FILE* OpenFILE(const char mode[], hsBool throwIfFailure = false);
virtual hsStream* OpenStream(const char mode[], hsBool throwIfFailure = false);
virtual void Close(); // called automatically in the destructor
};
typedef hsFile hsUnixFile; // for compatibility
#if HS_BUILD_FOR_MAC
class hsMacFile : public hsFile {
enum {
kRefNum_Dirty,
kPathName_Dirty
};
FSSpec fSpec;
Int16 fRefNum;
UInt16 fFlags;
void SetSpecFromName();
void SetNameFromSpec();
public:
hsMacFile();
hsMacFile(const FSSpec* spec);
hsMacFile(const char pathAndName[]);
virtual ~hsMacFile();
const FSSpec* GetSpec() const { return &fSpec; }
void SetSpec(const FSSpec* spec);
hsBool Create(OSType creator, OSType fileType, ScriptCode scriptCode = smSystemScript);
hsBool OpenDataFork(SInt8 permission, Int16* refnum);
// Overrides
virtual const char* GetPathAndName();
virtual void SetPathAndName(const char pathAndName[]);
virtual hsStream* OpenStream(const char mode[], hsBool throwIfFailure = false);
virtual void Close();
};
typedef hsMacFile hsOSFile;
#else
typedef hsFile hsOSFile;
#endif
#endif // HS_BUILD_FOR_PS2
///////////////////////////////////////////////////////////////////////
class hsFolderIterator {
char fPath[kFolderIterator_MaxPath];
struct hsFolderIterator_Data* fData;
bool fCustomFilter;
public:
#ifdef HS_BUILD_FOR_WIN32
hsFolderIterator(const char path[] = nil, bool useCustomFilter=false);
#else
hsFolderIterator(const char path[] = nil, bool unused=true);
hsFolderIterator(const struct FSSpec* spec); // Alt constructor
#endif
virtual ~hsFolderIterator();
const char* GetPath() const { return fPath; }
void SetPath(const char path[]);
void Reset();
hsBool NextFile();
hsBool NextFileSuffix(const char suffix[]);
const char* GetFileName() const;
int GetPathAndName(char pathandname[] = nil);
hsBool IsDirectory( void ) const;
FILE* OpenFILE(const char mode[]);
#if HS_BUILD_FOR_MAC
void SetMacFolder(const char path[]);
void SetMacFolder(OSType folderType);
void SetMacFolder(Int16 vRefNum, Int32 dirID);
hsBool NextMacFile(OSType targetFileType, OSType targetCreator);
const struct FSSpec* GetMacSpec() const;
OSType GetMacFileType() const;
OSType GetMacCreator() const;
#elif HS_BUILD_FOR_WIN32
void SetWinSystemDir(const char subdir[]); // e.g. "Fonts"
void SetFileFilterStr(const char filterStr[]); // e.g. "*.*"
#endif
};
#ifdef HS_BUILD_FOR_WIN32
// only implemented on Win32 for now
class hsWFolderIterator {
wchar fPath[kFolderIterator_MaxPath];
struct hsWFolderIterator_Data* fData;
bool fCustomFilter;
public:
hsWFolderIterator(const wchar path[] = nil, bool useCustomFilter=false);
virtual ~hsWFolderIterator();
const wchar* GetPath() const { return fPath; }
void SetPath(const wchar path[]);
void Reset();
hsBool NextFile();
hsBool NextFileSuffix(const wchar suffix[]);
const wchar* GetFileName() const;
int GetPathAndName(wchar pathandname[] = nil);
hsBool IsDirectory( void ) const;
FILE* OpenFILE(const wchar mode[]);
void SetWinSystemDir(const wchar subdir[]); // e.g. "Fonts"
void SetFileFilterStr(const wchar filterStr[]); // e.g. "*.*"
};
#endif
#endif

View File

@ -0,0 +1,409 @@
/*==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 "hsFiles.h"
#include "hsUtils.h"
#include "hsMemory.h"
#if HS_BUILD_FOR_MAC
#include <Files.h>
#include <Folders.h>
#include <Errors.h>
///////////////////////////////////////////////////////////////////////////
hsMacFile::hsMacFile() : fFlags(kRefNum_Dirty)
{
fSpec.name[0] = 0;
}
hsMacFile::hsMacFile(const char pathAndName[]) : hsFile(pathAndName), fFlags(kRefNum_Dirty)
{
this->SetSpecFromName();
}
hsMacFile::hsMacFile(const FSSpec* spec) : fFlags(kRefNum_Dirty)
{
this->SetSpec(spec);
}
hsMacFile::~hsMacFile()
{
this->Close();
}
void hsMacFile::SetSpec(const FSSpec* spec)
{
if (spec)
fSpec = *spec;
else
fSpec.name[0] = 0;
fFlags |= kPathName_Dirty;
}
void hsMacFile::SetSpecFromName()
{
Str255 pstr;
if (fPathAndName == nil)
fSpec.name[0] = 0;
else
{ hsC2PString(fPathAndName, pstr);
::FSMakeFSSpec(0, 0, pstr, &fSpec);
}
}
void hsMacFile::SetNameFromSpec()
{
CInfoPBRec pb;
Str255 dirNameP;
char dirName[256], temp[256];
int err;
hsP2CString(fSpec.name, temp);
pb.dirInfo.ioNamePtr = dirNameP;
pb.dirInfo.ioVRefNum = fSpec.vRefNum;
pb.dirInfo.ioDrParID = fSpec.parID;
pb.dirInfo.ioFDirIndex = -1;
do {
pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
err = PBGetCatInfoSync(&pb);
hsThrowIfOSErr(err);
hsP2CString(dirNameP, dirName);
strcat(dirName,":");
strcat(dirName, temp);
strcpy(temp, dirName);
} while( pb.dirInfo.ioDrDirID != fsRtDirID);
hsAssert(fPathAndName == nil, "pathname should be nil");
fPathAndName = hsStrcpy(temp);
}
hsBool hsMacFile::Create(OSType creator, OSType fileType, ScriptCode scriptCode)
{
this->Close();
OSErr err;
(void)::FSpDelete(&fSpec);
err = ::FSpCreate(&fSpec, creator, fileType, scriptCode);
hsIfDebugMessage(err != 0, "FSpCreate failed", err);
return err == 0;
}
#define kFileNotFound_Err -43
hsBool hsMacFile::OpenDataFork(SInt8 perm, Int16* refnum)
{
this->Close();
OSErr err;
err = ::FSpOpenDF(&fSpec, perm, &fRefNum);
if (err == kFileNotFound_Err && (perm & fsWrPerm) && (perm & fsRdPerm) == 0)
{ if (this->Create('HdSp', '????'))
err = ::FSpOpenDF(&fSpec, perm, &fRefNum);
}
if (err == 0)
{ fFlags &= ~kRefNum_Dirty;
if (refnum)
*refnum = fRefNum;
return true;
}
return false;
}
const char* hsMacFile::GetPathAndName()
{
if (fFlags & kPathName_Dirty)
{ this->SetNameFromSpec();
fFlags &= ~kPathName_Dirty;
}
return fPathAndName;
}
void hsMacFile::SetPathAndName(const char pathAndName[])
{
this->hsFile::SetPathAndName(pathAndName);
this->SetSpecFromName();
}
hsStream* hsMacFile::OpenStream(const char mode[], hsBool throwIfFailure)
{
hsThrowIfNilParam(mode);
short refnum;
SInt8 perm = 0;
if (::strchr(mode, 'r'))
perm |= fsRdPerm;
if (::strchr(mode, 'w'))
perm |= fsWrPerm;
if (this->OpenDataFork(perm, &refnum))
{ hsFileStream* stream = TRACKED_NEW hsFileStream;
stream->SetFileRef(refnum);
return stream;
}
hsThrowIfTrue(throwIfFailure);
return nil;
}
void hsMacFile::Close()
{
if (fFlags & kRefNum_Dirty)
{ OSErr err = ::FSClose(fRefNum);
hsIfDebugMessage(err != 0, "FSClose failed", err);
fFlags &= ~kRefNum_Dirty;
}
this->hsFile::Close();
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
struct hsFolderIterator_Data {
FSSpec fSpec;
OSType fFileType;
OSType fCreator;
char fCName[_MAX_PATH];
Int16 fCurrIndex;
hsBool fValid;
};
hsFolderIterator::hsFolderIterator(const char path[])
{
fData = TRACKED_NEW hsFolderIterator_Data;
fData->fCurrIndex = 0;
fData->fValid = false;
#if HS_BUILD_FOR_WIN32
this->SetPath(path);
#else
this->SetMacFolder(path);
#endif
}
hsFolderIterator::hsFolderIterator(const struct FSSpec* spec) // Alt Constructor - pass in FSSpec from OpenDlg()
{
fData = TRACKED_NEW hsFolderIterator_Data;
fData->fCurrIndex = 0;
fData->fValid = false;
SetMacFolder(spec->vRefNum, spec->parID);
}
hsFolderIterator::~hsFolderIterator()
{
delete fData;
}
void hsFolderIterator::SetPath(const char path[])
{
fPath[0] = 0;
fData->fValid = false;
fData->fCurrIndex = 0;
if (path)
{
::strcpy(fPath, path);
}
}
///////////////////////////////////////////////////////////////////////////
void hsFolderIterator::SetMacFolder(OSType folderType)
{
fData->fCurrIndex = 0;
fData->fValid = ::FindFolder(kOnSystemDisk, folderType, false,
&fData->fSpec.vRefNum, &fData->fSpec.parID) == 0;
this->Reset();
}
void hsFolderIterator::SetMacFolder(Int16 vRefNum, Int32 dirID)
{
fData->fSpec.vRefNum = vRefNum;
fData->fSpec.parID = dirID;
fData->fCurrIndex = 0;
fData->fValid = true;
this->Reset();
}
void hsFolderIterator::SetMacFolder(const char path[])
{
char tmp[255];
FSSpec fileSpec;
OSErr err;
hsCPathToMacPath(&tmp[1], (char*)path);
tmp[0] = hsStrlen(&tmp[1]);
SetPath((char*)&tmp[1]);
err = FSMakeFSSpec(0, 0, (const unsigned char*)tmp, &fileSpec);
if(err == fnfErr)
{
HSDebugProc("XCmd directory does not exist.");
return;
}
hsAssert(err == noErr, "Error making file spec.");
// by now we should have the file spec for the given
// directory, however, the DirID is the PARENT directory,
// not the child directory. The following steps should
// give us the items we want.
CInfoPBRec pb;
pb.hFileInfo.ioVRefNum = fileSpec.vRefNum;
pb.hFileInfo.ioNamePtr = (StringPtr)fileSpec.name; // The name of the child directory.
pb.hFileInfo.ioDirID = fileSpec.parID; // The ID of the parent directory.
pb.hFileInfo.ioFDirIndex = 0;
pb.hFileInfo.ioCompletion = 0;
err = ::PBGetCatInfoSync(&pb);
hsAssert(err == noErr, "PBGetCatInfoSync() failure.");
fData->fSpec.vRefNum = fileSpec.vRefNum; // Volume reference
fData->fSpec.parID = pb.dirInfo.ioDrDirID; // child directory ID (Finally!)
fData->fCurrIndex = 0;
fData->fValid = true;
this->Reset();
}
///////////////////////////////////////////////////////////////////////////
void hsFolderIterator::Reset()
{
if (fData->fValid)
fData->fCurrIndex = 1;
#ifdef HS_DEBUGGING
else
hsAssert(fData->fCurrIndex == 0, "bad currindex");
#endif
}
hsBool hsFolderIterator::NextFile()
{
if (fData->fCurrIndex == 0)
return false;
CInfoPBRec pb;
do {
pb.hFileInfo.ioVRefNum = fData->fSpec.vRefNum;
pb.hFileInfo.ioNamePtr = (StringPtr)fData->fSpec.name;
pb.hFileInfo.ioDirID = fData->fSpec.parID;
pb.hFileInfo.ioFDirIndex = fData->fCurrIndex++;
OSErr err = ::PBGetCatInfoSync(&pb);
if (err)
{
fData->fCurrIndex = 0;
return false;
}
} while (pb.hFileInfo.ioFlAttrib & ioDirMask);
fData->fFileType = pb.hFileInfo.ioFlFndrInfo.fdType;
fData->fCreator = pb.hFileInfo.ioFlFndrInfo.fdCreator;
return true;
}
const char* hsFolderIterator::GetFileName() const
{
if (fData->fCurrIndex == 0)
throw "end of folder";
// Copy our filename (in pascal format) into a cstring and then return
HSMemory::BlockMove(&fData->fSpec.name[1], fData->fCName, fData->fSpec.name[0]);
fData->fCName[fData->fSpec.name[0]] = 0;
return fData->fCName;
}
////////////////////////////////////////////////////////////////////////////
hsBool hsFolderIterator::NextMacFile(OSType targetFileType, OSType targetCreator)
{
for (;;)
{ if (this->NextFile() == false)
return false;
if ((targetFileType == 0 || targetFileType == this->GetMacFileType()) &&
(targetCreator == 0 || targetCreator == this->GetMacCreator()))
return true;
}
}
const FSSpec* hsFolderIterator::GetMacSpec() const
{
if (fData->fCurrIndex == 0)
throw "end of folder";
return &fData->fSpec;
}
OSType hsFolderIterator::GetMacFileType() const
{
if (fData->fCurrIndex == 0)
throw "end of folder";
return fData->fFileType;
}
OSType hsFolderIterator::GetMacCreator() const
{
if (fData->fCurrIndex == 0)
throw "end of folder";
return fData->fCreator;
}
hsBool hsFolderIterator::IsDirectory( void ) const
{
hsAssert( false, "hsFolderIterator::IsDirectory() not defined on this platform!!!" );
return false;
}
#endif // HS_BUILD_FOR_MAC

View File

@ -0,0 +1,84 @@
/*==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 "hsFiles.h"
#if HS_BUILD_FOR_PS2
hsFolderIterator::hsFolderIterator(const char path[])
{
hsAssert(0,"No folder Interator defined for PS2 -- yet");
}
hsFolderIterator::~hsFolderIterator()
{
}
void hsFolderIterator::SetPath(const char path[])
{
}
///////////////////////////////////////////////////////////////////////////////
void hsFolderIterator::Reset()
{
}
hsBool hsFolderIterator::NextFile()
{
}
const char* hsFolderIterator::GetFileName() const
{
}
hsBool hsFolderIterator::IsDirectory( void ) const
{
hsAssert( false, "hsFolderIterator::IsDirectory() not defined on this platform!!!" );
return false;
}
#endif // HS_BUILD_FOR_PS2

View File

@ -0,0 +1,146 @@
/*==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 "hsFiles.h"
#if HS_BUILD_FOR_UNIX
#include <errno.h>
#include <dirent.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <glob.h>
#include "hsTemplates.h"
#include "plFileUtils.h"
#include "hsStlUtils.h"
struct hsFolderIterator_Data {
glob_t fGlobBuf;
bool fInited;
int fCnt;
hsFolderIterator_Data() : fInited(false), fCnt(0) {}
// ~hsFolderIterator_Data() { fInited=false; globfree(&fData->fGlobBuf); }
};
hsFolderIterator::hsFolderIterator(const char path[], bool)
{
fData = TRACKED_NEW hsFolderIterator_Data;
this->SetPath(path);
}
hsFolderIterator::~hsFolderIterator()
{
this->Reset();
delete fData;
}
void hsFolderIterator::SetPath(const char path[])
{
fPath[0] = 0;
if (path)
{
::strcpy(fPath, path);
}
this->Reset();
}
void hsFolderIterator::Reset()
{
if (fData->fInited)
{
globfree(&fData->fGlobBuf);
fData->fCnt = 0;
fData->fInited=false;
}
}
hsBool hsFolderIterator::NextFile()
{
if (fData->fInited == false)
{
std::string path=fPath;
if(!(strchr(fPath,'*') || strchr(fPath,'?') || strchr(fPath,'[')))
{
if (fPath[strlen(fPath)-1] != PATH_SEPARATOR)
path = path + PATH_SEPARATOR_STR + "*";
else
path = path + "*";
}
if(glob(path.c_str(), 0, NULL, &fData->fGlobBuf) != 0 ) {
return false;
}
fData->fInited=true;
fData->fCnt = 0;
}
return fData->fCnt++ < fData->fGlobBuf.gl_pathc;
}
const char* hsFolderIterator::GetFileName() const
{
if (!fData->fInited || fData->fCnt > fData->fGlobBuf.gl_pathc)
throw "end of folder";
const char* fn=fData->fGlobBuf.gl_pathv[fData->fCnt-1];
return plFileUtils::GetFileName(fn);
}
hsBool hsFolderIterator::IsDirectory( void ) const
{
// rob, please forgive me, this is my best attempt...
if(fData->fCnt > fData->fGlobBuf.gl_pathc )
return false;
struct stat info;
const char* fn=fData->fGlobBuf.gl_pathv[fData->fCnt-1];
if( stat( fn, &info ) )
{
printf("Error calling stat(): %s errno=%d\n", strerror(errno), errno);
return false;
}
return ( info.st_mode & S_IFDIR ) ? true : false;
}
#endif

View File

@ -0,0 +1,320 @@
/*==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 "hsFiles.h"
#if HS_BUILD_FOR_WIN32
#include <windows.h>
#include "hsExceptions.h"
struct hsFolderIterator_Data {
HANDLE fSearchHandle;
WIN32_FIND_DATA fFindData;
Boolean fValid;
};
hsFolderIterator::hsFolderIterator(const char path[], bool useCustomFilter)
{
fCustomFilter = useCustomFilter;
fData = TRACKED_NEW hsFolderIterator_Data;
fData->fSearchHandle = nil;
fData->fValid = true;
if(useCustomFilter)
{
this->SetFileFilterStr(path);
}
else
{
this->SetPath(path);
}
}
hsFolderIterator::~hsFolderIterator()
{
delete fData;
}
void hsFolderIterator::SetPath(const char path[])
{
fCustomFilter = false;
fPath[0] = 0;
if (path)
{
::strcpy(fPath, path);
// Make sure the dir ends with a slash
char lastchar = fPath[strlen(fPath)-1];
if (lastchar != '\\' && lastchar != '/')
strcat(fPath, "\\");
}
this->Reset();
}
void hsFolderIterator::SetWinSystemDir(const char subdir[])
{
int ret = GetWindowsDirectory(fPath, _MAX_PATH);
hsAssert(ret != 0, "Error getting windows directory in UseWindowsFontsPath");
if (subdir)
{ ::strcat(fPath, "\\");
::strcat(fPath, subdir);
::strcat(fPath, "\\");
}
this->Reset();
}
void hsFolderIterator::SetFileFilterStr(const char filterStr[])
{
fPath[0] = 0;
if (filterStr)
{
fCustomFilter = true;
::strcpy(fPath, filterStr);
}
this->Reset();
}
///////////////////////////////////////////////////////////////////////////////
void hsFolderIterator::Reset()
{
if (fData->fSearchHandle)
{ FindClose(fData->fSearchHandle);
fData->fSearchHandle = nil;
}
fData->fValid = true;
}
hsBool hsFolderIterator::NextFile()
{
if (fData->fValid == false)
return false;
if (fData->fSearchHandle == nil)
{ int len = ::strlen(fPath);
if(fCustomFilter == false)
{
fPath[len] = '*';
fPath[len+1] = 0;
}
fData->fSearchHandle = FindFirstFile(fPath, &fData->fFindData);
fPath[len] = 0;
if (fData->fSearchHandle == INVALID_HANDLE_VALUE)
{ fData->fSearchHandle = nil;
fData->fValid = false;
return false;
}
}
else
{ if (FindNextFile(fData->fSearchHandle, &fData->fFindData) == false)
{ FindClose(fData->fSearchHandle);
fData->fSearchHandle = nil;
fData->fValid = false;
return false;
}
}
return true;
}
hsBool hsFolderIterator::IsDirectory( void ) const
{
if( fData->fValid && ( fData->fFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
return true;
return false;
}
const char* hsFolderIterator::GetFileName() const
{
if (fData->fValid == false)
hsThrow( "end of folder");
return fData->fFindData.cFileName;
}
///////////////////////////////////////////////////////////////////////////////
struct hsWFolderIterator_Data {
HANDLE fSearchHandle;
WIN32_FIND_DATAW fFindData;
Boolean fValid;
};
hsWFolderIterator::hsWFolderIterator(const wchar path[], bool useCustomFilter)
{
fCustomFilter = useCustomFilter;
fData = TRACKED_NEW hsWFolderIterator_Data;
fData->fSearchHandle = nil;
fData->fValid = true;
if(useCustomFilter)
SetFileFilterStr(path);
else
SetPath(path);
}
hsWFolderIterator::~hsWFolderIterator()
{
delete fData;
}
void hsWFolderIterator::SetPath(const wchar path[])
{
fCustomFilter = false;
fPath[0] = 0;
if (path)
{
wcscpy(fPath, path);
// Make sure the dir ends with a slash
wchar lastchar = fPath[wcslen(fPath)-1];
if (lastchar != L'\\' && lastchar != L'/')
wcscat(fPath, L"\\");
}
Reset();
}
void hsWFolderIterator::SetWinSystemDir(const wchar subdir[])
{
int ret = GetWindowsDirectoryW(fPath, _MAX_PATH);
hsAssert(ret != 0, "Error getting windows directory in UseWindowsFontsPath");
if (subdir)
{
wcscat(fPath, L"\\");
wcscat(fPath, subdir);
wcscat(fPath, L"\\");
}
Reset();
}
void hsWFolderIterator::SetFileFilterStr(const wchar filterStr[])
{
fPath[0] = 0;
if (filterStr)
{
fCustomFilter = true;
wcscpy(fPath, filterStr);
}
Reset();
}
///////////////////////////////////////////////////////////////////////////////
void hsWFolderIterator::Reset()
{
if (fData->fSearchHandle)
{
FindClose(fData->fSearchHandle);
fData->fSearchHandle = nil;
}
fData->fValid = true;
}
hsBool hsWFolderIterator::NextFile()
{
if (fData->fValid == false)
return false;
if (fData->fSearchHandle == nil)
{
int len = wcslen(fPath);
if(fCustomFilter == false)
{
fPath[len] = L'*';
fPath[len+1] = L'\0';
}
fData->fSearchHandle = FindFirstFileW(fPath, &fData->fFindData);
fPath[len] = 0;
if (fData->fSearchHandle == INVALID_HANDLE_VALUE)
{
fData->fSearchHandle = nil;
fData->fValid = false;
return false;
}
}
else
{
if (FindNextFileW(fData->fSearchHandle, &fData->fFindData) == false)
{
FindClose(fData->fSearchHandle);
fData->fSearchHandle = nil;
fData->fValid = false;
return false;
}
}
return true;
}
hsBool hsWFolderIterator::IsDirectory( void ) const
{
if( fData->fValid && ( fData->fFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
return true;
return false;
}
const wchar* hsWFolderIterator::GetFileName() const
{
if (fData->fValid == false)
hsThrow( "end of folder");
return fData->fFindData.cFileName;
}
#endif // HS_BUILD_FOR_WIN32

View File

@ -0,0 +1,88 @@
/*==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 "plBrowseFolder.h"
#ifdef HS_BUILD_FOR_WIN32
#include <shlobj.h>
bool plBrowseFolder::GetFolder(char *path, const char *startPath, const char *title, HWND hwndOwner)
{
BROWSEINFO bi;
memset(&bi, 0, sizeof(bi));
bi.hwndOwner = hwndOwner;
bi.lpszTitle = title;
bi.lpfn = BrowseCallbackProc;
bi.lParam = (LPARAM) startPath;
ITEMIDLIST *iil = SHBrowseForFolder(&bi);
// Browse failed, or cancel was selected
if (!iil)
return false;
// Browse succeded. Get the path.
else
SHGetPathFromIDList(iil, path);
// Free the memory allocated by SHBrowseForFolder
LPMALLOC pMalloc;
SHGetMalloc(&pMalloc);
pMalloc->Free(iil);
pMalloc->Release();
return true;
}
int CALLBACK plBrowseFolder::BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
switch (uMsg)
{
case BFFM_INITIALIZED:
// lpData should be the lParam passed to SHBrowseForFolder, which is the start path.
if (lpData)
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
break;
}
return 0;
}
#endif // HS_BUILD_FOR_WIN32

View File

@ -0,0 +1,74 @@
/*==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==*/
#ifndef plBrowseFolder_h_inc
#define plBrowseFolder_h_inc
#include "hsConfig.h"
#ifdef HS_BUILD_FOR_WIN32
#include "hsWindows.h"
//
// Gets a directory using the "Browse for Folder" dialog.
//
// path: Buffer to recieve the path. Should be MAX_PATH characters.
// startPath: Initial path.
// title: Not really the title of the dialog, but it's displayed above the
// folder list. Could be used to give instructions.
// hwndOwner: Owner window for dialog box.
//
// Returns true if path contains a valid path, false otherwise (error or user
// clicked cancel.
//
class plBrowseFolder
{
public:
static bool GetFolder(char *path, const char *startPath = NULL, const char *title = NULL, HWND hwndOwner = NULL);
protected:
static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
};
#endif // HS_BUILD_FOR_WIN32
#endif // plBrowseFolder_h_inc

View File

@ -0,0 +1,593 @@
/*==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 "plEncryptedStream.h"
#include "hsUtils.h"
#include "plFileUtils.h"
#include "hsSTLStream.h"
#include <time.h>
static const UInt32 kDefaultKey[4] = { 0x6c0a5452, 0x3827d0f, 0x3a170b92, 0x16db7fc2 };
static const int kEncryptChunkSize = 8;
static const char* kOldMagicString = "BriceIsSmart";
static const char* kMagicString = "whatdoyousee";
static const int kMagicStringLen = 12;
static const int kFileStartOffset = kMagicStringLen + sizeof(UInt32);
static const int kMaxBufferedFileSize = 10*1024;
plEncryptedStream::plEncryptedStream(UInt32* key) :
fRef(nil),
fActualFileSize(0),
fBufferedStream(false),
fRAMStream(nil),
fWriteFileName(nil),
fOpenMode(kOpenFail)
{
if (key)
memcpy(&fKey, key, sizeof(kDefaultKey));
else
memcpy(&fKey, &kDefaultKey, sizeof(kDefaultKey));
}
plEncryptedStream::~plEncryptedStream()
{
}
//
// Tiny Encryption Algorithm
// http://vader.brad.ac.uk/tea/tea.shtml
//
// A potential weakness in this implementation is the fact that a known value
// (length of the original file) is written at the start of the encrypted file. -Colin
//
// Oh, and also there's some kind of potential weakness in TEA that they fixed with XTEA,
// but frankly, who cares. No one is going to break the encryption, they'll just get the
// key out of the exe or memory.
//
void plEncryptedStream::IEncipher(UInt32* const v)
{
register unsigned long y=v[0], z=v[1], sum=0, delta=0x9E3779B9, n=32;
while (n-- > 0)
{
y += (z << 4 ^ z >> 5) + z ^ sum + fKey[sum&3];
sum += delta;
z += (y << 4 ^ y >> 5) + y ^ sum + fKey[sum>>11 & 3];
}
v[0]=y; v[1]=z;
}
void plEncryptedStream::IDecipher(UInt32* const v)
{
register unsigned long y=v[0], z=v[1], sum=0xC6EF3720, delta=0x9E3779B9, n=32;
// sum = delta<<5, in general sum = delta * n
while (n-- > 0)
{
z -= (y << 4 ^ y >> 5) + y ^ sum + fKey[sum>>11 & 3];
sum -= delta;
y -= (z << 4 ^ z >> 5) + z ^ sum + fKey[sum&3];
}
v[0]=y; v[1]=z;
}
hsBool plEncryptedStream::Open(const char* name, const char* mode)
{
wchar* wName = hsStringToWString(name);
wchar* wMode = hsStringToWString(mode);
hsBool ret = Open(wName, wMode);
delete [] wName;
delete [] wMode;
return ret;
}
hsBool plEncryptedStream::Open(const wchar* name, const wchar* mode)
{
if (wcscmp(mode, L"rb") == 0)
{
fRef = _wfopen(name, mode);
fPosition = 0;
if (!fRef)
return false;
// Make sure our special magic string is there
if (!ICheckMagicString(fRef))
{
fclose(fRef);
return false;
}
fread(&fActualFileSize, sizeof(UInt32), 1, fRef);
// The encrypted stream is inefficient if you do reads smaller than
// 8 bytes. Since we do a lot of those, any file under a size threshold
// is buffered in memory
if (fActualFileSize <= kMaxBufferedFileSize)
IBufferFile();
fOpenMode = kOpenRead;
return true;
}
else if (wcscmp(mode, L"wb") == 0)
{
fRAMStream = TRACKED_NEW hsVectorStream;
fWriteFileName = TRACKED_NEW wchar[wcslen(name) + 1];
wcscpy(fWriteFileName, name);
fPosition = 0;
fOpenMode = kOpenWrite;
fBufferedStream = true;
return true;
}
else
{
hsAssert(0, "Unsupported open mode");
fOpenMode = kOpenFail;
return false;
}
}
hsBool plEncryptedStream::Close()
{
int rtn = false;
if (fOpenMode == kOpenWrite)
{
fRAMStream->Rewind();
rtn = IWriteEncypted(fRAMStream, fWriteFileName);
}
if (fRef)
{
rtn = (fclose(fRef) == 0);
fRef = nil;
}
if (fRAMStream)
{
delete fRAMStream;
fRAMStream = nil;
}
if (fWriteFileName)
{
delete [] fWriteFileName;
fWriteFileName = nil;
}
fActualFileSize = 0;
fBufferedStream = false;
fOpenMode = kOpenFail;
return rtn;
}
UInt32 plEncryptedStream::IRead(UInt32 bytes, void* buffer)
{
if (!fRef)
return 0;
int numItems = (int)(::fread(buffer, 1 /*size*/, bytes /*count*/, fRef));
fBytesRead += numItems;
fPosition += numItems;
if ((unsigned)numItems < bytes) {
if (feof(fRef)) {
// EOF ocurred
char str[128];
sprintf(str, "Hit EOF on UNIX Read, only read %d out of requested %d bytes\n", numItems, bytes);
hsDebugMessage(str, 0);
}
else {
hsDebugMessage("Error on UNIX Read", ferror(fRef));
}
}
return numItems;
}
void plEncryptedStream::IBufferFile()
{
fRAMStream = TRACKED_NEW hsVectorStream;
char buf[1024];
while (!AtEnd())
{
UInt32 numRead = Read(1024, buf);
fRAMStream->Write(numRead, buf);
}
fRAMStream->Rewind();
fBufferedStream = true;
fclose(fRef);
fRef = nil;
fPosition = 0;
}
hsBool plEncryptedStream::AtEnd()
{
if (fBufferedStream)
return fRAMStream->AtEnd();
else
return (GetPosition() == fActualFileSize);
}
void plEncryptedStream::Skip(UInt32 delta)
{
if (fBufferedStream)
{
fRAMStream->Skip(delta);
fPosition = fRAMStream->GetPosition();
}
else if (fRef)
{
fBytesRead += delta;
fPosition += delta;
fseek(fRef, delta, SEEK_CUR);
}
}
void plEncryptedStream::Rewind()
{
if (fBufferedStream)
{
fRAMStream->Rewind();
fPosition = fRAMStream->GetPosition();
}
else if (fRef)
{
fBytesRead = 0;
fPosition = 0;
fseek(fRef, kFileStartOffset, SEEK_SET);
}
}
void plEncryptedStream::FastFwd()
{
if (fBufferedStream)
{
fRAMStream->FastFwd();
fPosition = fRAMStream->GetPosition();
}
else if (fRef)
{
fseek(fRef, kFileStartOffset+fActualFileSize, SEEK_SET);
fBytesRead = fPosition = ftell(fRef);
}
}
UInt32 plEncryptedStream::GetEOF()
{
return fActualFileSize;
}
UInt32 plEncryptedStream::Read(UInt32 bytes, void* buffer)
{
if (fBufferedStream)
{
UInt32 numRead = fRAMStream->Read(bytes, buffer);
fPosition = fRAMStream->GetPosition();
return numRead;
}
UInt32 startPos = fPosition;
// Offset into the first buffer (0 if we are aligned on a chunk, which means no extra block read)
UInt32 startChunkPos = startPos % kEncryptChunkSize;
// Amount of data in the partial first chunk (0 if we're aligned)
UInt32 startAmt = (startChunkPos != 0) ? hsMinimum(kEncryptChunkSize - startChunkPos, bytes) : 0;
UInt32 totalNumRead = IRead(bytes, buffer);
UInt32 numMidChunks = (totalNumRead - startAmt) / kEncryptChunkSize;
UInt32 endAmt = (totalNumRead - startAmt) % kEncryptChunkSize;
// If the start position is in the middle of a chunk we need to rewind and
// read that whole chunk in and decrypt it.
if (startChunkPos != 0)
{
// Move to the start of this chunk
SetPosition(startPos-startChunkPos);
// Read in the chunk and decrypt it
char buf[kEncryptChunkSize];
UInt32 numRead = IRead(kEncryptChunkSize, &buf);
IDecipher((UInt32*)&buf);
// Copy the relevant portion to the output buffer
memcpy(buffer, &buf[startChunkPos], startAmt);
SetPosition(startPos+totalNumRead);
}
if (numMidChunks != 0)
{
UInt32* bufferPos = (UInt32*)(((char*)buffer)+startAmt);
for (int i = 0; i < numMidChunks; i++)
{
// Decrypt chunk
IDecipher(bufferPos);
bufferPos += (kEncryptChunkSize / sizeof(UInt32));
}
}
if (endAmt != 0)
{
// Read in the final chunk and decrypt it
char buf[kEncryptChunkSize];
SetPosition(startPos + startAmt + numMidChunks*kEncryptChunkSize);
UInt32 numRead = IRead(kEncryptChunkSize, &buf);
IDecipher((UInt32*)&buf);
memcpy(((char*)buffer)+totalNumRead-endAmt, &buf, endAmt);
SetPosition(startPos+totalNumRead);
}
// If we read into the padding at the end, update the total read to not include that
if (totalNumRead > 0 && startPos + totalNumRead > fActualFileSize)
{
totalNumRead -= (startPos + totalNumRead) - fActualFileSize;
SetPosition(fActualFileSize);
}
return totalNumRead;
}
UInt32 plEncryptedStream::Write(UInt32 bytes, const void* buffer)
{
if (fOpenMode != kOpenWrite)
{
hsAssert(0, "Trying to write to a read stream");
return 0;
}
return fRAMStream->Write(bytes, buffer);
}
bool plEncryptedStream::IWriteEncypted(hsStream* sourceStream, const wchar* outputFile)
{
hsUNIXStream outputStream;
if (!outputStream.Open(outputFile, L"wb"))
return false;
outputStream.Write(kMagicStringLen, kMagicString);
// Save some space to write the file size at the end
outputStream.WriteSwap32(0);
// Write out all the full size encrypted blocks we can
char buf[kEncryptChunkSize];
UInt32 amtRead;
while ((amtRead = sourceStream->Read(kEncryptChunkSize, &buf)) == kEncryptChunkSize)
{
IEncipher((UInt32*)&buf);
outputStream.Write(kEncryptChunkSize, &buf);
}
// Pad with random data and write out the final partial block, if there is one
if (amtRead > 0)
{
static bool seededRand = false;
if (!seededRand)
{
seededRand = true;
srand((unsigned int)time(nil));
}
for (int i = amtRead; i < kEncryptChunkSize; i++)
buf[i] = rand();
IEncipher((UInt32*)&buf);
outputStream.Write(kEncryptChunkSize, &buf);
}
// Write the original file size at the start
UInt32 actualSize = sourceStream->GetPosition();
outputStream.Rewind();
outputStream.Skip(kMagicStringLen);
outputStream.WriteSwap32(actualSize);
outputStream.Close();
return true;
}
bool plEncryptedStream::FileEncrypt(const char* fileName)
{
wchar* wFilename = hsStringToWString(fileName);
bool ret = FileEncrypt(wFilename);
delete [] wFilename;
return ret;
}
bool plEncryptedStream::FileEncrypt(const wchar* fileName)
{
hsUNIXStream sIn;
if (!sIn.Open(fileName))
return false;
// Don't double encrypt any files
if (ICheckMagicString(sIn.GetFILE()))
{
sIn.Close();
return true;
}
sIn.Rewind();
plEncryptedStream sOut;
bool wroteEncrypted = sOut.IWriteEncypted(&sIn, L"crypt.dat");
sIn.Close();
sOut.Close();
if (wroteEncrypted)
{
plFileUtils::RemoveFile(fileName);
plFileUtils::FileMove(L"crypt.dat", fileName);
}
return true;
}
bool plEncryptedStream::FileDecrypt(const char* fileName)
{
wchar* wFilename = hsStringToWString(fileName);
bool ret = FileDecrypt(wFilename);
delete [] wFilename;
return ret;
}
bool plEncryptedStream::FileDecrypt(const wchar* fileName)
{
plEncryptedStream sIn;
if (!sIn.Open(fileName))
return false;
hsUNIXStream sOut;
if (!sOut.Open(L"crypt.dat", L"wb"))
{
sIn.Close();
return false;
}
char buf[1024];
while (!sIn.AtEnd())
{
UInt32 numRead = sIn.Read(sizeof(buf), buf);
sOut.Write(numRead, buf);
}
sIn.Close();
sOut.Close();
plFileUtils::RemoveFile(fileName);
plFileUtils::FileMove(L"crypt.dat", fileName);
return true;
}
bool plEncryptedStream::ICheckMagicString(FILE* fp)
{
char magicString[kMagicStringLen+1];
fread(&magicString, kMagicStringLen, 1, fp);
magicString[kMagicStringLen] = '\0';
return (hsStrEQ(magicString, kMagicString) || hsStrEQ(magicString, kOldMagicString));
}
bool plEncryptedStream::IsEncryptedFile(const char* fileName)
{
wchar* wFilename = hsStringToWString(fileName);
bool ret = IsEncryptedFile(wFilename);
delete [] wFilename;
return ret;
}
bool plEncryptedStream::IsEncryptedFile(const wchar* fileName)
{
FILE* fp = _wfopen(fileName, L"rb");
if (!fp)
return false;
bool isEncrypted = ICheckMagicString(fp);
fclose(fp);
return isEncrypted;
}
hsStream* plEncryptedStream::OpenEncryptedFile(const char* fileName, bool requireEncrypted, UInt32* cryptKey)
{
wchar* wFilename = hsStringToWString(fileName);
hsStream* ret = OpenEncryptedFile(wFilename, requireEncrypted, cryptKey);
delete [] wFilename;
return ret;
}
hsStream* plEncryptedStream::OpenEncryptedFile(const wchar* fileName, bool requireEncrypted, UInt32* cryptKey)
{
#ifndef PLASMA_EXTERNAL_RELEASE
requireEncrypted = false;
#endif
bool isEncrypted = IsEncryptedFile(fileName);
hsStream* s = nil;
if (isEncrypted)
s = TRACKED_NEW plEncryptedStream(cryptKey);
// If this isn't an external release, let them use unencrypted data
else
if (!requireEncrypted)
s = TRACKED_NEW hsUNIXStream;
if (s)
s->Open(fileName, L"rb");
return s;
}
hsStream* plEncryptedStream::OpenEncryptedFileWrite(const char* fileName, UInt32* cryptKey)
{
wchar* wFilename = hsStringToWString(fileName);
hsStream* ret = OpenEncryptedFileWrite(wFilename, cryptKey);
delete [] wFilename;
return ret;
}
hsStream* plEncryptedStream::OpenEncryptedFileWrite(const wchar* fileName, UInt32* cryptKey)
{
hsStream* s = nil;
#ifdef PLASMA_EXTERNAL_RELEASE
s = TRACKED_NEW plEncryptedStream(cryptKey);
#else
s = TRACKED_NEW hsUNIXStream;
#endif
s->Open(fileName, L"wb");
return s;
}

View File

@ -0,0 +1,116 @@
/*==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==*/
#ifndef plEncryptedStream_h_inc
#define plEncryptedStream_h_inc
#include "hsStream.h"
//
// Encrypt a large file by running FileEncrypt on it. Small files can be done
// in the usual way, but they will be in memory until Close is called. Files
// will be decrypted on the fly during read.operations
//
class plEncryptedStream : public hsStream
{
protected:
FILE* fRef;
UInt32 fKey[4];
UInt32 fActualFileSize;
bool fBufferedStream;
hsStream* fRAMStream;
wchar* fWriteFileName;
enum OpenMode { kOpenRead, kOpenWrite, kOpenFail };
OpenMode fOpenMode;
void IBufferFile();
UInt32 IRead(UInt32 bytes, void* buffer);
void IEncipher(UInt32* const v);
void IDecipher(UInt32* const v);
bool IWriteEncypted(hsStream* sourceStream, const wchar* outputFile);
static bool ICheckMagicString(FILE* fp);
public:
// If you don't pass in a key (4 UInt32's), the default one will be used
plEncryptedStream(UInt32* key=nil);
~plEncryptedStream();
virtual hsBool Open(const char* name, const char* mode = "rb");
virtual hsBool Open(const wchar* name, const wchar* mode = L"rb");
virtual hsBool Close();
virtual UInt32 Read(UInt32 byteCount, void* buffer);
virtual UInt32 Write(UInt32 byteCount, const void* buffer);
virtual hsBool AtEnd();
virtual void Skip(UInt32 deltaByteCount);
virtual void Rewind();
virtual void FastFwd();
virtual UInt32 GetEOF();
UInt32 GetActualFileSize() const { return fActualFileSize;}
static bool FileEncrypt(const char* fileName);
static bool FileEncrypt(const wchar* fileName);
static bool FileDecrypt(const char* fileName);
static bool FileDecrypt(const wchar* fileName);
static bool IsEncryptedFile(const char* fileName);
static bool IsEncryptedFile(const wchar* fileName);
// Attempts to create a read-binary stream for the requested file. If it's
// encrypted, you'll get a plEncryptedStream, otherwise just a standard
// hsUNIXStream. Remember to delete the stream when you're done with it.
static hsStream* OpenEncryptedFile(const char* fileName, bool requireEncrypted = true, UInt32* cryptKey = nil);
static hsStream* OpenEncryptedFile(const wchar* fileName, bool requireEncrypted = true, UInt32* cryptKey = nil);
static hsStream* OpenEncryptedFileWrite(const char* fileName, UInt32* cryptKey = nil);
static hsStream* OpenEncryptedFileWrite(const wchar* fileName, UInt32* cryptKey = nil);
};
#endif // plEncryptedStream_h_inc

View File

@ -0,0 +1,516 @@
/*==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==*/
/////////////////////////////////////////////////////////////////////////////
//
// plFileUtils - Namespace of fun file utilities
//
//// History /////////////////////////////////////////////////////////////////
//
// 5.7.2002 mcn - Created
// 4.8.2003 chip - added FileCopy and FileMove for Unix
//
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "hsStlUtils.h"
#include "plFileUtils.h"
#include "hsFiles.h"
#include "hsStringTokenizer.h"
#include "hsWindows.h"
#include "../plUnifiedTime/plUnifiedTime.h"
#include "plSecureStream.h" // for the default key
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#if HS_BUILD_FOR_WIN32
#include <direct.h>
#include <io.h>
#endif
#if HS_BUILD_FOR_UNIX
#include <unistd.h>
#include <errno.h>
#include <utime.h>
#endif
//// CreateDir ///////////////////////////////////////////////////////////////
// Creates the directory specified. Returns false if unsuccessful or
// directory already exists
hsBool plFileUtils::CreateDir( const char *path )
{
// Create our directory
#if HS_BUILD_FOR_WIN32
return ( mkdir( path ) == 0 ) ? true : ( errno==EEXIST );
#elif HS_BUILD_FOR_UNIX
return ( mkdir( path, 0777 ) == 0 ) ? true : ( errno==EEXIST );
#endif
}
hsBool plFileUtils::CreateDir( const wchar *path )
{
// Create our directory
#if HS_BUILD_FOR_WIN32
return ( _wmkdir( path ) == 0 ) ? true : ( errno==EEXIST );
#elif HS_BUILD_FOR_UNIX
return ( mkdir( path, 0777 ) == 0 ) ? true : ( errno==EEXIST );
#endif
}
hsBool plFileUtils::RemoveDir(const char* path)
{
return (rmdir(path) == 0);
}
hsBool plFileUtils::RemoveDirTree(const char * path)
{
hsFolderIterator it(path);
while (it.NextFile())
{
const char * fname = it.GetFileName();
if ( fname[0]=='.' )
continue;
char pathAndName[128];
it.GetPathAndName(pathAndName);
if ( it.IsDirectory() )
{
RemoveDirTree( pathAndName );
RemoveDir( pathAndName );
}
else
{
RemoveFile( pathAndName );
}
}
RemoveDir( path );
return 1;
}
//// RemoveFile ////////////////////////////////////////////////////////////
bool plFileUtils::RemoveFile(const char* filename, bool delReadOnly)
{
if (delReadOnly)
chmod(filename, S_IWRITE);
return (unlink(filename) == 0);
}
bool plFileUtils::RemoveFile(const wchar* filename, bool delReadOnly)
{
if (delReadOnly)
_wchmod(filename, S_IWRITE);
return (_wunlink(filename) == 0);
}
bool plFileUtils::FileCopy(const char* existingFile, const char* newFile)
{
wchar* wExisting = hsStringToWString(existingFile);
wchar* wNew = hsStringToWString(newFile);
bool ret = FileCopy(wExisting, wNew);
delete [] wExisting;
delete [] wNew;
return ret;
}
bool plFileUtils::FileCopy(const wchar* existingFile, const wchar* newFile)
{
#if HS_BUILD_FOR_WIN32
return (::CopyFileW(existingFile, newFile, FALSE) != 0);
#elif HS_BUILD_FOR_UNIX
char data[1500];
FILE* fp = fopen(existingFile, "rb");
FILE* fw = fopen(newFile, "w");
int num = 0;
bool retVal = true;
if (fp && fw){
while(!feof(fp)){
num = fread(data, sizeof( char ), 1500, fp);
if( ferror( fp ) ) {
retVal = false;
break;
}
fwrite(data, sizeof( char ), num, fw);
}
fclose(fp);
fclose(fw);
} else {
retVal = false;
}
return retVal;
#else
hsAssert(0, "Not implemented");
return false;
#endif
}
bool plFileUtils::FileMove(const char* existingFile, const char* newFile)
{
#if HS_BUILD_FOR_WIN32
return (::MoveFile(existingFile, newFile) != 0);
#elif HS_BUILD_FOR_UNIX
FileCopy(existingFile,newFile);
return( RemoveFile( existingFile )==0);
#else
hsAssert(0, "Not implemented");
return false;
#endif
}
bool plFileUtils::FileMove(const wchar* existingFile, const wchar* newFile)
{
#if HS_BUILD_FOR_WIN32
return (::MoveFileW(existingFile, newFile) != 0);
#elif HS_BUILD_FOR_UNIX
FileCopy(existingFile,newFile);
return( RemoveFile( existingFile )==0);
#else
hsAssert(0, "Not implemented");
return false;
#endif
}
bool plFileUtils::FileExists(const wchar* file)
{
FILE* fp = _wfopen(file, L"rb");
bool retVal = (fp != nil);
if (fp)
fclose(fp);
return retVal;
}
bool plFileUtils::FileExists(const char* file)
{
FILE* fp = fopen(file, "rb");
bool retVal = (fp != nil);
if (fp)
fclose(fp);
return retVal;
}
//// EnsureFilePathExists ////////////////////////////////////////////////////
// Given a filename with path, makes sure the file's path exists
hsBool plFileUtils::EnsureFilePathExists( const char *filename )
{
wchar* wFilename = hsStringToWString(filename);
hsBool ret = EnsureFilePathExists(wFilename);
delete [] wFilename;
return ret;
}
hsBool plFileUtils::EnsureFilePathExists( const wchar *filename )
{
hsWStringTokenizer izer( filename, L"\\/" );
hsBool lastWorked = false;
wchar token[ kFolderIterator_MaxPath ];
while( izer.Next( token, arrsize( token ) ) && izer.HasMoreTokens() )
{
// Want the full path from the start of the string
lastWorked = CreateDir( izer.fString );
izer.RestoreLastTerminator();
}
return lastWorked;
}
//// GetFileTimes ////////////////////////////////////////////////////////////
// Gets the creation and modification dates of the file specified. Returns
// false if unsuccessful
hsBool plFileUtils::GetFileTimes( const char *path, plUnifiedTime *createTimeOut, plUnifiedTime *modifyTimeOut )
{
struct stat fileInfo;
int result = stat( path, &fileInfo );
if( result != 0 )
return false;
if( createTimeOut != nil )
*createTimeOut = plUnifiedTime( fileInfo.st_ctime );
if( modifyTimeOut != nil )
*modifyTimeOut = plUnifiedTime( fileInfo.st_mtime );
return true;
}
plFileUtils::Modify plFileUtils::CompareModifyTimes(const char* file1, const char* file2)
{
plUnifiedTime modTime1, modTime2;
if (GetFileTimes(file1, nil, &modTime1) &&
GetFileTimes(file2, nil, &modTime2))
{
double diff = plUnifiedTime::GetTimeDifference(modTime1, modTime2);
if (hsABS(diff) <= 2)
return kFilesEqual;
else if (diff > 0)
return kFile1Newer;
else
return kFile2Newer;
}
return kFileError;
}
bool plFileUtils::SetModifyTime( const char * filename, const plUnifiedTime & timestamp )
{
#ifdef HS_BUILD_FOR_WIN32
HANDLE hFile = CreateFile(filename,
GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nil);
if (hFile==INVALID_HANDLE_VALUE)
return false;
SYSTEMTIME systime;
systime.wDay = timestamp.GetDay();
systime.wDayOfWeek = timestamp.GetDayOfWeek();
systime.wHour = timestamp.GetHour();
systime.wMilliseconds = 0;
systime.wMinute = timestamp.GetMinute();
systime.wMonth = timestamp.GetMonth();
systime.wSecond = timestamp.GetSecond();
systime.wYear = timestamp.GetYear();
FILETIME localFileTime, filetime;
SystemTimeToFileTime(&systime,&localFileTime);
LocalFileTimeToFileTime(&localFileTime,&filetime);
SetFileTime(hFile,nil,nil,&filetime);
CloseHandle(hFile);
return true;
#elif HS_BUILD_FOR_UNIX
struct stat sbuf;
int result = stat( filename, &sbuf );
if( result )
return false;
struct utimbuf utb;
utb.actime = sbuf.st_atime;
utb.modtime = timestamp.GetSecs();
result = utime( filename, &utb );
if( result )
return false;
return true;
#endif
}
//// StripPath ///////////////////////////////////////////////////////////////
const char* plFileUtils::GetFileName(const char* path)
{
const char* c = strrchr(path, '/');
if (c == nil)
c = strrchr(path, '\\');
if (c == nil)
c = path;
else
c++;
return c;
}
const wchar* plFileUtils::GetFileName(const wchar* path)
{
const wchar* c = wcsrchr(path, L'/');
if (c == nil)
c = wcsrchr(path, L'\\');
if (c == nil)
c = path;
else
c++;
return c;
}
void plFileUtils::StripFile(char* pathAndName)
{
char* fileName = (char*)GetFileName(pathAndName);
if (fileName != pathAndName)
*fileName = '\0';
}
void plFileUtils::StripFile(wchar* pathAndName)
{
wchar* fileName = (wchar*)GetFileName(pathAndName);
if (fileName != pathAndName)
*fileName = L'\0';
}
void plFileUtils::StripExt(char* fileName)
{
char* ext = (char*)GetFileExt(fileName);
if (ext)
*(ext-1) = '\0';
}
const char* plFileUtils::GetFileExt(const char* pathAndName)
{
const char* fileName = GetFileName(pathAndName);
if (fileName)
{
const char* ext = strrchr(fileName, '.');
if (ext)
return ext+1;
}
return nil;
}
const wchar* plFileUtils::GetFileExt(const wchar* pathAndName)
{
const wchar* fileName = GetFileName(pathAndName);
if (fileName)
{
const wchar* ext = wcsrchr(fileName, L'.');
if (ext)
return ext+1;
}
return nil;
}
void plFileUtils::AddSlash(char* path)
{
char lastChar = path[strlen(path)-1];
if (lastChar != '\\' && lastChar != '/')
strcat(path, "\\");
}
void plFileUtils::ConcatFileName(char* path, const char* fileName)
{
AddSlash(path);
strcat(path, fileName);
}
//// GetFileSize /////////////////////////////////////////////////////////////
UInt32 plFileUtils::GetFileSize( const char *path )
{
wchar* wPath = hsStringToWString(path);
UInt32 ret = GetFileSize(wPath);
delete [] wPath;
return ret;
}
UInt32 plFileUtils::GetFileSize( const wchar *path )
{
UInt32 len = 0;
hsUNIXStream str;
if (str.Open(path, L"rb"))
{
len = str.GetEOF();
str.Close();
}
return len;
}
//// GetSecureEncryptionKey //////////////////////////////////////////////////
bool plFileUtils::GetSecureEncryptionKey(const char* filename, UInt32* key, unsigned length)
{
wchar* wFilename = hsStringToWString(filename);
bool ret = GetSecureEncryptionKey(wFilename, key, length);
delete [] wFilename;
return ret;
}
bool plFileUtils::GetSecureEncryptionKey(const wchar* filename, UInt32* key, unsigned length)
{
// looks for an encryption key file in the same directory, and reads it
std::wstring sFilename = filename;
// grab parent directory
unsigned loc = sFilename.rfind(L"\\");
if (loc == std::wstring::npos)
loc = sFilename.rfind(L"/");
std::wstring sDir;
if (loc != std::wstring::npos)
sDir = sFilename.substr(0, loc);
else // no directory
sDir = L"./";
if ((sDir[sDir.length()-1] != L'/') && (sDir[sDir.length()-1] != L'\\'))
sDir += L'/'; // add the slash, if it doesn't has one
// now add the key filename
std::wstring keyFile = sDir + kWKeyFilename;
if (FileExists(keyFile.c_str()))
{
// file exists, read from it
hsUNIXStream file;
file.Open(keyFile.c_str(), L"rb");
unsigned bytesToRead = length * sizeof(UInt32);
byte* buffer = (byte*)ALLOC(bytesToRead);
unsigned bytesRead = file.Read(bytesToRead, buffer);
file.Close();
unsigned memSize = min(bytesToRead, bytesRead);
memcpy(key, buffer, memSize);
FREE(buffer);
return true;
}
else
{
// file doesn't exist, use default key
unsigned memSize = min(length, arrsize(plSecureStream::kDefaultKey));
memSize *= sizeof(UInt32);
memcpy(key, plSecureStream::kDefaultKey, memSize);
return false;
}
}

View File

@ -0,0 +1,122 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
//
// plFileUtils - Namespace of fun file utilities
//
//// History /////////////////////////////////////////////////////////////////
//
// 5.7.2002 mcn - Created
//
//////////////////////////////////////////////////////////////////////////////
#ifndef _plFileUtils_h
#define _plFileUtils_h
class plUnifiedTime;
namespace plFileUtils
{
static const char kKeyFilename[] = "encryption.key";
static const wchar kWKeyFilename[] = L"encryption.key";
// Creates the directory specified. Returns false if unsuccessful or directory already exists
hsBool CreateDir( const char *path );
hsBool CreateDir( const wchar *path );
hsBool RemoveDir(const char* path);
hsBool RemoveDirTree(const char * path);
// delete file from disk
bool RemoveFile(const char* filename, bool delReadOnly=false);
bool RemoveFile(const wchar* filename, bool delReadOnly=false);
bool FileCopy(const char* existingFile, const char* newFile);
bool FileCopy(const wchar* existingFile, const wchar* newFile);
bool FileMove(const char* existingFile, const char* newFile);
bool FileMove(const wchar* existingFile, const wchar* newFile);
bool FileExists(const char* file);
bool FileExists(const wchar* file);
// Given a filename with path, makes sure the file's path exists
hsBool EnsureFilePathExists( const char *filename );
hsBool EnsureFilePathExists( const wchar *filename );
// Gets the creation and modification dates of the file specified. Returns false if unsuccessful
hsBool GetFileTimes( const char *path, plUnifiedTime *createTimeOut, plUnifiedTime *modifyTimeOut );
// Compares file times, taking into account NTFS/FAT32 time issues
enum Modify { kFileError, kFilesEqual, kFile1Newer, kFile2Newer };
Modify CompareModifyTimes(const char* file1, const char* file2);
// Set file modify time
bool SetModifyTime( const char * filename, const plUnifiedTime & time );
// Return a pointer into the given string at the start of the actual filename (i.e. past any path info)
const char* GetFileName(const char* pathAndName);
const wchar* GetFileName(const wchar* pathAndName);
// Get the file extension (without the .), or nil if it doesn't have one
const char* GetFileExt(const char* pathAndName);
const wchar* GetFileExt(const wchar* pathAndName);
// Strips the filename off the given full path
void StripFile(char* pathAndName);
void StripFile(wchar* pathAndName);
void StripExt(char* fileName);
// Get the size of the given file in bytes
UInt32 GetFileSize( const char *path );
UInt32 GetFileSize( const wchar *path );
// Adds a slash to the end of a filename (or does nothing if it's already there)
void AddSlash(char* path);
// Concatenates fileName onto path, making sure to add a slash if necessary
void ConcatFileName(char* path, const char* fileName);
// searches the parent directory of filename for the encryption key file, and reads it
// into the key passed in. Returns false if the key file didn't exist (and sets key to
// the default key)
bool GetSecureEncryptionKey(const char* filename, UInt32* key, unsigned length);
bool GetSecureEncryptionKey(const wchar* filename, UInt32* key, unsigned length);
};
#endif // _plFileUtils_h

View File

@ -0,0 +1,218 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plInitFileReader - Helper class that parses a standard-format .ini file //
// and allows you to specify derived classes to handle //
// interpreting specific portions. //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "plInitFileReader.h"
#include "hsStream.h"
#include "hsUtils.h"
#include "hsStringTokenizer.h"
#include "plEncryptedStream.h"
plInitSectionTokenReader::plInitSectionTokenReader( const char *separators ) : fSeparators( separators )
{
}
hsBool plInitSectionTokenReader::ParseLine( const char *line, UInt32 userData )
{
hsStringTokenizer izer( line, fSeparators );
char *token = izer.next();
return IParseToken( token, &izer, userData );
}
void plInitFileReader::IInitReaders( plInitSectionReader **readerArray )
{
UInt32 i;
for( i = 0; readerArray[ i ] != nil; i++ )
fSections.Append( readerArray[ i ] );
hsAssert( fSections.GetCount() > 0, "No sections for initFileReader" );
fCurrSection = fSections[ 0 ];
}
plInitFileReader::plInitFileReader( plInitSectionReader **readerArray, UInt16 lineSize )
{
fRequireEncrypted = true;
fCurrLine = nil;
fLineSize = lineSize;
fStream = fOurStream = nil;
IInitReaders( readerArray );
fUnhandledSection = nil;
}
plInitFileReader::plInitFileReader( const char *fileName, plInitSectionReader **readerArray, UInt16 lineSize )
{
fRequireEncrypted = true;
fCurrLine = nil;
fLineSize = lineSize;
fStream = fOurStream = nil;
IInitReaders( readerArray );
if( !Open( fileName ) )
hsAssert( false, "Constructor open for plInitFileReader failed!" );
fUnhandledSection = nil;
}
plInitFileReader::plInitFileReader( hsStream *stream, plInitSectionReader **readerArray, UInt16 lineSize )
{
fRequireEncrypted = true;
fCurrLine = nil;
fLineSize = lineSize;
fStream = fOurStream = nil;
IInitReaders( readerArray );
if( !Open( stream ) )
hsAssert( false, "Constructor open for plInitFileReader failed!" );
fUnhandledSection = nil;
}
plInitFileReader::~plInitFileReader()
{
Close();
delete [] fCurrLine;
}
hsBool plInitFileReader::Open( const char *fileName )
{
if( fStream != nil )
{
hsAssert( false, "Unable to open initFileReader; already open" );
return false;
}
fOurStream = plEncryptedStream::OpenEncryptedFile( fileName, fRequireEncrypted );
if( fOurStream == nil )
return false;
fStream = fOurStream;
return true;
}
hsBool plInitFileReader::Open( hsStream *stream )
{
if( fStream != nil )
{
hsAssert( false, "Unable to open initFileReader; already open" );
return false;
}
fStream = stream;
return true;
}
hsBool plInitFileReader::Parse( UInt32 userData )
{
hsAssert( fStream != nil, "Nil stream in initFileReader::Parse(); file not yet open?" );
if( fCurrLine == nil )
fCurrLine = TRACKED_NEW char[ fLineSize + 1 ];
// Start parsing lines
while( fStream->ReadLn( fCurrLine, fLineSize ) )
{
// puts( fCurrLine );
// Is line a section header?
if( fCurrLine[ 0 ] == '[' )
{
// Yes--match against our sections and switch to the given one
char *end = strchr( fCurrLine, ']' );
if( end != nil )
*end = 0;
UInt32 i;
bool foundSection = false;
for( i = 0; i < fSections.GetCount(); i++ )
{
if( stricmp( fSections[ i ]->GetSectionName(), &fCurrLine[ 1 ] ) == 0 )
{
fCurrSection = fSections[ i ];
foundSection = true;
break;
}
}
if (!foundSection && fUnhandledSection)
{
fCurrSection = fUnhandledSection;
fCurrSection->SetSectionName(&fCurrLine[1]);
}
}
else
{
// Nope, just a line, pass to our current section tokenizer
if( !fCurrSection->ParseLine( fCurrLine, userData ) )
return false;
}
}
return true;
}
void plInitFileReader::Close( void )
{
if( fStream == nil )
return;
if( fStream == fOurStream )
{
fStream->Close();
delete fOurStream;
fOurStream = nil;
}
fStream = nil;
}

View File

@ -0,0 +1,153 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plInitFileReader - Helper class that parses a standard-format .ini file //
// and allows you to specify derived classes to handle //
// interpreting specific portions. //
// //
//// Usage ///////////////////////////////////////////////////////////////////
// //
// First create a set of derived classes from plInitSectionReader //
// (or plInitSectionTokenReader, to be easier) that will parse the lines //
// for each section of your .ini file. Then create a C-style array of //
// pointers to instances of each reader, the first being the default //
// reader, and ending with a nil pointer (see below). Finally, create //
// a plInitFileReader with the array you created and it'll parse the //
// given file (or stream) and call your readers as needed. You can also //
// optionally pass in a UInt32 for userData that will be passed on to each //
// reader in turn. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plInitFileReader_h
#define _plInitFileReader_h
#include "hsTypes.h"
#include "hsStream.h"
#include "hsTemplates.h"
//// Base Section Class //////////////////////////////////////////////////////
// Define a derived version of this for each section of your init file.
class plInitSectionReader
{
public:
// Override this to define what [string] your section starts with
virtual const char *GetSectionName( void ) const = 0;
// Override this to parse each line in your section. Return false to abort parsing
virtual hsBool ParseLine( const char *line, UInt32 userData ) = 0;
// Override this if you're defining an unhandled section reader
virtual void SetSectionName(const char* section) {}
};
//// Semi-Derived Class //////////////////////////////////////////////////////
// Half-way derived class for parsing lines by tokens rather than pure
// strings.
class hsStringTokenizer;
class plInitSectionTokenReader : public plInitSectionReader
{
protected:
const char *fSeparators;
// Override this to parse each token in your section. Return false to abort parsing
virtual hsBool IParseToken( const char *token, hsStringTokenizer *tokenizer, UInt32 userData ) = 0;
public:
plInitSectionTokenReader( const char *separators = ",=\t" );
// Overridden for you. Override IParseToken()
virtual hsBool ParseLine( const char *line, UInt32 userData );
};
//// Main Reader Class ///////////////////////////////////////////////////////
// Create one of these and add an array of derived versions of the above
// reader to parse your init file.
class plInitFileReader
{
protected:
hsStream *fStream;
hsStream *fOurStream;
char *fCurrLine;
UInt32 fLineSize;
bool fRequireEncrypted;
plInitSectionReader *fCurrSection;
hsTArray<plInitSectionReader *> fSections;
plInitSectionReader* fUnhandledSection;
void IInitReaders( plInitSectionReader **readerArray );
public:
// The array passed in should be an array of pointers to plInitSectionReader,
// with the last pointer being nil (denoting the end of the array). The first
// element of the array will be the "default" section--i.e. if there is no section
// header at the top of the file, that reader will be used.
plInitFileReader( plInitSectionReader **readerArray, UInt16 lineSize = 256 );
plInitFileReader( const char *fileName, plInitSectionReader **readerArray, UInt16 lineSize = 256 );
plInitFileReader( hsStream *stream, plInitSectionReader **readerArray, UInt16 lineSize = 256 );
virtual ~plInitFileReader();
void SetRequireEncrypted(bool require) { fRequireEncrypted = require; }
bool GetRequireEncrypted() const { return fRequireEncrypted; }
void SetUnhandledSectionReader(plInitSectionReader* reader) { fUnhandledSection = reader; }
hsBool Open( const char *fileName );
hsBool Open( hsStream *stream );
hsBool Parse( UInt32 userData = 0 );
void Close( void );
hsBool IsOpen( void ) const { return fStream != nil; }
};
#endif //_plInitFileReader_h

View File

@ -0,0 +1,640 @@
/*==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 "plSecureStream.h"
#include "hsUtils.h"
#include "plFileUtils.h"
#include "hsSTLStream.h"
#include <time.h>
// our default encryption key
const UInt32 plSecureStream::kDefaultKey[4] = { 0x6c0a5452, 0x3827d0f, 0x3a170b92, 0x16db7fc2 };
static const int kEncryptChunkSize = 8;
static const char* kMagicString = "notthedroids";
static const int kMagicStringLen = 12;
static const int kFileStartOffset = kMagicStringLen + sizeof(UInt32);
static const int kMaxBufferedFileSize = 10*1024;
plSecureStream::plSecureStream(hsBool deleteOnExit, UInt32* key) :
fRef(INVALID_HANDLE_VALUE),
fActualFileSize(0),
fBufferedStream(false),
fRAMStream(nil),
fWriteFileName(nil),
fOpenMode(kOpenFail),
fDeleteOnExit(deleteOnExit)
{
if (key)
memcpy(&fKey, key, sizeof(kDefaultKey));
else
memcpy(&fKey, &kDefaultKey, sizeof(kDefaultKey));
}
plSecureStream::~plSecureStream()
{
}
//
// XXTEA
// http://www-users.cs.york.ac.uk/~matthew/TEA/
//
// A potential weakness in this implementation is the fact that a known value
// (length of the original file) is written at the start of the encrypted file. -Colin
//
#define MX (z>>5 ^ y<<2) + (y>>3 ^ z<<4) ^ (sum^y) + (fKey[p&3^e]^z)
void plSecureStream::IEncipher(UInt32* const v, UInt32 n)
{
register unsigned long y=v[0], z=v[n-1], e, delta=0x9E3779B9;
register unsigned long q = 6 + 52/n, p, sum = 0;
while (q-- > 0)
{
sum += delta;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++)
{
y = v[p + 1];
v[p] += MX;
z = v[p];
}
y = v[0];
v[n - 1] += MX;
z = v[n - 1];
}
}
void plSecureStream::IDecipher(UInt32* const v, UInt32 n)
{
register unsigned long y=v[0], z=v[n-1], e, delta=0x9E3779B9;
register unsigned long q = 6 + 52/n, p, sum = q * delta;
while (sum > 0)
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = v[p - 1];
v[p] -= MX;
y = v[p];
}
z = v[n - 1];
v[0] -= MX;
y = v[0];
sum -= delta;
}
}
hsBool plSecureStream::Open(const char* name, const char* mode)
{
wchar* wName = hsStringToWString(name);
wchar* wMode = hsStringToWString(mode);
hsBool ret = Open(wName, wMode);
delete [] wName;
delete [] wMode;
return ret;
}
hsBool plSecureStream::Open(const wchar* name, const wchar* mode)
{
if (wcscmp(mode, L"rb") == 0)
{
if (fDeleteOnExit)
{
fRef = CreateFileW(name,
GENERIC_READ, // open for reading
0, // no one can open the file until we're done
NULL, // default security
OPEN_EXISTING, // only open existing files (no creation)
FILE_FLAG_DELETE_ON_CLOSE, // delete the file from disk when we close the handle
NULL); // no template
}
else
{
fRef = CreateFileW(name,
GENERIC_READ, // open for reading
0, // no one can open the file until we're done
NULL, // default security
OPEN_EXISTING, // only open existing files (no creation)
FILE_ATTRIBUTE_NORMAL, // normal file attributes
NULL); // no template
}
fPosition = 0;
if (fRef == INVALID_HANDLE_VALUE)
return false;
// Make sure our special magic string is there
if (!ICheckMagicString(fRef))
{
CloseHandle(fRef);
fRef = INVALID_HANDLE_VALUE;
return false;
}
DWORD numBytesRead;
ReadFile(fRef, &fActualFileSize, sizeof(UInt32), &numBytesRead, NULL);
// The encrypted stream is inefficient if you do reads smaller than
// 8 bytes. Since we do a lot of those, any file under a size threshold
// is buffered in memory
if (fActualFileSize <= kMaxBufferedFileSize)
IBufferFile();
fOpenMode = kOpenRead;
return true;
}
else if (wcscmp(mode, L"wb") == 0)
{
fRAMStream = TRACKED_NEW hsVectorStream;
fWriteFileName = TRACKED_NEW wchar[wcslen(name) + 1];
wcscpy(fWriteFileName, name);
fPosition = 0;
fOpenMode = kOpenWrite;
fBufferedStream = true;
return true;
}
else
{
hsAssert(0, "Unsupported open mode");
fOpenMode = kOpenFail;
return false;
}
}
hsBool plSecureStream::Close()
{
int rtn = false;
if (fOpenMode == kOpenWrite)
{
fRAMStream->Rewind();
rtn = IWriteEncrypted(fRAMStream, fWriteFileName);
}
if (fRef != INVALID_HANDLE_VALUE)
{
rtn = CloseHandle(fRef);
fRef = INVALID_HANDLE_VALUE;
}
if (fRAMStream)
{
delete fRAMStream;
fRAMStream = nil;
}
if (fWriteFileName)
{
delete [] fWriteFileName;
fWriteFileName = nil;
}
fActualFileSize = 0;
fBufferedStream = false;
fOpenMode = kOpenFail;
return rtn;
}
UInt32 plSecureStream::IRead(UInt32 bytes, void* buffer)
{
if (fRef == INVALID_HANDLE_VALUE)
return 0;
DWORD numItems;
bool success = (ReadFile(fRef, buffer, bytes, &numItems, NULL) != 0);
fBytesRead += numItems;
fPosition += numItems;
if ((unsigned)numItems < bytes)
{
if (success)
{
// EOF ocurred
char str[128];
sprintf(str, "Hit EOF on Windows read, only read %d out of requested %d bytes\n", numItems, bytes);
hsDebugMessage(str, 0);
}
else
{
hsDebugMessage("Error on Windows read", GetLastError());
}
}
return numItems;
}
void plSecureStream::IBufferFile()
{
fRAMStream = TRACKED_NEW hsVectorStream;
char buf[1024];
while (!AtEnd())
{
UInt32 numRead = Read(1024, buf);
fRAMStream->Write(numRead, buf);
}
fRAMStream->Rewind();
fBufferedStream = true;
CloseHandle(fRef);
fRef = INVALID_HANDLE_VALUE;
fPosition = 0;
}
hsBool plSecureStream::AtEnd()
{
if (fBufferedStream)
return fRAMStream->AtEnd();
else
return (GetPosition() == fActualFileSize);
}
void plSecureStream::Skip(UInt32 delta)
{
if (fBufferedStream)
{
fRAMStream->Skip(delta);
fPosition = fRAMStream->GetPosition();
}
else if (fRef != INVALID_HANDLE_VALUE)
{
fBytesRead += delta;
fPosition += delta;
SetFilePointer(fRef, delta, 0, FILE_CURRENT);
}
}
void plSecureStream::Rewind()
{
if (fBufferedStream)
{
fRAMStream->Rewind();
fPosition = fRAMStream->GetPosition();
}
else if (fRef != INVALID_HANDLE_VALUE)
{
fBytesRead = 0;
fPosition = 0;
SetFilePointer(fRef, kFileStartOffset, 0, FILE_BEGIN);
}
}
void plSecureStream::FastFwd()
{
if (fBufferedStream)
{
fRAMStream->FastFwd();
fPosition = fRAMStream->GetPosition();
}
else if (fRef != INVALID_HANDLE_VALUE)
{
fBytesRead = fPosition = SetFilePointer(fRef, kFileStartOffset + fActualFileSize, 0, FILE_BEGIN);
}
}
UInt32 plSecureStream::GetEOF()
{
return fActualFileSize;
}
UInt32 plSecureStream::Read(UInt32 bytes, void* buffer)
{
if (fBufferedStream)
{
UInt32 numRead = fRAMStream->Read(bytes, buffer);
fPosition = fRAMStream->GetPosition();
return numRead;
}
UInt32 startPos = fPosition;
// Offset into the first buffer (0 if we are aligned on a chunk, which means no extra block read)
UInt32 startChunkPos = startPos % kEncryptChunkSize;
// Amount of data in the partial first chunk (0 if we're aligned)
UInt32 startAmt = (startChunkPos != 0) ? hsMinimum(kEncryptChunkSize - startChunkPos, bytes) : 0;
UInt32 totalNumRead = IRead(bytes, buffer);
UInt32 numMidChunks = (totalNumRead - startAmt) / kEncryptChunkSize;
UInt32 endAmt = (totalNumRead - startAmt) % kEncryptChunkSize;
// If the start position is in the middle of a chunk we need to rewind and
// read that whole chunk in and decrypt it.
if (startChunkPos != 0)
{
// Move to the start of this chunk
SetPosition(startPos-startChunkPos);
// Read in the chunk and decrypt it
char buf[kEncryptChunkSize];
UInt32 numRead = IRead(kEncryptChunkSize, &buf);
IDecipher((UInt32*)&buf, kEncryptChunkSize / sizeof(UInt32));
// Copy the relevant portion to the output buffer
memcpy(buffer, &buf[startChunkPos], startAmt);
SetPosition(startPos+totalNumRead);
}
if (numMidChunks != 0)
{
UInt32* bufferPos = (UInt32*)(((char*)buffer)+startAmt);
for (int i = 0; i < numMidChunks; i++)
{
// Decrypt chunk
IDecipher(bufferPos, kEncryptChunkSize / sizeof(UInt32));
bufferPos += (kEncryptChunkSize / sizeof(UInt32));
}
}
if (endAmt != 0)
{
// Read in the final chunk and decrypt it
char buf[kEncryptChunkSize];
SetPosition(startPos + startAmt + numMidChunks*kEncryptChunkSize);
UInt32 numRead = IRead(kEncryptChunkSize, &buf);
IDecipher((UInt32*)&buf, kEncryptChunkSize / sizeof(UInt32));
memcpy(((char*)buffer)+totalNumRead-endAmt, &buf, endAmt);
SetPosition(startPos+totalNumRead);
}
// If we read into the padding at the end, update the total read to not include that
if (totalNumRead > 0 && startPos + totalNumRead > fActualFileSize)
{
totalNumRead -= (startPos + totalNumRead) - fActualFileSize;
SetPosition(fActualFileSize);
}
return totalNumRead;
}
UInt32 plSecureStream::Write(UInt32 bytes, const void* buffer)
{
if (fOpenMode != kOpenWrite)
{
hsAssert(0, "Trying to write to a read stream");
return 0;
}
return fRAMStream->Write(bytes, buffer);
}
bool plSecureStream::IWriteEncrypted(hsStream* sourceStream, const wchar* outputFile)
{
hsUNIXStream outputStream;
if (!outputStream.Open(outputFile, L"wb"))
return false;
outputStream.Write(kMagicStringLen, kMagicString);
// Save some space to write the file size at the end
outputStream.WriteSwap32(0);
// Write out all the full size encrypted blocks we can
char buf[kEncryptChunkSize];
UInt32 amtRead;
while ((amtRead = sourceStream->Read(kEncryptChunkSize, &buf)) == kEncryptChunkSize)
{
IEncipher((UInt32*)&buf, kEncryptChunkSize / sizeof(UInt32));
outputStream.Write(kEncryptChunkSize, &buf);
}
// Pad with random data and write out the final partial block, if there is one
if (amtRead > 0)
{
static bool seededRand = false;
if (!seededRand)
{
seededRand = true;
srand((unsigned int)time(nil));
}
for (int i = amtRead; i < kEncryptChunkSize; i++)
buf[i] = rand();
IEncipher((UInt32*)&buf, kEncryptChunkSize / sizeof(UInt32));
outputStream.Write(kEncryptChunkSize, &buf);
}
// Write the original file size at the start
UInt32 actualSize = sourceStream->GetPosition();
outputStream.Rewind();
outputStream.Skip(kMagicStringLen);
outputStream.WriteSwap32(actualSize);
outputStream.Close();
return true;
}
bool plSecureStream::FileEncrypt(const char* fileName, UInt32* key /* = nil */)
{
wchar* wFilename = hsStringToWString(fileName);
bool ret = FileEncrypt(wFilename, key);
delete [] wFilename;
return ret;
}
bool plSecureStream::FileEncrypt(const wchar* fileName, UInt32* key /* = nil */)
{
hsUNIXStream sIn;
if (!sIn.Open(fileName))
return false;
// Don't double encrypt any files
if (ICheckMagicString(sIn.GetFILE()))
{
sIn.Close();
return true;
}
sIn.Rewind();
plSecureStream sOut(false, key);
bool wroteEncrypted = sOut.IWriteEncrypted(&sIn, L"crypt.dat");
sIn.Close();
sOut.Close();
if (wroteEncrypted)
{
plFileUtils::RemoveFile(fileName);
plFileUtils::FileMove(L"crypt.dat", fileName);
}
return true;
}
bool plSecureStream::FileDecrypt(const char* fileName, UInt32* key /* = nil */)
{
wchar* wFilename = hsStringToWString(fileName);
bool ret = FileDecrypt(wFilename, key);
delete [] wFilename;
return ret;
}
bool plSecureStream::FileDecrypt(const wchar* fileName, UInt32* key /* = nil */)
{
plSecureStream sIn(false, key);
if (!sIn.Open(fileName))
return false;
hsUNIXStream sOut;
if (!sOut.Open(L"crypt.dat", L"wb"))
{
sIn.Close();
return false;
}
char buf[1024];
while (!sIn.AtEnd())
{
UInt32 numRead = sIn.Read(sizeof(buf), buf);
sOut.Write(numRead, buf);
}
sIn.Close();
sOut.Close();
plFileUtils::RemoveFile(fileName);
plFileUtils::FileMove(L"crypt.dat", fileName);
return true;
}
bool plSecureStream::ICheckMagicString(HANDLE fp)
{
char magicString[kMagicStringLen+1];
DWORD numBytesRead;
ReadFile(fp, &magicString, kMagicStringLen, &numBytesRead, NULL);
magicString[kMagicStringLen] = '\0';
return (hsStrEQ(magicString, kMagicString) != 0);
}
bool plSecureStream::IsSecureFile(const char* fileName)
{
wchar* wFilename = hsStringToWString(fileName);
bool ret = IsSecureFile(wFilename);
delete [] wFilename;
return ret;
}
bool plSecureStream::IsSecureFile(const wchar* fileName)
{
HANDLE fp = INVALID_HANDLE_VALUE;
fp = CreateFileW(fileName,
GENERIC_READ, // open for reading
0, // no one can open the file until we're done
NULL, // default security
OPEN_EXISTING, // only open existing files (no creation)
FILE_ATTRIBUTE_NORMAL, // normal file attributes
NULL); // no template
if (fp == INVALID_HANDLE_VALUE)
return false;
bool isEncrypted = ICheckMagicString(fp);
CloseHandle(fp);
return isEncrypted;
}
hsStream* plSecureStream::OpenSecureFile(const char* fileName, const UInt32 flags /* = kRequireEncryption */, UInt32* key /* = nil */)
{
wchar* wFilename = hsStringToWString(fileName);
hsStream* ret = OpenSecureFile(wFilename, flags, key);
delete [] wFilename;
return ret;
}
hsStream* plSecureStream::OpenSecureFile(const wchar* fileName, const UInt32 flags /* = kRequireEncryption */, UInt32* key /* = nil */)
{
bool requireEncryption = flags & kRequireEncryption;
#ifndef PLASMA_EXTERNAL_RELEASE
requireEncryption = false;
#endif
hsBool deleteOnExit = flags & kDeleteOnExit;
bool isEncrypted = IsSecureFile(fileName);
hsStream* s = nil;
if (isEncrypted)
s = TRACKED_NEW plSecureStream(deleteOnExit, key);
else if (!requireEncryption) // If this isn't an external release, let them use unencrypted data
s = TRACKED_NEW hsUNIXStream;
if (s)
s->Open(fileName, L"rb");
return s;
}
hsStream* plSecureStream::OpenSecureFileWrite(const char* fileName, UInt32* key /* = nil */)
{
wchar* wFilename = hsStringToWString(fileName);
hsStream* ret = OpenSecureFileWrite(wFilename, key);
delete [] wFilename;
return ret;
}
hsStream* plSecureStream::OpenSecureFileWrite(const wchar* fileName, UInt32* key /* = nil */)
{
hsStream* s = nil;
#ifdef PLASMA_EXTERNAL_RELEASE
s = TRACKED_NEW plSecureStream(false, key);
#else
s = TRACKED_NEW hsUNIXStream;
#endif
s->Open(fileName, L"wb");
return s;
}

View File

@ -0,0 +1,127 @@
/*==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==*/
#ifndef plSecureStream_h_inc
#define plSecureStream_h_inc
#include "hsStream.h"
#include <windows.h>
// A slightly more secure stream then plEncryptedStream in that it uses windows file functions
// to prevent other processes from accessing the file it is working with. It also can be set
// to download the file from a server into a temporary directory (with a mangled name) and
// delete that file on close, thereby minimizing the chance of having that file examined or
// edited.
class plSecureStream: public hsStream
{
protected:
HANDLE fRef;
UInt32 fKey[4];
UInt32 fActualFileSize;
bool fBufferedStream;
hsStream* fRAMStream;
wchar* fWriteFileName;
enum OpenMode {kOpenRead, kOpenWrite, kOpenFail};
OpenMode fOpenMode;
hsBool fDeleteOnExit;
void IBufferFile();
UInt32 IRead(UInt32 bytes, void* buffer);
void IEncipher(UInt32* const v, UInt32 n);
void IDecipher(UInt32* const v, UInt32 n);
bool IWriteEncrypted(hsStream* sourceStream, const wchar* outputFile);
static bool ICheckMagicString(HANDLE fp);
public:
plSecureStream(hsBool deleteOnExit = false, UInt32* key = nil); // uses default key if you don't pass one in
~plSecureStream();
virtual hsBool Open(const char* name, const char* mode = "rb");
virtual hsBool Open(const wchar* name, const wchar* mode = L"rb");
virtual hsBool Close();
virtual UInt32 Read(UInt32 byteCount, void* buffer);
virtual UInt32 Write(UInt32 byteCount, const void* buffer);
virtual hsBool AtEnd();
virtual void Skip(UInt32 deltaByteCount);
virtual void Rewind();
virtual void FastFwd();
virtual UInt32 GetEOF();
UInt32 GetActualFileSize() const {return fActualFileSize;}
static bool FileEncrypt(const char* fileName, UInt32* key = nil);
static bool FileEncrypt(const wchar* fileName, UInt32* key = nil);
static bool FileDecrypt(const char* fileName, UInt32* key = nil);
static bool FileDecrypt(const wchar* fileName, UInt32* key = nil);
enum OpenSecureFileFlags
{
kRequireEncryption = 0x01,
kDeleteOnExit = 0x02,
};
static bool IsSecureFile(const char* fileName);
static bool IsSecureFile(const wchar* fileName);
// Attempts to create a read-binary stream for the requested file (delete the stream
// when you are done with it!)
static hsStream* OpenSecureFile(const char* fileName, const UInt32 flags = kRequireEncryption, UInt32* key = nil);
static hsStream* OpenSecureFile(const wchar* fileName, const UInt32 flags = kRequireEncryption, UInt32* key = nil);
// Attempts to create a write-binary stream for the requested file (delete the stream
// when you are done with it!)
static hsStream* OpenSecureFileWrite(const char* fileName, UInt32* key = nil);
static hsStream* OpenSecureFileWrite(const wchar* fileName, UInt32* key = nil);
static const UInt32 kDefaultKey[4]; // our default encryption key
};
#endif // plSecureStream_h_inc

View File

@ -0,0 +1,212 @@
/*==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;
}

View File

@ -0,0 +1,84 @@
/*==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==*/
#ifndef plStreamSource_h_inc
#define plStreamSource_h_inc
#include "hsStream.h"
#include "hsStlUtils.h"
// A class for holding and accessing file streams. The preloader will insert
// files in here once they are loaded. In internal builds, if a requested file
// is not found, it will be retrieved from disk.
class plStreamSource
{
private:
struct fileData
{
std::wstring fFilename; // includes path
std::wstring fDir; // parent directory
std::wstring fExt;
hsStream* fStream; // we own this pointer, so clean it up
};
std::map<std::wstring, fileData> fFileData; // key is filename
void ICleanup(); // closes all file pointers and cleans up after itself
void IBreakupFilename(std::wstring filename, std::wstring& dir, std::wstring& ext);
plStreamSource() {}
public:
~plStreamSource() {ICleanup();}
// Force a cleanup of all data (some apps need to get at those file again, and they can't while we have them open)
void Cleanup() {ICleanup();}
// File access functions
hsStream* GetFile(std::wstring filename); // internal builds will read from disk if it doesn't exist
std::vector<std::wstring> GetListOfNames(std::wstring dir, std::wstring ext); // internal builds merge from disk
// For other classes to insert files (takes ownership of the stream if successful)
bool InsertFile(std::wstring filename, hsStream* stream);
// Instance handling
static plStreamSource* GetInstance();
};
#endif // plStreamSource_h_inc