287 lines
7.7 KiB
C++
287 lines
7.7 KiB
C++
/*
|
|
* This is a part of the BugTrap package.
|
|
* Copyright (c) 2005-2009 IntelleSoft.
|
|
* All rights reserved.
|
|
*
|
|
* Description: Text log file.
|
|
* Author: Maksim Pyatkovskiy.
|
|
*
|
|
* This source code is only intended as a supplement to the
|
|
* BugTrap package reference and related electronic documentation
|
|
* provided with the product. See these sources for detailed
|
|
* information regarding the BugTrap package.
|
|
*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "TextLogFile.h"
|
|
#include "TextFormat.h"
|
|
#include "Globals.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
/**
|
|
* @return true if the log was loaded successfully.
|
|
*/
|
|
BOOL CTextLogFile::LoadEntries(void)
|
|
{
|
|
#ifdef _DEBUG
|
|
DWORD dwStartTime = GetTickCount();
|
|
#endif
|
|
BOOL bResult = FALSE;
|
|
PCTSTR pszLogFileName = GetLogFileName();
|
|
HANDLE hFile = CreateFile(pszLogFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwFileSize = (DWORD)GetFileSize(hFile, NULL);
|
|
if (dwFileSize == 0)
|
|
{
|
|
// ignore empty files
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
DWORD dwBufferSize = min(dwFileSize, g_dwMaxBufferSize);
|
|
PBYTE pFileBuffer = new BYTE[dwBufferSize];
|
|
if (pFileBuffer)
|
|
{
|
|
BYTE arrUTF8Preamble[sizeof(g_arrUTF8Preamble)];
|
|
DWORD dwWritten = 0;
|
|
if (ReadFile(hFile, arrUTF8Preamble, sizeof(arrUTF8Preamble), &dwWritten, NULL) &&
|
|
dwWritten == sizeof(arrUTF8Preamble) && memcmp(arrUTF8Preamble, g_arrUTF8Preamble, sizeof(arrUTF8Preamble)) == 0)
|
|
{
|
|
bResult = TRUE;
|
|
DWORD dwCurrentPos = 0, dwLineStart = 0;
|
|
for (;;)
|
|
{
|
|
dwWritten = 0;
|
|
DWORD dwFreeSize = dwBufferSize - dwCurrentPos;
|
|
if (! ReadFile(hFile, pFileBuffer + dwCurrentPos, dwFreeSize, &dwWritten, NULL))
|
|
goto end;
|
|
BOOL bEndOfFile = dwWritten < dwFreeSize;
|
|
dwWritten += dwCurrentPos;
|
|
dwCurrentPos = 0;
|
|
if (dwWritten == 0)
|
|
goto end;
|
|
for (;;)
|
|
{
|
|
if (dwCurrentPos >= dwWritten && ! bEndOfFile)
|
|
{
|
|
if (dwLineStart > 0)
|
|
{
|
|
dwCurrentPos -= dwLineStart;
|
|
MoveMemory(pFileBuffer, pFileBuffer + dwLineStart, dwCurrentPos);
|
|
dwLineStart = 0;
|
|
}
|
|
else
|
|
{
|
|
dwBufferSize *= 2;
|
|
PBYTE pNewFileBuffer = new BYTE[dwBufferSize];
|
|
if (! pNewFileBuffer)
|
|
{
|
|
bResult = FALSE;
|
|
goto end;
|
|
}
|
|
CopyMemory(pNewFileBuffer, pFileBuffer, dwCurrentPos);
|
|
delete[] pFileBuffer;
|
|
pFileBuffer = pNewFileBuffer;
|
|
}
|
|
break;
|
|
}
|
|
if (dwCurrentPos < dwWritten ? pFileBuffer[dwCurrentPos] == '\r' || pFileBuffer[dwCurrentPos] == '\n' : bEndOfFile)
|
|
{
|
|
if (dwLineStart < dwCurrentPos && ! AddToTail(pFileBuffer + dwLineStart, dwCurrentPos - dwLineStart, true))
|
|
{
|
|
bResult = FALSE;
|
|
goto end;
|
|
}
|
|
if (dwCurrentPos == dwWritten) // bEndOfFile == TRUE, see condition above
|
|
{
|
|
bResult = TRUE;
|
|
goto end;
|
|
}
|
|
dwLineStart = dwCurrentPos + 1;
|
|
}
|
|
++dwCurrentPos;
|
|
}
|
|
}
|
|
}
|
|
end:
|
|
if (! bResult)
|
|
FreeEntries();
|
|
delete[] pFileBuffer;
|
|
}
|
|
CloseHandle(hFile);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
if (dwLastError == ERROR_FILE_NOT_FOUND ||
|
|
dwLastError == ERROR_PATH_NOT_FOUND ||
|
|
GetFileAttributes(pszLogFileName) == INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
bResult = TRUE; // ignore missing files
|
|
}
|
|
}
|
|
#ifdef _DEBUG
|
|
DWORD dwEndTime = GetTickCount();
|
|
TCHAR szMessage[128];
|
|
_stprintf_s(szMessage, countof(szMessage), _T("CTextLogFile::LoadEntries(): %lu entries, %lu bytes, %lu milliseconds\r\n"), GetNumEntries(), GetNumBytes(), dwEndTime - dwStartTime);
|
|
OutputDebugString(szMessage);
|
|
#endif
|
|
return bResult;
|
|
}
|
|
|
|
/**
|
|
* @param bCrash - true if crash has occurred.
|
|
* @return true if the log was saved successfully.
|
|
*/
|
|
BOOL CTextLogFile::SaveEntries(BOOL /*bCrash*/)
|
|
{
|
|
#ifdef _DEBUG
|
|
DWORD dwStartTime = GetTickCount();
|
|
#endif
|
|
PCTSTR pszLogFileName = GetLogFileName();
|
|
HANDLE hFile = CreateFile(pszLogFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
DWORD dwWritten;
|
|
WriteFile(hFile, g_arrUTF8Preamble, sizeof(g_arrUTF8Preamble), &dwWritten, NULL);
|
|
CLogEntry* pLogEntry = GetFirstEntry();
|
|
while (pLogEntry)
|
|
{
|
|
CTextLogEntry* pTextLogEntry = (CTextLogEntry*)pLogEntry;
|
|
WriteFile(hFile, pTextLogEntry->m_pbData, pTextLogEntry->m_dwSize, &dwWritten, NULL);
|
|
pLogEntry = pLogEntry->m_pNextEntry;
|
|
}
|
|
#ifdef _DEBUG
|
|
DWORD dwEndTime = GetTickCount();
|
|
TCHAR szMessage[128];
|
|
_stprintf_s(szMessage, countof(szMessage), _T("CTextLogFile::SaveEntries(): %lu entries, %lu bytes, %lu milliseconds\r\n"), GetNumEntries(), GetNumBytes(), dwEndTime - dwStartTime);
|
|
OutputDebugString(szMessage);
|
|
#endif
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @param pbData - entry data.
|
|
* @param dwSize - data size.
|
|
* @param bAddCrLf - true if CR/LF must be added.
|
|
* @return pointer to the new entry.
|
|
*/
|
|
CTextLogFile::CTextLogEntry* CTextLogFile::AllocLogEntry(const BYTE* pbData, DWORD dwSize, BOOL bAddCrLf)
|
|
{
|
|
DWORD dwFullSize = bAddCrLf ? dwSize + 2 : dwSize;
|
|
CTextLogEntry* pLogEntry = (CTextLogEntry*)new BYTE[sizeof(CTextLogEntry) + dwFullSize];
|
|
if (pLogEntry)
|
|
{
|
|
pLogEntry->m_dwSize = dwFullSize;
|
|
PBYTE pDstData = pLogEntry->m_pbData;
|
|
CopyMemory(pDstData, pbData, dwSize);
|
|
if (bAddCrLf)
|
|
{
|
|
pDstData[dwSize++] = _T('\r');
|
|
pDstData[dwSize++] = _T('\n');
|
|
}
|
|
}
|
|
return pLogEntry;
|
|
}
|
|
|
|
/**
|
|
* @param pbData - entry data.
|
|
* @param dwSize - data size.
|
|
* @param bAddCrLf - true if CR/LF must be added.
|
|
* @return true if entry was added.
|
|
*/
|
|
BOOL CTextLogFile::AddToHead(const BYTE* pbData, DWORD dwSize, BOOL bAddCrLf)
|
|
{
|
|
CTextLogEntry* pLogEntry = AllocLogEntry(pbData, dwSize, bAddCrLf);
|
|
if (pLogEntry)
|
|
{
|
|
CInMemLogFile::AddToHead(pLogEntry);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* @param pbData - entry data.
|
|
* @param dwSize - data size.
|
|
* @param bAddCrLf - true if CR/LF must be added.
|
|
* @return true if entry was added.
|
|
*/
|
|
BOOL CTextLogFile::AddToTail(const BYTE* pbData, DWORD dwSize, BOOL bAddCrLf)
|
|
{
|
|
CTextLogEntry* pLogEntry = AllocLogEntry(pbData, dwSize, bAddCrLf);
|
|
if (pLogEntry)
|
|
{
|
|
CInMemLogFile::AddToTail(pLogEntry);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* @param bAddCrLf - true if CR/LF must be added.
|
|
* @return true if entry was added.
|
|
*/
|
|
BOOL CTextLogFile::AddToHead(BOOL bAddCrLf)
|
|
{
|
|
const BYTE* pBuffer = m_MemStream.GetBuffer();
|
|
if (pBuffer == NULL)
|
|
return FALSE;
|
|
DWORD dwLength = (DWORD)m_MemStream.GetLength();
|
|
_ASSERTE(dwLength > 0);
|
|
return AddToHead(pBuffer, dwLength, bAddCrLf);
|
|
}
|
|
|
|
/**
|
|
* @param bAddCrLf - true if CR/LF must be added.
|
|
* @return true if entry was added.
|
|
*/
|
|
BOOL CTextLogFile::AddToTail(BOOL bAddCrLf)
|
|
{
|
|
const BYTE* pBuffer = m_MemStream.GetBuffer();
|
|
if (pBuffer == NULL)
|
|
return FALSE;
|
|
DWORD dwLength = (DWORD)m_MemStream.GetLength();
|
|
_ASSERTE(dwLength > 0);
|
|
return AddToTail(pBuffer, dwLength, bAddCrLf);
|
|
}
|
|
|
|
/**
|
|
* @param eLogLevel - log level number.
|
|
* @param eEntryMode - entry mode.
|
|
* @param rcsConsoleAccess - provides synchronous access to the console.
|
|
* @param pszEntry - log entry text.
|
|
* @return true if operation was completed successfully.
|
|
*/
|
|
BOOL CTextLogFile::WriteLogEntry(BUGTRAP_LOGLEVEL eLogLevel, ENTRY_MODE eEntryMode, CRITICAL_SECTION& rcsConsoleAccess, PCTSTR pszEntry)
|
|
{
|
|
BOOL bResult = TRUE;
|
|
BUGTRAP_LOGLEVEL eLogFileLevel = GetLogLevel();
|
|
if (eLogLevel <= eLogFileLevel)
|
|
{
|
|
SYSTEMTIME st;
|
|
GetLocalTime(&st);
|
|
if (! WriteLogEntryToConsole(eLogLevel, &st, rcsConsoleAccess, pszEntry))
|
|
FillEntryText(eLogLevel, &st, pszEntry);
|
|
EncodeEntryText();
|
|
switch (eEntryMode)
|
|
{
|
|
case EM_APPEND:
|
|
AddToTail(FALSE);
|
|
break;
|
|
case EM_INSERT:
|
|
AddToHead(FALSE);
|
|
break;
|
|
default:
|
|
_ASSERT(FALSE);
|
|
bResult = FALSE;
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|