1
0
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-17 10:52:46 +00:00

Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin

This commit is contained in:
JWPlatt
2011-03-12 12:34:52 -05:00
commit a20a222fc2
3976 changed files with 1301355 additions and 0 deletions

View File

@ -0,0 +1,79 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plEncryptLogLine Header //
// //
//// Description /////////////////////////////////////////////////////////////
// //
// Broken into a separate file for easy include in utility apps //
// //
//////////////////////////////////////////////////////////////////////////////
#include "plEncryptLogLine.h"
#include <string.h>
void plStatusEncrypt::Encrypt( UInt8 *line, UInt8 hint )
{
// Current encryption scheme: rotate all characters right by 2 bits,
// then rotate the whole damn line by 3 bits to the right
UInt32 i, len = strlen( (char *)line );
UInt8 newHi, hiBits = ( ( line[ len - 1 ] ) << ( 5 - 2 ) ) & 0xe0;
for( i = 0; i < len; i++ )
{
// So each character will be the src char rotated right 2 bits, then shifted
// right 3 bits, or'ed with the last high bits, and the 3 discarded bits
// become the new high bits
// Too bad C doesn't have a bit-rotate op
line[ i ] = ( line[ i ] << 6 ) | ( line[ i ] >> 2 );
newHi = line[ i ] << 5;
line[ i ] = ( line[ i ] >> 3 ) | hiBits;
line[ i ] ^= hint; // Should wrap around
hiBits = newHi;
}
}
void plStatusEncrypt::Decrypt( UInt8 *line, Int32 len, UInt8 hint )
{
// Da reverse, of course!
Int32 i;
UInt8 lastChar = 0, newLo, loBits = ( line[ 0 ] ^ hint ) >> 5;
for( i = len - 1; i >= 0; i-- )
{
lastChar = line[ i ];
line[ i ] ^= hint;
newLo = line[ i ] >> 5;
line[ i ] = ( line[ i ] << 3 ) | loBits;
line[ i ] = ( line[ i ] >> 6 ) | ( line[ i ] << 2 );
loBits = newLo;
}
}

View File

@ -0,0 +1,48 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plEncryptLogLine Header //
// //
//// Description /////////////////////////////////////////////////////////////
// //
// Broken into a separate file for easy include in utility apps //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plEncryptLogLine_h
#define _plEncryptLogLine_h
#include "hsTypes.h"
namespace plStatusEncrypt
{
void Encrypt( UInt8 *line, UInt8 hint );
void Decrypt( UInt8 *line, Int32 length, UInt8 hint );
};
#endif //_plEncryptLogLine_h

View File

@ -0,0 +1,144 @@
/*==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/>.
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 "plLoggable.h"
#include "plStatusLog.h"
#include "hsStlUtils.h"
#include "hsTemplates.h"
plLoggable::~plLoggable()
{
IDeleteLog();
}
void plLoggable::IDeleteLog()
{
if ( fWeCreatedLog )
delete fStatusLog;
fWeCreatedLog = false;
fStatusLog = nil;
}
plStatusLog* plLoggable::GetLog() const
{
// create status log if necessary
if(fStatusLog==nil)
{
ICreateStatusLog(); // Usually overridden by derived class
if ( fStatusLog )
fWeCreatedLog = true;
}
#ifdef HS_DEBUGGING
if ( fComplainAboutMissingLog )
{
hsAssert(fStatusLog, "nil fStatusLog. Should override ICreateStatusLog()");
}
#endif
return fStatusLog;
}
void plLoggable::SetLog( plStatusLog * log, bool deleteOnDestruct/*=false */)
{
IDeleteLog();
fStatusLog = log;
fWeCreatedLog = deleteOnDestruct;
}
bool plLoggable::Log( const char * str ) const
{
if ( !str || strlen( str )==0 )
return true;
GetLog();
if ( fStatusLog )
return fStatusLog->AddLine( str );
return true;
}
bool plLoggable::LogF( const char * fmt, ... ) const
{
va_list args;
va_start(args, fmt);
return Log( xtl::formatv( fmt, args ).c_str() );
}
bool plLoggable::LogV( const char * fmt, va_list args ) const
{
return Log( xtl::formatv( fmt, args ).c_str() );
}
bool plLoggable::DebugMsgV(const char* fmt, va_list args) const
{
return LogF("DBG: %s", xtl::formatv(fmt,args).c_str());
}
bool plLoggable::ErrorMsgV(const char* fmt, va_list args) const
{
return LogF("ERR: %s", xtl::formatv(fmt,args).c_str());
}
bool plLoggable::WarningMsgV(const char* fmt, va_list args) const
{
return LogF("WRN: %s", xtl::formatv(fmt,args).c_str());
}
bool plLoggable::AppMsgV(const char* fmt, va_list args) const
{
return LogF("APP: %s", xtl::formatv(fmt,args).c_str());
}
///////////////////////////////////////////////////////////////
bool plLoggable::DebugMsg(const char* fmt, ...) const
{
va_list args;
va_start(args, fmt);
return DebugMsgV(fmt, args);
}
bool plLoggable::ErrorMsg(const char* fmt, ...) const
{
va_list args;
va_start(args, fmt);
return ErrorMsgV(fmt, args);
}
bool plLoggable::WarningMsg(const char* fmt, ...) const
{
va_list args;
va_start(args, fmt);
return WarningMsgV(fmt, args);
}
bool plLoggable::AppMsg(const char* fmt, ...) const
{
va_list args;
va_start(args, fmt);
return AppMsgV(fmt, args);
}

