Files
Jedi-Academy/tools/ModView/generic_stuff.cpp
2013-04-04 14:32:05 -07:00

809 lines
16 KiB
C++

// Filename: generic_stuff.cpp
//
#include "stdafx.h"
#include "includes.h"
#include "MainFrm.h"
//
#include "generic_stuff.h"
#define BASEDIRNAME "base"
#define BASEDIRNAME_XMEN "development"
// kept as non-hungarian labels purely because these 2 are so common in our projects...
//
char qdir[1024]={0}; // "S:\"
char gamedir[1024]={0}; // "S:\\baseq3\\"
// unlike "normal" SetQdirFromPath() functions, I need to see if qdir has changed
// (ie by loading an EF model over an SOF model) which could mean that we're in a different dir, and so
// should lose all cached textures etc...
//
bool bXMenPathHack = false;
bool bQ3RulesApply = true;
static bool SetQdirFromPath2( const char *path, const char *psBaseDir );
void SetQdirFromPath( const char *path )
{
char prevQdir[1024];
strcpy(prevQdir,qdir);
bXMenPathHack = false; // MUST be here
if (SetQdirFromPath2(path,BASEDIRNAME))
{
bQ3RulesApply = true;
}
else
{
if (SetQdirFromPath2(path,BASEDIRNAME_XMEN))
{
bQ3RulesApply = false;
bXMenPathHack = true;
}
}
if (stricmp(prevQdir,qdir))
{
extern void Media_Delete(void);
Media_Delete();
}
}
static bool SetQdirFromPath2( const char *path, const char *psBaseDir )
{
// static bool bDone = false;
// if (!bDone)
{
// bDone = true;
char temp[1024];
strcpy(temp,path);
path = temp;
const char *c;
const char *sep;
int len, count;
// if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
// { // path is partial
// Q_getwd (temp);
// strcat (temp, path);
// path = temp;
// }
_strlwr((char*)path);
// search for "base" in path from the RIGHT hand side (and must have a [back]slash just before it)
len = strlen(psBaseDir);
for (c=path+strlen(path)-1 ; c != path ; c--)
{
int i;
if (!strnicmp (c, psBaseDir, len)
&&
(*(c-1) == '/' || *(c-1) == '\\') // would be more efficient to do this first, but only checking after a strncasecmp ok ensures no invalid pointer-1 access
)
{
sep = c + len;
count = 1;
while (*sep && *sep != '/' && *sep != '\\')
{
sep++;
count++;
}
strncpy (gamedir, path, c+len+count-path);
gamedir[c+len+count-path]='\0';
for ( i = 0; i < (int)strlen( gamedir ); i++ )
{
if ( gamedir[i] == '\\' )
gamedir[i] = '/';
}
// qprintf ("gamedir: %s\n", gamedir);
strncpy (qdir, path, c-path);
qdir[c-path] = 0;
for ( i = 0; i < (int)strlen( qdir ); i++ )
{
if ( qdir[i] == '\\' )
qdir[i] = '/';
}
// qprintf ("qdir: %s\n", qdir);
return true;
}
}
// Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path);
}
return false;
}
// takes (eg) "q:\quake\baseq3\textures\borg\name.tga"
//
// and produces "textures/borg/name.tga"
//
void Filename_RemoveQUAKEBASE(CString &string)
{
string.Replace("\\","/");
string.MakeLower();
/*
int loc = string.Find("/quake");
if (loc >=0 )
{
loc = string.Find("/",loc+1);
if (loc >=0)
{
// now pointing at "baseq3", "demoq3", whatever...
loc = string.Find("/", loc+1);
if (loc >= 0)
{
// now pointing at local filename...
//
string = string.Mid(loc+1);
}
}
}
*/
// SetQdirFromPath( string );
string.Replace( gamedir, "" );
}
bool FileExists (LPCSTR psFilename)
{
FILE *handle = fopen(psFilename, "r");
if (!handle)
{
return false;
}
fclose (handle);
return true;
}
long FileLen( LPCSTR psFilename)
{
FILE *handle = fopen(psFilename, "r");
if (!handle)
{
return -1;
}
long l = filesize(handle);
fclose (handle);
return l;
}
// returns actual filename only, no path
//
char *Filename_WithoutPath(LPCSTR psFilename)
{
static char sString[MAX_PATH];
/*
LPCSTR p = strrchr(psFilename,'\\');
if (!p++)
{
p = strrchr(psFilename,'/');
if (!p++)
p=psFilename;
}
strcpy(sString,p);
*/
LPCSTR psCopyPos = psFilename;
while (*psFilename)
{
if (*psFilename == '/' || *psFilename == '\\')
psCopyPos = psFilename+1;
psFilename++;
}
strcpy(sString,psCopyPos);
return sString;
}
// returns (eg) "\dir\name" for "\dir\name.bmp"
//
char *Filename_WithoutExt(LPCSTR psFilename)
{
static char sString[MAX_PATH];
strcpy(sString,psFilename);
char *p = strrchr(sString,'.');
char *p2= strrchr(sString,'\\');
char *p3= strrchr(sString,'/');
// special check, make sure the first suffix we found from the end wasn't just a directory suffix (eg on a path'd filename with no extension anyway)
//
if (p &&
(p2==0 || (p2 && p>p2)) &&
(p3==0 || (p3 && p>p3))
)
*p=0;
return sString;
}
// loses anything after the path (if any), (eg) "\dir\name.bmp" becomes "\dir"
//
char *Filename_PathOnly(LPCSTR psFilename)
{
static char sString[MAX_PATH];
strcpy(sString,psFilename);
// for (int i=0; i<strlen(sString); i++)
// {
// if (sString[i] == '/')
// sString[i] = '\\';
// }
char *p1= strrchr(sString,'\\');
char *p2= strrchr(sString,'/');
char *p = (p1>p2)?p1:p2;
if (p)
*p=0;
return sString;
}
// returns filename's extension only (including '.'), else returns original string if no '.' in it...
//
char *Filename_ExtOnly(LPCSTR psFilename)
{
static char sString[MAX_PATH];
LPCSTR p = strrchr(psFilename,'.');
if (!p)
p=psFilename;
strcpy(sString,p);
return sString;
}
// used when sending output to a text file etc, keeps columns nice and neat...
//
char *String_EnsureMinLength(LPCSTR psString, int iMinLength)
{
static char sString[8][1024];
static int i=0;
i=(i+1)&7;
strcpy(sString[i],psString);
// a bit slow and lazy, but who cares?...
//
while (strlen(sString[i])<(UINT)iMinLength)
strcat(sString[i]," ");
return sString[i];
}
// similar to strlwr, but (crucially) doesn't touch original...
//
char *String_ToLower(LPCSTR psString)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
return strlwr(sString);
}
// similar to strupr, but (crucially) doesn't touch original...
//
char *String_ToUpper(LPCSTR psString)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
return strupr(sString);
}
char *String_ForwardSlash(LPCSTR psString)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
char *p;
while ( (p=strchr(sString,'\\')) != NULL)
{
*p = '/';
}
return strlwr(sString);
}
char *String_RemoveOccurences(LPCSTR psString, LPCSTR psSubStr)
{
static CString str;
str = psString;
str.Replace(psSubStr,"");
return const_cast < char * > ((LPCSTR) str); // :-)
}
char *va(char *format, ...)
{
va_list argptr;
static char string[16][16384]; // important to have a good depth to this. 16 is nice
static index = 0;
index = (++index)&15;
va_start (argptr, format);
// vsprintf (string[index], format,argptr);
_vsnprintf(string[index], sizeof(string[0]), format, argptr);
va_end (argptr);
string[index][sizeof(string[0])-1] = '\0';
return string[index];
}
// returns a path to somewhere writeable, without trailing backslash...
//
// (for extra speed now, only evaluates it on the first call, change this if you like)
//
char *scGetTempPath(void)
{
static char sBuffer[MAX_PATH];
DWORD dwReturnedSize;
static int i=0;
if (!i++)
{
dwReturnedSize = GetTempPath(sizeof(sBuffer),sBuffer);
if (dwReturnedSize>sizeof(sBuffer))
{
// temp path too long to return, so forget it...
//
strcpy(sBuffer,"c:"); // "c:\\"); // should be writeable
}
// strip any trailing backslash...
//
if (sBuffer[strlen(sBuffer)-1]=='\\')
sBuffer[strlen(sBuffer)-1]='\0';
}// if (!i++)
return sBuffer;
}
// psInitialSaveName can be "" if not bothered
LPCSTR InputSaveFileName(LPCSTR psInitialSaveName, LPCSTR psCaption, LPCSTR psInitialPath, LPCSTR psFilter, LPCSTR psExtension)
{
CFileStatus Filestatus;
CFile File;
static char name[MAX_PATH];
CString strInitialSaveName(psInitialSaveName);
strInitialSaveName.Replace("/","\\"); // or windows immediately cancels the dialog
CFileDialog FileDlg(FALSE, psExtension,
strInitialSaveName,
OFN_OVERWRITEPROMPT|OFN_CREATEPROMPT,
psFilter, //TEXT("Map Project Files (*.mpj)|*.lit|Other Map Files (*.smd/*.sc2)|*.sc2;*.smd|FastMap Files (*.fmf)|*.fmf|All Files(*.*)|*.*||"), //Map Object Files|*.sms||"),
AfxGetMainWnd()
);
// FileDlg.m_ofn.lpstrInitialDir=psInitialPath;
// FileDlg.m_ofn.lpstrTitle=psCaption;
// strcpy(name,psInitialSaveName);
// FileDlg.m_ofn.lpstrFile=name;
if (FileDlg.DoModal() == IDOK)
{
static CString strName;
strName = FileDlg.GetPathName();
return strName;
}
return NULL;
}
// "psInitialLoadName" param can be "" if not bothered, "psInitialDir" can be NULL to open to last browse-dir
//
// psFilter example: TEXT("Model files (*.glm)|*.glm|All Files(*.*)|*.*||") // LPCSTR psFilter
//
// there is too much crap in here, and some needless code, fix it sometime... (yeah, right)
//
LPCSTR InputLoadFileName(LPCSTR psInitialLoadName, LPCSTR psCaption, LPCSTR psInitialDir, LPCSTR psFilter)
{
CFileStatus Filestatus;
CFile File;
static char name[MAX_PATH];
CFileDialog FileDlg(TRUE, NULL, NULL,
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
//TEXT("Map Project Files (*.mpj)|*.lit|Other Map Files (*.smd/*.sc2)|*.sc2;*.smd|FastMap Files (*.fmf)|*.fmf|All Files(*.*)|*.*||"), //Map Object Files|*.sms||"),
psFilter, //Map Object Files|*.sms||"),
AfxGetMainWnd());
static CString strInitialDir;
if (psInitialDir)
strInitialDir = psInitialDir;
strInitialDir.Replace("/","\\");
FileDlg.m_ofn.lpstrInitialDir = (LPCSTR) strInitialDir;
FileDlg.m_ofn.lpstrTitle=psCaption; // Load Editor Model";
CString strInitialLoadName(psInitialLoadName);
strInitialLoadName.Replace("/","\\");
strcpy(name,(LPCSTR)strInitialLoadName);
FileDlg.m_ofn.lpstrFile=name;
if (FileDlg.DoModal() == IDOK)
{
return name;
}
return NULL;
}
// these MUST all be MB_TASKMODAL boxes now!!
//
bool gbErrorBox_Inhibit = false; // Keith wanted to be able to remote-deactivate these...
string strLastError;
LPCSTR ModView_GetLastError() // function for him to be able to interrogate if he's disabled the error boxes
{
return strLastError.c_str();
}
extern bool Gallery_Active();
extern void Gallery_AddError (LPCSTR psText);
extern void Gallery_AddInfo (LPCSTR psText);
extern void Gallery_AddWarning (LPCSTR psText);
void ErrorBox(const char *sString)
{
if (Gallery_Active())
{
Gallery_AddError(sString);
Gallery_AddError("\n");
return;
}
if (!gbErrorBox_Inhibit)
{
MessageBox( NULL, sString, "Error", MB_OK|MB_ICONERROR|MB_TASKMODAL );
}
strLastError = sString;
}
void InfoBox(const char *sString)
{
if (Gallery_Active())
{
Gallery_AddInfo(sString);
Gallery_AddInfo("\n");
return;
}
MessageBox( NULL, sString, "Info", MB_OK|MB_ICONINFORMATION|MB_TASKMODAL );
}
void WarningBox(const char *sString)
{
if (Gallery_Active())
{
Gallery_AddWarning(sString);
Gallery_AddWarning("\n");
return;
}
MessageBox( NULL, sString, "Warning", MB_OK|MB_ICONWARNING|MB_TASKMODAL );
}
bool GetYesNo(const char *psQuery)
{
if (Gallery_Active())
{
Gallery_AddWarning("GetYesNo call (... to which I guessed 'NO' ) using this query...\n\n");
Gallery_AddWarning(psQuery);
Gallery_AddWarning("\n");
return false;
}
//#define GetYesNo(psQuery) (!!(MessageBox(AppVars.hWnd,psQuery,"Query",MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES))
#define _GetYesNo(psQuery) (!!(AfxMessageBox(psQuery, MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES))
return _GetYesNo(psQuery);
}
void StatusMessage(LPCSTR psString) // param can be NULL to indicate fallback to "ready" or whatever you want
{
CMainFrame* pMainFrame = (CMainFrame*) AfxGetMainWnd();
if (pMainFrame)
{
pMainFrame->StatusMessage(psString);
}
}
/* this piece copied out of on-line examples, it basically works as a
similar function to Ffilelength(int handle), but it works with streams */
long filesize(FILE *handle)
{
long curpos, length;
curpos = ftell(handle);
fseek(handle, 0L, SEEK_END);
length = ftell(handle);
fseek(handle, curpos, SEEK_SET);
return length;
}
// returns -1 for error
int LoadFile (LPCSTR psPathedFilename, void **bufferptr, int bReportErrors)
{
FILE *f;
int length;
void *buffer;
f = fopen(psPathedFilename,"rb");
if (f)
{
length = filesize(f);
buffer = malloc (length+1);
((char *)buffer)[length] = 0;
int lread = fread (buffer,1,length, f);
fclose (f);
if (lread==length)
{
*bufferptr = buffer;
return length;
}
free(buffer);
}
extern bool gbInImageLoader; // tacky, but keeps quieter errors
if (bReportErrors && !gbInImageLoader)
{
ErrorBox(va("Error reading file %s!",psPathedFilename));
}
return -1;
}
// returns -1 for error
int SaveFile (LPCSTR psPathedFilename, const void *pBuffer, int iSize)
{
extern void CreatePath (const char *path);
CreatePath(psPathedFilename);
FILE *f = fopen(psPathedFilename,"wb");
if (f)
{
int iLength = fwrite(pBuffer, 1, iSize, f);
fclose (f);
if (iLength == iSize)
{
return iLength;
}
ErrorBox(va("Error writing file \"%s\" (length %d), only %d bytes written!",psPathedFilename,iSize,iLength));
return -1;
}
ErrorBox(va("Error opening file \"%s\" for writing!",psPathedFilename));
return -1;
}
// this'll return a string of up to the first 4095 chars of a system error message...
//
LPCSTR SystemErrorString(DWORD dwError)
{
static char sString[4096];
LPVOID lpMsgBuf=0;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
ZEROMEM(sString);
strncpy(sString,(LPCSTR) lpMsgBuf,sizeof(sString)-1);
LocalFree( lpMsgBuf );
return sString;
}
void SystemErrorBox(DWORD dwError)
{
ErrorBox( SystemErrorString(dwError) );
}
LPCSTR scGetComputerName(void)
{
static char cTempBuffer[128]; // well ott for laziness
DWORD dwTempBufferSize;
static int i=0;
if (!i++)
{
dwTempBufferSize = (sizeof (cTempBuffer))-1;
strcpy(cTempBuffer,"");
if (!GetComputerName(cTempBuffer, &dwTempBufferSize))
strcpy(cTempBuffer,"Unknown"); // error retrieving host computer name
}
return &cTempBuffer[0];
}
LPCSTR scGetUserName(void)
{
static char cTempBuffer[128];
DWORD dwTempBufferSize;
static int i=0;
if (!i++)
{
dwTempBufferSize = (sizeof (cTempBuffer))-1;
strcpy(cTempBuffer,"");
if (!GetUserName(cTempBuffer, &dwTempBufferSize))
strcpy(cTempBuffer,"Unknown"); // error retrieving host computer name
}
return &cTempBuffer[0];
}
bool TextFile_Read(CString &strFile, LPCSTR psFullPathedFilename, bool bLoseSlashSlashREMs /* = true */, bool bLoseBlankLines /* = true */)
{
FILE *fhTextFile = fopen(psFullPathedFilename,"rt");
if (fhTextFile)
{
char sLine[32768]; // sod it, should be enough for one line.
char *psLine;
strFile.Empty();
while ((psLine = fgets( sLine, sizeof(sLine), fhTextFile ))!=NULL)
{
if (bLoseSlashSlashREMs && !strncmp(psLine,"//",2))
{
// do nothing
}
else
{
// lose any whitespace to either side
CString strTemp(psLine);
strTemp.TrimLeft();
strTemp.TrimRight();
strTemp+="\n"; // restore the CR that got trimmed off by TrimRight()
if (bLoseBlankLines && (strTemp.IsEmpty() || strTemp.GetAt(0)=='\n'))
{
// do nothing
}
else
{
strFile += strTemp;
}
}
}
fclose(fhTextFile);
}
return !!fhTextFile;
}
bool SendFileToNotepad(LPCSTR psFilename)
{
bool bReturn = false;
char sExecString[MAX_PATH];
sprintf(sExecString,"notepad %s",psFilename);
if (WinExec(sExecString, // LPCSTR lpCmdLine, // address of command line
SW_SHOWNORMAL // UINT uCmdShow // window style for new application
)
>31 // don't ask me, Windoze just uses >31 as OK in this call.
)
{
// ok...
//
bReturn = true;
}
else
{
ErrorBox("Unable to locate/run NOTEPAD on this machine!\n\n(let me know about this -Ste)");
}
return bReturn;
}
// creates as temp file, then spawns notepad with it...
//
bool SendStringToNotepad(LPCSTR psWhatever, LPCSTR psLocalFileName)
{
bool bReturn = false;
LPCSTR psOutputFileName = va("%s\\%s",scGetTempPath(),psLocalFileName);
FILE *handle = fopen(psOutputFileName,"wt");
if (handle)
{
fprintf(handle,psWhatever);
fclose(handle);
bReturn = SendFileToNotepad(psOutputFileName);
}
else
{
ErrorBox(va("Unable to create file \"%s\" for notepad to use!",psOutputFileName));
}
return bReturn;
}
////////////////////////// eof ///////////////////////////