2018-04-22 15:55:55 +00:00
|
|
|
//======== (C) Copyright 2001 Charles G. Cleveland All rights reserved. =========
|
|
|
|
//
|
|
|
|
// The copyright to the contents herein is the property of Charles G. Cleveland.
|
|
|
|
// The contents may be used and/or copied only with the written permission of
|
|
|
|
// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in
|
|
|
|
// the agreement/contract under which the contents have been supplied.
|
|
|
|
//
|
|
|
|
// Purpose: Utility functions loosely wrapping the STL
|
|
|
|
//
|
|
|
|
// $Workfile: STLUtil.cpp$
|
|
|
|
// $Date: 2002/07/26 21:43:04 $
|
|
|
|
//
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
// $Log: STLUtil.cpp,v $
|
|
|
|
// Revision 1.6 2002/07/26 21:43:04 flayra
|
|
|
|
// - Updates to get particles and sounds working under Linux
|
|
|
|
//
|
|
|
|
// Revision 1.5 2002/07/26 01:51:23 Flayra
|
|
|
|
// - Linux support for FindFirst/FindNext
|
|
|
|
//
|
|
|
|
// Revision 1.4 2002/05/23 04:03:11 Flayra
|
|
|
|
// - Post-crash checkin. Restored @Backup from around 4/16. Contains changes for last four weeks of development.
|
|
|
|
//
|
|
|
|
// Revision 1.5 2002/05/14 18:48:16 Charlie
|
|
|
|
// - More utility functions
|
|
|
|
//
|
|
|
|
// Revision 1.4 2002/05/01 00:52:34 Charlie
|
|
|
|
// - Added BuildAbridgedString
|
|
|
|
//
|
|
|
|
//===============================================================================
|
|
|
|
#include "STLUtil.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "stdarg.h"
|
|
|
|
|
|
|
|
|
|
|
|
// For FindFirst/FindNext functionality in BuildFileList
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include "winsani_in.h"
|
|
|
|
#include <windows.h>
|
|
|
|
#include "winsani_out.h"
|
|
|
|
#else
|
|
|
|
#include "LinuxSupport.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
string LowercaseString(const string& ioString)
|
|
|
|
{
|
|
|
|
string theReturnString = ioString;
|
|
|
|
LowercaseString(theReturnString);
|
|
|
|
return theReturnString;
|
|
|
|
}
|
|
|
|
|
|
|
|
string LowercaseString(string& ioString)
|
|
|
|
{
|
|
|
|
size_t theLength = ioString.length();
|
|
|
|
for(size_t i = 0; i < theLength; i++)
|
|
|
|
{
|
|
|
|
char theCurrentChar = ioString[i];
|
|
|
|
ioString[i] = tolower(theCurrentChar);
|
|
|
|
}
|
|
|
|
return ioString;
|
|
|
|
}
|
|
|
|
|
|
|
|
string UppercaseString(const string& ioString)
|
|
|
|
{
|
|
|
|
string theReturnString = ioString;
|
|
|
|
UppercaseString(theReturnString);
|
|
|
|
return theReturnString;
|
|
|
|
}
|
|
|
|
|
|
|
|
string UppercaseString(string& ioString)
|
|
|
|
{
|
|
|
|
size_t theLength = ioString.length();
|
|
|
|
for(size_t i = 0; i < theLength; i++)
|
|
|
|
{
|
|
|
|
char theCurrentChar = ioString[i];
|
|
|
|
ioString[i] = toupper(theCurrentChar);
|
|
|
|
}
|
|
|
|
return ioString;
|
|
|
|
}
|
|
|
|
|
|
|
|
int MakeIntFromString(string& inString)
|
|
|
|
{
|
|
|
|
int theInt = 0;
|
|
|
|
if(inString.length() > 0)
|
|
|
|
{
|
|
|
|
sscanf(inString.c_str(), "%d", &theInt);
|
|
|
|
}
|
|
|
|
return theInt;
|
|
|
|
}
|
|
|
|
|
|
|
|
float MakeFloatFromString(string& inString)
|
|
|
|
{
|
|
|
|
float theFloat = 0;
|
|
|
|
if(inString.length() > 0)
|
|
|
|
{
|
|
|
|
sscanf(inString.c_str(), "%f", &theFloat);
|
|
|
|
}
|
|
|
|
|
|
|
|
return theFloat;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MakeBytesFromHexPairs(const string& inHex, unsigned char* ioBytes, int numBytes)
|
|
|
|
{
|
|
|
|
bool theSuccess = true;
|
|
|
|
if(inHex.size() != numBytes*2)
|
|
|
|
{
|
|
|
|
theSuccess = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(int index = 0; index < numBytes; ++index)
|
|
|
|
{
|
|
|
|
int theByte = 0;
|
|
|
|
for(int strpos = index*2; strpos < (index+1)*2; ++strpos)
|
|
|
|
{
|
|
|
|
theByte *= 16;
|
|
|
|
switch(inHex[strpos])
|
|
|
|
{
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
theByte += inHex[strpos] - '0';
|
|
|
|
break;
|
|
|
|
case 'A': case 'B': case 'C':
|
|
|
|
case 'D': case 'E': case 'F':
|
|
|
|
theByte += inHex[strpos] - 'A' + 10;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
theSuccess = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(theSuccess)
|
|
|
|
{
|
|
|
|
ioBytes[index] = theByte;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return theSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
string MakeStringFromInt(int inNumber)
|
|
|
|
{
|
|
|
|
char theBuffer[kMaxStrLen];
|
|
|
|
sprintf(theBuffer, "%d", inNumber);
|
|
|
|
return string(theBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
string MakeStringFromFloat(float inNumber, int inNumDecimals)
|
|
|
|
{
|
|
|
|
// Build format specfier like "%.2f" (where 2 is inNumDecimals)
|
|
|
|
string theFormatSpecfier("%.");
|
|
|
|
theFormatSpecfier += MakeStringFromInt(inNumDecimals);
|
|
|
|
theFormatSpecfier += string("f");
|
|
|
|
|
|
|
|
char theBuffer[kMaxStrLen];
|
|
|
|
sprintf(theBuffer, theFormatSpecfier.c_str(), inNumber);
|
|
|
|
|
|
|
|
return string(theBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MakeHexPairsFromBytes(const unsigned char* inBytes, string& ioHex, int numBytes)
|
|
|
|
{
|
|
|
|
bool theSuccess = true;
|
|
|
|
string theString;
|
|
|
|
int theNumber;
|
|
|
|
for(int index = 0; index < numBytes*2; ++index)
|
|
|
|
{
|
|
|
|
theNumber = inBytes[index/2];
|
|
|
|
if(index % 2)
|
|
|
|
{
|
|
|
|
theNumber %= 16;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
theNumber /= 16;
|
|
|
|
}
|
|
|
|
if(theNumber > 15 || theNumber < 0)
|
|
|
|
{
|
|
|
|
theSuccess = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch(theNumber)
|
|
|
|
{
|
|
|
|
case 0: case 1: case 2: case 3: case 4:
|
|
|
|
case 5: case 6: case 7: case 8: case 9:
|
|
|
|
theString += ('0' + theNumber);
|
|
|
|
break;
|
|
|
|
case 10: case 11: case 12:
|
|
|
|
case 13: case 14: case 15:
|
|
|
|
theString += ('A' + theNumber - 10);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(theSuccess)
|
|
|
|
{
|
|
|
|
ioHex.assign(theString);
|
|
|
|
}
|
|
|
|
return theSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string BuildAbridgedString(const string& inString, int inMaxLen)
|
|
|
|
{
|
|
|
|
ASSERT(inMaxLen > 0);
|
|
|
|
|
|
|
|
string theAbridgedString = inString;
|
|
|
|
|
|
|
|
// If inString is longer then inMaxLen
|
|
|
|
if(inString.length() > (unsigned int)inMaxLen)
|
|
|
|
{
|
|
|
|
// For short max strings, just truncate past inMaxLen (it would be ridiculous to have more then half the string be "...")
|
|
|
|
if(inMaxLen <= 7)
|
|
|
|
{
|
|
|
|
theAbridgedString = inString.substr(0, inMaxLen-1);
|
|
|
|
}
|
|
|
|
// else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Cut off all characters pass inMaxLen - 3
|
|
|
|
theAbridgedString = inString.substr(0, inMaxLen-4);
|
|
|
|
|
|
|
|
// Tack on "..."
|
|
|
|
theAbridgedString += "...";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return theAbridgedString;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *ignoreSounds[] = {
|
|
|
|
"vox/ssay82.wav",
|
|
|
|
"vox/ssay83.wav",
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
// Pass in relative path, do search on path including mod directory, return files relative to mod directory
|
|
|
|
bool BuildFileList(const string& inBaseDirectoryName, const string& inDirectoryName, const string& inFileExtension, CStringList& outList)
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
const string kDelimiter("\\");
|
|
|
|
#else
|
|
|
|
const string kDelimiter("/");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool theSuccess = false;
|
|
|
|
|
|
|
|
string theBaseDirectoryName = inBaseDirectoryName;
|
|
|
|
string theDirectoryName = inDirectoryName;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
// Replace all forward slashes with \\'s if needed
|
|
|
|
std::replace(theBaseDirectoryName.begin(), theBaseDirectoryName.end(), '/', '\\');
|
|
|
|
std::replace(theDirectoryName.begin(), theDirectoryName.end(), '/', '\\');
|
|
|
|
#endif
|
|
|
|
|
|
|
|
string theFullDirName = theBaseDirectoryName + theDirectoryName;
|
|
|
|
|
|
|
|
size_t theEndOffset = theDirectoryName.find_last_of(kDelimiter);
|
|
|
|
string theBaseDirName = theDirectoryName.substr(0, theEndOffset);
|
|
|
|
|
|
|
|
theFullDirName += inFileExtension;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
WIN32_FIND_DATA theFindData;
|
|
|
|
HANDLE theFileHandle;
|
|
|
|
|
|
|
|
theFileHandle = FindFirstFile(theFullDirName.c_str(), &theFindData);
|
|
|
|
if (theFileHandle != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
string theFoundFilename = string(theFindData.cFileName);
|
|
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
string theFoundFilename;
|
|
|
|
FIND_DATA theFindData;
|
|
|
|
|
|
|
|
const char* theFullDirNameCStr = theFullDirName.c_str();
|
|
|
|
int theRC = FindFirstFile(theFullDirNameCStr, &theFindData);
|
|
|
|
if(theRC != -1)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
string theFoundFilename = string(theFindData.cFileName);
|
|
|
|
#endif
|
|
|
|
CString theCString;
|
|
|
|
string theFullFileName = theBaseDirName + string("/") + theFoundFilename;
|
|
|
|
|
|
|
|
// Precache requires / in the filename
|
|
|
|
std::replace(theFullFileName.begin(), theFullFileName.end(), '\\', '/');
|
|
|
|
|
|
|
|
theCString = theFullFileName;
|
|
|
|
#ifdef AVH_SERVER
|
|
|
|
// <HACK> Ignore ssay82 and ssay83 till we can client patch this ..
|
|
|
|
int i=0;
|
|
|
|
bool found = false;
|
|
|
|
while ( ignoreSounds[i] != 0 ) {
|
|
|
|
if ( !strcmp(ignoreSounds[i], theCString))
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (found == false)
|
|
|
|
{
|
|
|
|
#endif
|
|
|
|
outList.push_back(theCString);
|
|
|
|
theSuccess = true;
|
|
|
|
#ifdef AVH_SERVER
|
|
|
|
}
|
|
|
|
// </HACK>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
}
|
|
|
|
while(FindNextFile(theFileHandle, &theFindData));
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
}
|
|
|
|
while(FindNextFile(0, &theFindData));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//DIR theDirp = opendir(theDirName.c_str());
|
|
|
|
// while(theDirp)
|
|
|
|
// {
|
|
|
|
// int theErrno = 0;
|
|
|
|
// if ((dp = readdir(theDirp)) != NULL) {
|
|
|
|
// if (strcmp(dp->d_name, name) == 0) {
|
|
|
|
// closedir(theDirp);
|
|
|
|
// return FOUND;
|
|
|
|
// }
|
|
|
|
// } else {
|
|
|
|
// if (theErrno == 0) {
|
|
|
|
// closedir(theDirp);
|
|
|
|
// return NOT_FOUND;
|
|
|
|
// }
|
|
|
|
// closedir(theDirp);
|
|
|
|
// return READ_ERROR;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// return OPEN_ERROR;
|
|
|
|
|
|
|
|
return theSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 sprintf(string& outString, const char* inPattern, ...)
|
|
|
|
{
|
|
|
|
va_list theParameters;
|
|
|
|
int32 theResult;
|
|
|
|
|
|
|
|
va_start(theParameters, inPattern);
|
|
|
|
|
|
|
|
char theCharArray[kMaxStrLen];
|
|
|
|
|
|
|
|
theResult = ::vsprintf(theCharArray, inPattern, theParameters);
|
|
|
|
outString = theCharArray;
|
|
|
|
|
|
|
|
va_end(theParameters);
|
|
|
|
|
|
|
|
return theResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SafeStrcmp(const char* inStringOne, const char* inStringTwo)
|
|
|
|
{
|
|
|
|
int theReturnValue = -1;
|
|
|
|
|
|
|
|
if(inStringOne && inStringTwo)
|
|
|
|
{
|
|
|
|
theReturnValue = strcmp(inStringOne, inStringTwo);
|
|
|
|
}
|
|
|
|
|
|
|
|
return theReturnValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove leading and trailing spaces.
|
|
|
|
// Remove trailing \r\n
|
|
|
|
void TrimString(string& ioString)
|
|
|
|
{
|
|
|
|
int theStartChopIndex = 0;
|
|
|
|
int theEndChopIndex = (int)ioString.length();
|
|
|
|
|
|
|
|
// Now remove any leading spaces
|
|
|
|
while((theStartChopIndex < (signed)ioString.length()) && (ioString[theStartChopIndex] == ' '))
|
|
|
|
{
|
|
|
|
theStartChopIndex++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove trailing newlines, carriage returns, or spaces
|
|
|
|
while((theEndChopIndex > 0) && ((ioString[theEndChopIndex-1] == '\r') || (ioString[theEndChopIndex-1] == '\n') || (ioString[theEndChopIndex-1] == ' ')))
|
|
|
|
{
|
|
|
|
theEndChopIndex--;
|
|
|
|
}
|
|
|
|
|
|
|
|
int theLength = (int)(theEndChopIndex - theStartChopIndex);
|
|
|
|
if(theLength > 0)
|
|
|
|
{
|
|
|
|
string theTrimmedString = ioString.substr(theStartChopIndex, theLength);
|
|
|
|
ioString = theTrimmedString;
|
|
|
|
}
|
|
|
|
}
|