View File

@ -0,0 +1,69 @@
/*==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/>.
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 plLoggable_inc
#define plLoggable_inc
#include <stdio.h>
#include "hsTypes.h"
//
// An abstract base class which contains a status log and simple functions
// for writing Debug and Error msgs to the log
//
class plStatusLog;
class plLoggable
{
protected:
mutable plStatusLog* fStatusLog;
mutable bool fWeCreatedLog;
mutable bool fComplainAboutMissingLog;
virtual void ICreateStatusLog() const { }; // call plStatusLogMgr::CreateStatusLog with the options you want
void IDeleteLog();
public:
plLoggable() : fStatusLog(nil), fWeCreatedLog(false),fComplainAboutMissingLog(true) { }
virtual ~plLoggable();
plStatusLog* GetLog() const;
void SetLog( plStatusLog * log, bool deleteOnDestruct=false );
// logging
virtual bool Log( const char * str ) const;
virtual bool LogF( const char * fmt, ... ) const;
virtual bool LogV( const char * fmt, va_list args ) const;
virtual bool ErrorMsgV(const char* fmt, va_list args) const ;
virtual bool DebugMsgV(const char* fmt, va_list args) const ;
virtual bool WarningMsgV(const char* fmt, va_list args) const ;
virtual bool AppMsgV(const char* fmt, va_list args) const ;
virtual bool ErrorMsg(const char* fmt, ...) const ;
virtual bool DebugMsg(const char* fmt, ...) const ;
virtual bool WarningMsg(const char* fmt, ...) const ;
virtual bool AppMsg(const char* fmt, ...) const ;
};
#endif // plLoggable_inc

View File

@ -0,0 +1,906 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plStatusLog Functions //
// //
//// History /////////////////////////////////////////////////////////////////
// //
// 10.02.2001 mcn - Created //
// 10.16.2001 mcn - Added static versions of AddLine() so you don't need //
// to explicitly create a log //
// 10.17.2001 mcn - Added support for carriage returns in printed lines //
// 10.24.2002 eap - Added kDebugOutput flag for writing to debug window //
// 10.25.2002 eap - Updated to work under unix //
// 12.13.2002 eap - Added kStdout flag //
// //
//////////////////////////////////////////////////////////////////////////////
#include <stdarg.h>
#include <stdlib.h>
#include "hsThread.h"
#include "hsTemplates.h"
#include "hsTimer.h"
#include "hsStlUtils.h"
#include "../plFile/plFileUtils.h"
#include "plStatusLog.h"
#include "plPipeline.h"
#include "../plPipeline/plDebugText.h"
#include "hsStlUtils.h"
#include "../plFile/hsFiles.h"
#include "../plUnifiedTime/plUnifiedTime.h"
#include "../pnNetCommon/plNetApp.h"
#include "../pnUtils/pnUtils.h"
#include "../pnProduct/pnProduct.h"
#include "plEncryptLogLine.h"
#if HS_BUILD_FOR_UNIX
#include <limits.h>
#define MAX_PATH PATH_MAX
#endif
//////////////////////////////////////////////////////////////////////////////
//// plStatusLogMgr Stuff ////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
wchar plStatusLogMgr::fBasePath[ MAX_PATH ] = L"";
//// Constructor & Destructor ////////////////////////////////////////////////
plStatusLogMgr::plStatusLogMgr()
{
fDisplays = nil;
fCurrDisplay = nil;
fDrawer = nil;
fLastLogChangeTime = 0;
PathGetLogDirectory(fBasePath, arrsize(fBasePath));
}
plStatusLogMgr::~plStatusLogMgr()
{
// Unlink all the displays, but don't delete them; leave that to whomever owns them
while( fDisplays != nil )
{
plStatusLog *log = fDisplays;
fDisplays->IUnlink();
if( log->fFlags & plStatusLog::kDeleteForMe )
DEL(log);
}
}
plStatusLogMgr &plStatusLogMgr::GetInstance( void )
{
static plStatusLogMgr theManager;
return theManager;
}
//// IEnsurePathExists ///////////////////////////////////////////////////////
void plStatusLogMgr::IEnsurePathExists( const wchar *dirName )
{
// Note: this creates the directory if it doesn't exist, or if it does,
// returns false
plFileUtils::CreateDir( dirName );
}
//// IPathAppend /////////////////////////////////////////////////////////////
void plStatusLogMgr::IPathAppend( wchar *base, const wchar *extra, unsigned maxLen )
{
if (!base || !extra)
return;
unsigned baseLen = wcslen(base);
unsigned extraLen = wcslen(extra);
bool needsSeparator = false;
if (baseLen >= 1)
needsSeparator = (base[baseLen - 1] != WPATH_SEPARATOR);
if (needsSeparator)
{
if ((baseLen + 1 + 1) >= maxLen)
return; // abort, buffer isn't big enough
base[baseLen] = WPATH_SEPARATOR;
++baseLen;
base[baseLen] = '\0';
}
// concat the strings, making sure not to overrun the buffer
unsigned curExtraPos = 0;
for (unsigned curBasePos = baseLen; curBasePos < maxLen; ++curBasePos)
{
base[curBasePos] = extra[curExtraPos];
if (extra[curExtraPos] == '\0')
break; // done
++curExtraPos;
}
// ensure we are null-terminated
base[maxLen - 1] = '\0';
}
//// Draw ////////////////////////////////////////////////////////////////////
void plStatusLogMgr::Draw( void )
{
/// Just draw current plStatusLog
if( fCurrDisplay != nil && fDrawer != nil )
{
plStatusLog* firstLog = nil;
if (hsTimer::GetSysSeconds() - fLastLogChangeTime < 1)
firstLog = fDisplays;
fDrawer->Draw(fCurrDisplay, firstLog);
}
}
//// CreateStatusLog /////////////////////////////////////////////////////////
plStatusLog *plStatusLogMgr::CreateStatusLog( UInt8 numDisplayLines, const char *filename, UInt32 flags )
{
wchar* wFilename = hsStringToWString(filename);
plStatusLog* ret = CreateStatusLog(numDisplayLines, wFilename, flags);
delete [] wFilename;
return ret;
}
plStatusLog *plStatusLogMgr::CreateStatusLog( UInt8 numDisplayLines, const wchar *filename, UInt32 flags )
{
IEnsurePathExists( fBasePath );
plStatusLog *log = NEW(plStatusLog)( numDisplayLines, filename, flags );
// Put the new log in its alphabetical position
plStatusLog** nextLog = &fDisplays;
while (*nextLog)
{
if (wcsicmp(filename, (*nextLog)->GetFileNameW()) <= 0)
break;
nextLog = &(*nextLog)->fNext;
}
log->ILink(nextLog);
log->fDisplayPointer = &fCurrDisplay;
return log;
}
//// ToggleStatusLog /////////////////////////////////////////////////////////
void plStatusLogMgr::ToggleStatusLog( plStatusLog *logToDisplay )
{
if( fCurrDisplay == logToDisplay )
fCurrDisplay = nil;
else
fCurrDisplay = logToDisplay;
fLastLogChangeTime = hsTimer::GetSysSeconds();
}
//// SetCurrStatusLog ////////////////////////////////////////////////////////
void plStatusLogMgr::SetCurrStatusLog(const char* logName)
{
wchar* wLogName = hsStringToWString(logName);
SetCurrStatusLog(wLogName);
delete [] wLogName;
}
void plStatusLogMgr::SetCurrStatusLog(const wchar* logName)
{
plStatusLog* log = FindLog(logName, false);
if (log != nil)
fCurrDisplay = log;
}
//// NextStatusLog ///////////////////////////////////////////////////////////
void plStatusLogMgr::NextStatusLog( void )
{
if( fCurrDisplay == nil )
fCurrDisplay = fDisplays;
else
fCurrDisplay = fCurrDisplay->fNext;
fLastLogChangeTime = hsTimer::GetSysSeconds();
}
void plStatusLogMgr::PrevStatusLog( void )
{
if( fCurrDisplay == nil )
{
fCurrDisplay = fDisplays;
while (fCurrDisplay && fCurrDisplay->fNext)
fCurrDisplay = fCurrDisplay->fNext;
}
else
{
plStatusLog* lastLog = fDisplays;
while (lastLog && lastLog->fNext != fCurrDisplay)
lastLog = lastLog->fNext;
fCurrDisplay = lastLog;
}
fLastLogChangeTime = hsTimer::GetSysSeconds();
}
//// FindLog ////////////////////////////////////////////////////////////////
plStatusLog *plStatusLogMgr::FindLog( const char *filename, hsBool createIfNotFound )
{
wchar* wFilename = hsStringToWString(filename);
plStatusLog* ret = FindLog(wFilename, createIfNotFound);
delete [] wFilename;
return ret;
}
plStatusLog *plStatusLogMgr::FindLog( const wchar *filename, hsBool createIfNotFound )
{
plStatusLog *log = fDisplays;
while( log != nil )
{
if( wcsicmp( log->GetFileNameW(), filename ) == 0 )
return log;
log = log->fNext;
}
if( !createIfNotFound )
return nil;
// Didn't find one, so create one! (make it a nice default one :)
log = CreateStatusLog( kDefaultNumLines, filename, plStatusLog::kFilledBackground |
plStatusLog::kDeleteForMe );
return log;
}
//// SetBasePath ////////////////////////////////////////////////////////////////
void plStatusLogMgr::SetBasePath( const char * path )
{
wchar* wPath = hsStringToWString(path);
SetBasePath(wPath);
delete [] wPath;
}
void plStatusLogMgr::SetBasePath( const wchar * path )
{
wcscpy( fBasePath, path );
}
//// BounceLogs ///////////////////////////////////////////////////////////////
void plStatusLogMgr::BounceLogs()
{
plStatusLog *log = fDisplays;
while( log != nil )
{
plStatusLog * tmp = log;
log = log->fNext;
tmp->Bounce();
}
}
//// DumpLogs ////////////////////////////////////////////////////////////////
bool plStatusLogMgr::DumpLogs( const char *newFolderName )
{
wchar* wFolderName = hsStringToWString(newFolderName);
bool ret = DumpLogs(wFolderName);
delete [] wFolderName;
return ret;
}
bool plStatusLogMgr::DumpLogs( const wchar *newFolderName )
{
bool retVal = true; // assume success
// create root path and make sure it exists
wchar temp[MAX_PATH];
std::wstring newPath = L"";
if (fBasePath)
{
wcsncpy(temp, fBasePath, MAX_PATH);
IPathAppend(temp, newFolderName, MAX_PATH);
newPath = temp;
}
else
newPath = newFolderName;
IEnsurePathExists(newPath.c_str());
hsWFolderIterator folderIterator;
if (fBasePath)
folderIterator.SetPath(fBasePath);
else
folderIterator.SetPath(L".");
while (folderIterator.NextFile())
{
if (folderIterator.IsDirectory())
continue;
std::wstring baseFilename = folderIterator.GetFileName();
std::wstring source;
if (fBasePath)
{
wcsncpy(temp, fBasePath, MAX_PATH);
IPathAppend(temp, baseFilename.c_str(), MAX_PATH);
source = temp;
}
else
source = baseFilename;
std::wstring destination;
wcsncpy(temp, newPath.c_str(), MAX_PATH);
IPathAppend(temp, baseFilename.c_str(), MAX_PATH);
destination = temp;
bool succeeded = (CopyFileW(source.c_str(), destination.c_str(), FALSE) != 0);
retVal = retVal && succeeded;
}
return retVal;
}
//////////////////////////////////////////////////////////////////////////////
//// plStatusLog ////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
#if defined(PLASMA_EXTERNAL_RELEASE) && (BUILD_TYPE == BUILD_TYPE_LIVE)
// If this is an external live build then don't write log files
UInt32 plStatusLog::fLoggingOff = true;
#else
UInt32 plStatusLog::fLoggingOff = false;
#endif
plStatusLog::plStatusLog( UInt8 numDisplayLines, const wchar *filename, UInt32 flags )
{
fFileHandle = nil;
fSize = 0;
fForceLog = false;
fMaxNumLines = numDisplayLines;
if( filename != nil )
{
fFilename = filename;
char* temp = hsWStringToString(filename);
fCFilename = temp;
delete [] temp;
}
else
{
fFilename = L"";
fCFilename = "";
flags |= kDontWriteFile;
}
fOrigFlags = fFlags = flags;
IInit();
}
plStatusLog::~plStatusLog()
{
IFini();
}
void plStatusLog::IInit()
{
int i;
fFlags = fOrigFlags;
fLines = TRACKED_NEW char *[ fMaxNumLines ];
fColors = TRACKED_NEW UInt32[ fMaxNumLines ];
for( i = 0; i < fMaxNumLines; i++ )
{
fLines[ i ] = nil;
fColors[ i ] = kWhite;
}
fNext = nil;
fBack = nil;
}
bool plStatusLog::IReOpen( void )
{
if( fFileHandle != nil )
{
fclose( fFileHandle );
fFileHandle = nil;
}
// Open the file, clearing it, if necessary
if(!(fFlags & kDontWriteFile))
{
wchar file[ MAX_PATH ];
wchar fileNoExt[MAX_PATH];
wchar* ext=nil;
IParseFileName(file, fileNoExt, &ext);
fEncryptMe = false;
#ifdef PLASMA_EXTERNAL_RELEASE
fEncryptMe = ( wcsicmp( fFilename.c_str(), L"chat.log" ) != 0 ) ? true : false;
if( fEncryptMe )
ext = L".elf";
#endif
wchar fileToOpen[MAX_PATH];
swprintf(fileToOpen, L"%s.0%s", fileNoExt, ext);
if (!(fFlags & kDontRotateLogs))
{
wchar work[MAX_PATH], work2[MAX_PATH];
swprintf(work, L"%s.3%s",fileNoExt,ext);
_wremove(work);
swprintf(work2, L"%s.2%s",fileNoExt,ext);
_wrename(work2, work);
swprintf(work, L"%s.1%s",fileNoExt,ext);
_wrename(work, work2);
_wrename(fileToOpen, work);
}
if (fFlags & kAppendToLast)
{
fFileHandle = _wfopen( fileToOpen, fEncryptMe ? L"ab" : L"at" );
}
else
{
fFileHandle = _wfopen( fileToOpen, fEncryptMe ? L"wb" : L"wt" );
// if we need to reopen lets just append
fFlags |= kAppendToLast;
}
}
if (fFileHandle)
fSize = ftell( fFileHandle );
else
fSize = 0;
return fFileHandle != nil;
}
void plStatusLog::IFini( void )
{
int i;
if( fFileHandle != nil )
{
fclose( fFileHandle );
fFileHandle = nil;
}
if( *fDisplayPointer == this )
*fDisplayPointer = nil;
if( fBack != nil || fNext != nil )
IUnlink();
for( i = 0; i < fMaxNumLines; i++ )
delete [] fLines[ i ];
delete [] fLines;
delete [] fColors;
}
void plStatusLog::IParseFileName(wchar* file, wchar* fileNoExt, wchar** ext) const
{
const wchar *base = plStatusLogMgr::IGetBasePath();
if( wcslen( base ) != nil )
swprintf( file, L"%s%s%s", base, WPATH_SEPARATOR_STR, fFilename.c_str() );
else
wcscpy( file, fFilename.c_str() );
plFileUtils::EnsureFilePathExists( file );
// apache-style file backup
*ext = wcsrchr(file, L'.');
if (*ext)
{
int fileLen = *ext - file;
wcsncpy(fileNoExt, file, fileLen);
fileNoExt[fileLen] = L'\0';
}
else
{
wcscpy(fileNoExt, file);
*ext = L"";
}
}
//// IUnlink /////////////////////////////////////////////////////////////////
void plStatusLog::IUnlink( void )
{
hsAssert( fBack, "plStatusLog not in list" );
if( fNext )
fNext->fBack = fBack;
*fBack = fNext;
fBack = nil;
fNext = nil;
}
//// ILink ///////////////////////////////////////////////////////////////////
void plStatusLog::ILink( plStatusLog **back )
{
hsAssert( fNext == nil && fBack == nil, "Trying to link a plStatusLog that's already linked" );
fNext = *back;
if( *back )
(*back)->fBack = &fNext;
fBack = back;
*back = this;
}
//// IAddLine ////////////////////////////////////////////////////////////////
// Actually add a stinking line.
bool plStatusLog::IAddLine( const char *line, Int32 count, UInt32 color )
{
int i;
if(fLoggingOff && !fForceLog)
return true;
/// Scroll pointers up
hsTempMutexLock lock( fMutex );
bool ret = true;
if (fMaxNumLines > 0)
{
delete [] fLines[ 0 ];
for( i = 0; i < fMaxNumLines - 1; i++ )
{
fLines[ i ] = fLines[ i + 1 ];
fColors[ i ] = fColors[ i + 1 ];
}
}
/// Add new
if( line == nil || strlen( line ) == 0 )
{
if (fMaxNumLines > 0)
{
fColors[ i ] = 0;
fLines[ i ] = nil;
}
ret = IPrintLineToFile( "", 0 );
}
else
{
if( count < 0 )
count = strlen( line );
if (fMaxNumLines > 0)
{
fLines[ i ] = TRACKED_NEW char[ count + 1 ];
hsStrncpy( fLines[ i ], line, count + 1 );
fLines[ i ][ count ] = 0;
char *c = strchr( fLines[ i ], '\n' );
if( c != nil )
{
*c = 0;
count--;
}
fColors[ i ] = color;
}
ret = IPrintLineToFile( line, count );
}
return ret;
}
//// AddLine /////////////////////////////////////////////////////////////////
bool plStatusLog::AddLine( const char *line, UInt32 color )
{
char *c, *str;
if(fLoggingOff && !fForceLog)
return true;
bool ret = true;
/// Scan for carriage returns and feed each section into IAddLine()
for( str = (char *)line; ( c = strchr( str, '\n' ) ) != nil; str = c + 1 )
{
// So if we got here, c points to a carriage return...
ret = IAddLine( str, (UInt32)c - (UInt32)str, color );
}
/// We might have some left over
if( strlen( str ) > 0 )
{
ret &= IAddLine( str, -1, color );
}
return ret;
}
//// AddLine printf-style Variations /////////////////////////////////////////
bool plStatusLog::AddLineV( const char *format, va_list arguments )
{
if(fLoggingOff && !fForceLog)
return true;
return AddLineV( kWhite, format, arguments );
}
bool plStatusLog::AddLineV( UInt32 color, const char *format, va_list arguments )
{
if(fLoggingOff && !fForceLog)
return true;
char buffer[2000];
vsprintf(buffer, format, arguments);
return AddLine( buffer, color );
}
bool plStatusLog::AddLineF( const char *format, ... )
{
if(fLoggingOff && !fForceLog)
return true;
va_list arguments;
va_start( arguments, format );
return AddLineV( kWhite, format, arguments );
}
bool plStatusLog::AddLineF( UInt32 color, const char *format, ... )
{
if(fLoggingOff && !fForceLog)
return true;
va_list arguments;
va_start( arguments, format );
return AddLineV( color, format, arguments );
}
//// AddLine Static Variations ///////////////////////////////////////////////
bool plStatusLog::AddLineS( const char *filename, const char *format, ... )
{
plStatusLog *log = plStatusLogMgr::GetInstance().FindLog( filename );
if(fLoggingOff && !log->fForceLog)
return true;
va_list arguments;
va_start( arguments, format );
return log->AddLineV( format, arguments );
}
bool plStatusLog::AddLineS( const char *filename, UInt32 color, const char *format, ... )
{
plStatusLog *log = plStatusLogMgr::GetInstance().FindLog( filename );
if(fLoggingOff && !log->fForceLog)
return true;
va_list arguments;
va_start( arguments, format );
return log->AddLineV( color, format, arguments );
}
//// Clear ///////////////////////////////////////////////////////////////////
void plStatusLog::Clear( void )
{
int i;
for( i = 0; i < fMaxNumLines; i++ )
{
delete [] fLines[ i ];
fLines[ i ] = nil;
}
}
//// Bounce //////////////////////////////////////////////////////////////////
void plStatusLog::Bounce( UInt32 flags)
{
if (flags)
fOrigFlags=flags;
Clear();
if( fFileHandle != nil )
{
fclose( fFileHandle );
fFileHandle = nil;
}
AddLine( "--------- Bounced Log ---------" );
}
//// IPrintLineToFile ////////////////////////////////////////////////////////
bool plStatusLog::IPrintLineToFile( const char *line, UInt32 count )
{
if( fFlags & kDontWriteFile )
return true;
#ifdef PLASMA_EXTERNAL_RELEASE
UInt8 hint = 0;
if( fFlags & kAppendToLast )
{
hint = (UInt8)fSize;
}
#endif
if (!fFileHandle)
IReOpen();
bool ret = ( fFileHandle!=nil );
if( fFileHandle != nil )
{
char work[256];
char buf[2000];
buf[0] = 0;
//build line to encrypt
if( count != 0 )
{
if ( fFlags & kTimestamp )
{
StrPrintf(work, arrsize(work), "(%s) ", plUnifiedTime(kNow).Format("%m/%d %H:%M:%S").c_str());
StrPack(buf, work, arrsize(buf));
}
if ( fFlags & kTimestampGMT )
{
StrPrintf(work, arrsize(work), "(%s) ", plUnifiedTime::GetCurrentTime().Format("%m/%d %H:%M:%S UTC").c_str());
StrPack(buf, work, arrsize(buf));
}
if ( fFlags & kTimeInSeconds )
{
StrPrintf(work, arrsize(work), "(%u) ", plUnifiedTime(kNow).GetSecs());
StrPack(buf, work, arrsize(buf));
}
if ( fFlags & kTimeAsDouble )
{
StrPrintf(work, arrsize(work), "(%f) ", plUnifiedTime(kNow).GetSecsDouble());
StrPack(buf, work, arrsize(buf));
}
if (fFlags & kRawTimeStamp)
{
StrPrintf(work, arrsize(work), "[t=%10u] ", hsTimer::GetSeconds());
StrPack(buf, work, arrsize(buf));
}
if (fFlags & kThreadID)
{
StrPrintf(work, arrsize(work), "[t=%u] ", hsThread::GetMyThreadId());
StrPack(buf, work, arrsize(buf));
}
// find the size of the buf plus the size of the line and only pack that much
unsigned BufAndLine = StrLen(buf)+count+1;
if ( BufAndLine > arrsize(buf) )
BufAndLine = arrsize(buf);
StrPack(buf, line, BufAndLine );
if(!fEncryptMe )
{
StrPack(buf, "\n", arrsize(buf));
}
}
unsigned length = StrLen(buf);
#ifdef PLASMA_EXTERNAL_RELEASE
// Print to a separate line, since we have to encrypt it
if( fEncryptMe )
{
// Encrypt!
plStatusEncrypt::Encrypt( (UInt8 *)buf, hint );
// xor the line length, then write it out, then the line, no terminating character
UInt16 encrySize = length ^ ((UInt16)fSize);
// try the first write, if it fails reopen and try again
int err;
err = fputc( encrySize & 0xff, fFileHandle );
if (err == EOF && IReOpen())
{
err = fputc( encrySize & 0xff, fFileHandle );
}
if (err != EOF)
{
fSize++; // inc for the last putc
err = fputc( encrySize >> 8, fFileHandle );
if (err != EOF)
fSize++; // inc for the last putc
err = fwrite( buf, 1, length, fFileHandle );
fSize += err;
if (!(fFlags & kNonFlushedLog))
fflush(fFileHandle);
}
else
{
ret = false;
}
}
else
#endif
{
int err;
err = fwrite(buf,1,length,fFileHandle);
ret = ( ferror( fFileHandle )==0 );
if ( ret )
{
fSize += err;
if (!(fFlags & kNonFlushedLog))
fflush(fFileHandle);
}
}
if ( fSize>=kMaxFileSize )
{
plStatusLogMgr::GetInstance().BounceLogs();
}
}
if ( fFlags & kDebugOutput )
{
#if HS_BUILD_FOR_WIN32
#ifndef PLASMA_EXTERNAL_RELEASE
std::string str;
xtl::format( str, "%.*s\n", count, line );
OutputDebugString( str.c_str() );
#endif
#else
fprintf( stderr, "%.*s\n", count, line );
#endif
}
if ( fFlags & kStdout )
{
fprintf( stdout, "%.*s\n", count, line );
}
return ret;
}

View File

@ -0,0 +1,261 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plStatusLog Header //
// //
//// Description /////////////////////////////////////////////////////////////
// //
// plStatusLogs are our new encapsulated method of outputting text logs //
// for status (or other things, like, say, errors). They do more than just //
// output to the file, though; they maintain a scrolling buffer that //
// can be drawn on to the screen so you can actually view what's being //
// outputted to the log file (you can disable file writing if you wish). //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plStatusLog_h
#define _plStatusLog_h
#include "hsTypes.h"
#include "hsThread.h"
#include <string>
class plPipeline;
//// plStatusLog Definition //////////////////////////////////////////////////
// Currently, they all display in the same location, so only one should
// really be visible at any given time.
class plStatusLogMgr;
class hsMutex;
class plStatusLogDrawerStub;
class plStatusLog
{
friend class plStatusLogMgr;
friend class plStatusLogDrawerStub;
friend class plStatusLogDrawer;
protected:
mutable UInt32 fFlags; // Mutable so we can change it in IPrintLineToFile() internally
UInt32 fOrigFlags;
UInt32 fMaxNumLines;
std::string fCFilename; // used ONLY by GetFileName()
std::wstring fFilename;
char **fLines;
UInt32 *fColors;
hsMutex fMutex; // To make multithreaded-safe
FILE* fFileHandle;
UInt32 fSize;
bool fEncryptMe;
bool fForceLog;
plStatusLog *fNext, **fBack;
plStatusLog **fDisplayPointer; // Inside pfConsole
void IUnlink( void );
void ILink( plStatusLog **back );
bool IAddLine( const char *line, Int32 count, UInt32 color );
bool IPrintLineToFile( const char *line, UInt32 count );
void IParseFileName(wchar* file, wchar* fileNoExt, wchar** ext) const;
void IInit( void );
void IFini( void );
bool IReOpen( void );
plStatusLog( UInt8 numDisplayLines, const wchar *filename, UInt32 flags );
public:
static UInt32 fLoggingOff;
enum StatusFlagType
{
kFilledBackground = 0x00000001,
kAppendToLast = 0x00000002,
kDontWriteFile = 0x00000004,
kDeleteForMe = 0x00000008, // BE CAREFUL USING THIS!!
// kDeleteForMe instructs the statusLogMgr to delete
// this log itself when it destructs, which is at the
// very end of client shutdown (the manager is static).
// Because of this, it's safe to use this so long as you'll
// never reference it at the very end of shutdown (as an
// object is deleted by the resManager, for example, is
// okay because that's done in plClient::Shutdown(), not
// at the very end of app destruction). If you use this
// and your log is deleted before you, your pointer will
// NOT reflect this; it's up to you
kAlignToTop = 0x00000010,
kDebugOutput = 0x00000020, // Also write string to debug console
kTimestamp = 0x00000040, // Write a timestamp in Local time with each entry.
kStdout = 0x00000080, // Also write string to stdout
kTimeInSeconds = 0x00000100, // Write timestamp as seconds since epoch
kTimeAsDouble = 0x00000200, // Write timestamp as seconds.millis
kDontRotateLogs = 0x00000400, // Don't rename/renumber log fileName
kServerTimestamp = 0x00000800, // Timestamp each entry with the server's time
kRawTimeStamp = 0x00001000, // hsTimer::GetSeconds()
kThreadID = 0x00002000, // ID of current thread
kTimestampGMT = 0x00004000, // Write a timestamp in GMT with each entry.
kNonFlushedLog = 0x00008000, // Do not flush the log after each write
};
enum
{
kRed = 0xffff0000,
kGreen = 0xff00ff00,
kBlue = 0xff0000ff,
kYellow = 0xffffff00,
kWhite = 0xffffffff
};
enum
{
kMaxFileSize = 300000000, // 300 megs
};
~plStatusLog();
bool AddLine( const char *line, UInt32 color = kWhite );
/// printf-like functions
bool AddLineF( const char *format, ... );
bool AddLineF( UInt32 color, const char *format, ... );
bool AddLineV( const char *format, va_list arguments );
bool AddLineV( UInt32 color, const char *format, va_list arguments );
/// Static functions that you give a filename to and it searches for a log based on that
/// (or creates one if it isn't available)
static bool AddLineS( const char *filename, const char *format, ... );
static bool AddLineS( const char *filename, UInt32 color, const char *format, ... );
void Clear( void );
// Clear and open a new file.
void Bounce( UInt32 flags=0 );
const char* GetFileName() const {return fCFilename.c_str();}
const wchar* GetFileNameW() const {return fFilename.c_str();}
void SetForceLog(bool force) { fForceLog = force; }
};
//// Manager Class Definition ////////////////////////////////////////////////
class plStatusLogMgr
{
friend class plStatusLog;
private:
plStatusLogMgr();
static plStatusLogMgr fManager;
protected:
plStatusLog *fDisplays;
plStatusLog *fCurrDisplay;
plStatusLogDrawerStub *fDrawer;
double fLastLogChangeTime;
static wchar fBasePath[];
static const wchar *IGetBasePath( void ) { return fBasePath; }
void IEnsurePathExists( const wchar *dirName );
void IPathAppend( wchar *base, const wchar *extra, unsigned maxLen );
hsMutex fMutex; // To make multithreaded-safe
public:
enum
{
kDefaultNumLines = 40
};
~plStatusLogMgr();
static plStatusLogMgr &GetInstance( void );
void Draw( void );
plStatusLog *CreateStatusLog( UInt8 numDisplayLines, const char *filename, UInt32 flags = plStatusLog::kFilledBackground );
plStatusLog *CreateStatusLog( UInt8 numDisplayLines, const wchar *filename, UInt32 flags = plStatusLog::kFilledBackground );
void ToggleStatusLog( plStatusLog *logToDisplay );
void NextStatusLog( void );
void PrevStatusLog( void );
void SetCurrStatusLog( const char *logName );
void SetCurrStatusLog( const wchar *logName );
plStatusLog *FindLog( const char *filename, hsBool createIfNotFound = true );
plStatusLog *FindLog( const wchar *filename, hsBool createIfNotFound = true );
void SetDrawer( plStatusLogDrawerStub *drawer ) { fDrawer = drawer; }
void SetBasePath( const char * path );
void SetBasePath( const wchar * path );
void BounceLogs();
// Create a new folder and copy all log files into it (returns false on failure)
bool DumpLogs( const char *newFolderName );
bool DumpLogs( const wchar *newFolderName );
};
//// plStatusLogDrawerStub Class ////////////////////////////////////////////
// Sometimes, we want to be able to link to plStatusLog without having the
// pipeline-drawing functionality. So we do it this way: we define a single
// class of type plStatusLogDrawerStub. If it's allocated and we're given a
// pointer to it (by, say, the pipeline), then we use it to draw and all
// is happy. If not, we don't draw.
class plStatusLogDrawerStub
{
protected:
UInt32 IGetMaxNumLines( plStatusLog *log ) const { return log->fMaxNumLines; }
char **IGetLines( plStatusLog *log ) const { return log->fLines; }
const char *IGetFilename( plStatusLog *log ) const { return log->GetFileName(); }
const wchar *IGetFilenameW( plStatusLog *log ) const { return log->GetFileNameW(); }
UInt32 *IGetColors( plStatusLog *log ) const { return log->fColors; }
UInt32 IGetFlags( plStatusLog *log ) const { return log->fFlags; }
public:
virtual ~plStatusLogDrawerStub() {}
virtual void Draw(plStatusLog* curLog, plStatusLog* firstLog) {}
};
#endif //_plStatusLog_h