// All the routines about MD5 is copied from // ..../coretech/libraries/gameos/nlog_mark.cpp & network.hpp // & touched by jcem struct CMD5Context { public: UINT4 state[4]; /* state (ABCD) */ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ unsigned char buffer[64]; /* input buffer */ public: void Init(); void Update(unsigned char *input, unsigned int inputLen); void Final(unsigned char [16]); static void MD5_Digest(unsigned char ba[16], unsigned char *input, unsigned int inputLen); static void MD5_Transform (UINT4 [4], unsigned char [64]); static void MD5_Encode(unsigned char *, UINT4 *, unsigned int); static void MD5_Decode(UINT4 *, unsigned char *, unsigned int); static void MD5_memcpy (POINTER, POINTER, unsigned int); static void MD5_memset (POINTER, int, unsigned int); }; // Constants for MD5Transform routine. #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // F, G, H and I are basic MD5 functions. #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | (~z))) // ROTATE_LEFT rotates x left n bits. #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. // Rotation is separate from addition to prevent recomputation. #define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } #define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } #define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } #define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } /* MD5 initialization. Begins an MD5 operation, writing a new context. */ void CMD5Context::Init() { count[0] = count[1] = 0; /* Load magic initialization constants. */ state[0] = 0x67452301; state[1] = 0xefcdab89; state[2] = 0x98badcfe; state[3] = 0x10325476; } /* MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context. */ void CMD5Context::Update(unsigned char *input, unsigned int inputLen) { unsigned int i, index, partLen; /* Compute number of bytes mod 64 */ index = (unsigned int)((count[0] >> 3) & 0x3F); /* Update number of bits */ if ((count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3)) count[1]++; count[1] += ((UINT4)inputLen >> 29); partLen = 64 - index; /* Transform as many times as possible. */ if (inputLen >= partLen) { MD5_memcpy((POINTER)&buffer[index], (POINTER)input, partLen); MD5_Transform (state, buffer); for(i = partLen; i + 63 < inputLen; i += 64) MD5_Transform (state, &input[i]); index = 0; } else i = 0; /* Buffer remaining input */ MD5_memcpy ((POINTER)&buffer[index], (POINTER)&input[i], inputLen-i); } /* MD5 finalization. Ends an MD5 message-digest operation, writing the the message digest and zeroizing the context. */ void CMD5Context::Final(unsigned char digest[16]) { unsigned char bits[8]; unsigned int index, padLen; // Save number of bits MD5_Encode (bits, count, 8); // Pad out to 56 mod 64. index = (unsigned int)((count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); Update (PADDING, padLen); // Append length (before padding) Update (bits, 8); // Store state in digest MD5_Encode (digest, state, 16); // Zeroize sensitive information. MD5_memset ((POINTER)this, 0, sizeof (*this)); } void CMD5Context::MD5_Digest(unsigned char ba[16], unsigned char *input, unsigned int inputLen) { CMD5Context ctx; ctx.Init(); ctx.Update(input, inputLen); ctx.Final(ba); } /* MD5 basic transformation. Transforms state based on block. */ void CMD5Context::MD5_Transform(UINT4 state[4], unsigned char block[64]) { UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; MD5_Decode (x, block, 64); /* Round 1 */ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; /* Zeroize sensitive information. */ MD5_memset ((POINTER)x, 0, sizeof (x)); } /* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */ void CMD5Context::MD5_Encode(unsigned char *output, UINT4 *input, unsigned int len) { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (unsigned char)(input[i] & 0xff); output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); } } /* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */ void CMD5Context::MD5_Decode(UINT4 *output, unsigned char *input, unsigned int len) { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); } /* Note: Replace "for loop" with standard memcpy if possible. */ void CMD5Context::MD5_memcpy(POINTER output, POINTER input, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) output[i] = input[i]; } /* Note: Replace "for loop" with standard memset if possible. */ void CMD5Context::MD5_memset(POINTER output, int value, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) ((char *)output)[i] = (char)value; } bool SLogReport::s_bCached = false; SYSTEMTIME SLogReport::s_Time; BYTE SLogReport::s_ba[16]; BOOL MyReplaceFile(const char* pcszDst, char* pcszSrc) { int nRet = 0; char* pcszSrc2 = &pcszSrc[strlen(pcszSrc)]; strcpy(pcszSrc2, ".tmp2"); DeleteFile(pcszSrc); SetFileAttributes(pcszDst, FILE_ATTRIBUTE_NORMAL); if (access(pcszDst, 0) == 0) { if (MoveFile(pcszDst, pcszSrc)) { strcpy(pcszSrc2, ""); if (MoveFile(pcszSrc, pcszDst)) { strcpy(pcszSrc2, ".tmp2"); DeleteFile(pcszSrc); //nRet = 0; } else { strcpy(pcszSrc2, ".tmp2"); if (MoveFile(pcszSrc, pcszDst)) { nRet = -2; } else { nRet = -3; } } } else { nRet = -1; } } else { strcpy(pcszSrc2, ""); if (MoveFile(pcszSrc, pcszDst)) { //nRet = 0; } else { nRet = -2; } } strcpy(pcszSrc2, ""); return !nRet; } static BOOL IsLeapYear(int nYear) { if ((nYear % 4) == 0) { if (((nYear % 100) != 0) || ((nYear % 400) == 0)) return TRUE; } return FALSE; } static int GetDayEnd(int nYear, int nMonth) { switch(nMonth) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31; case 2: return IsLeapYear(nYear) ? 29: 28; default: return 30; } } static void MkCacheDate(char szCache[], const SYSTEMTIME& st) { sprintf(szCache, "%02d%04d%02d", st.wDay, st.wYear, st.wMonth); } static BOOL Get2HEX(const char*& pcsz, BYTE& b) { struct SLocal { static BOOL Get1HEX(char c, int& n) { if (('0' <= c) && (c <= '9')) c -= '0'; else if (('a' <= c) && (c <= 'f')) { c -= 'a'; c += 10; } else if (('A' <= c) && (c <= 'F')) { c -= 'A'; c += 10; } else return FALSE; n *= 16; n += c; return TRUE; } }; int n = 0; if (SLocal::Get1HEX(*pcsz++, n)) { if (SLocal::Get1HEX(*pcsz++, n)) { b = (BYTE)n; return TRUE; } } return FALSE; } void AdjustSysTimeForLog(SYSTEMTIME& Time) { static BOOL s_bMinShiftChecked = FALSE; static int s_nMinShift = 0; if (!s_bMinShiftChecked) { s_bMinShiftChecked = TRUE; char szBuf[512]; sprintf(szBuf, "%s\\options.ini", AssetsDirectory1); s_nMinShift = GetPrivateProfileInt("battle tech misc", "MinShift", 0, szBuf); } int nMinute = Time.wMinute; int nHour = Time.wHour; int nDay = Time.wDay; int nMonth = Time.wMonth; int nYear = Time.wYear; nMinute += s_nMinShift; while(nMinute < 0) { nHour--; nMinute += 60; } while(60 <= nMinute) { nHour++; nMinute -= 60; } while(nHour < 0) { nDay--; nHour += 24; } while(24 <= nHour) { nDay++; nHour -= 24; } int nDayEnd; while(TRUE) { nDayEnd = GetDayEnd(nYear, nMonth); if (nDay < 1) { if (nMonth == 1) { nYear--; nMonth = 12; } else { nMonth--; } nDay += nDayEnd; } else if (nDayEnd < nDay) { if (nMonth == 12) { nYear++; nMonth = 1; } else { nMonth++; } nDay -= nDayEnd; } else { break; } } Time.wMinute = (WORD)nMinute; Time.wHour = (WORD)nHour; Time.wDay = (WORD)nDay; Time.wMonth = (WORD)nMonth; Time.wYear = (WORD)nYear; } SLogItem* SLogItem::GetNext() const { return (SLogItem*)&((unsigned char*)&this[1])[m_uSize]; } BOOL SLogItem::CheckItem() const { if (m_szPlayers[m_uSize] == '\0') { if ((0 <= m_nPlayers) && (m_nPlayers <= 16)) { if ((0 <= m_nBOTs) && (m_nBOTs <= 16)) { if ((1 <= (m_nPlayers+m_nBOTs)) && ((m_nPlayers + m_nBOTs) <= 16)) { return TRUE; } } } } return FALSE; } // from here :: SLogReport* SLogReport::OpenLogReport(const char* pcszFile, SYSTEMTIME& st, BOOL bNewIfNotExist/* = TRUE*/) { HANDLE hFile; DWORD dwSize; SLogReport* pRet = NULL; CheckCached(st); int nRet; hFile = ::CreateFile(pcszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { dwSize = GetFileSize(hFile, NULL); if ((sizeof(SLogReport)/* + sizeof(SLogItem)*/) <= dwSize) { pRet = (SLogReport*)malloc(dwSize); DWORD dwRet; if (ReadFile(hFile, pRet, dwSize, &dwRet, NULL)) { switch(pRet->Check(st)) { default: // case -1: // invalid file nRet = -1; // invalid break; case 0: // cracked file nRet = 0; // invalid break; case +1: // valid file... ::CloseHandle(hFile); return pRet; } } else { nRet = -1; // invalid } SLogReport::FreeLogReport(pRet); pRet = NULL; } else { nRet = -1; // invalid... } ::CloseHandle(hFile); } else { if (SLogReport::s_bCached) { nRet = -2; // missing file } else { nRet = +1; // no file... } } if (bNewIfNotExist && !pRet) { pRet = (SLogReport*)malloc(sizeof(SLogReport)); pRet->Initialize(); if (nRet == (-1)) pRet->MarkErr(true); else if (nRet == 0) pRet->MarkErr(true); else if (nRet == -2) pRet->MarkErr(); } return pRet; } void SLogReport::FreeLogReport(SLogReport* pLogReport) { if (pLogReport) { free(pLogReport); } } void SLogReport::CheckCached(SYSTEMTIME& st) { if (SLogReport::s_bCached || !&st) return; char szPath[MAX_PATH]; sprintf(szPath, "%s\\options.ini", AssetsDirectory1); char szCacheOld[256]; MkCacheDate(szCacheOld, st); char szCache[256]; GetPrivateProfileString("battle tech misc", "lrpt", "", szCache, sizeof(szCache) - 1, szPath); int nLen = strlen(szCacheOld); if (memcmp(szCache, szCacheOld, nLen) == 0) { SLogReport::s_bCached = TRUE; SLogReport::s_Time = st; const char* pcsz = &szCache[nLen]; BOOL bOK; if (strlen(pcsz) == 16 * 2) { bOK = TRUE; for(nLen = 0; nLen < 16; nLen++) { if (!Get2HEX(pcsz, s_ba[nLen])) { bOK = FALSE; break; } } } else { bOK = FALSE; } if (!bOK) { memset(s_ba, 0xff, sizeof(s_ba)); } } } // from here SLogReport:: SLogItem* SLogReport::GetFirst() const { return (SLogItem*)&this[1]; } SLogItem* SLogReport::GetLast() const { return (SLogItem*)&((unsigned char*)&this[1])[m_uSize]; } void SLogReport::Initialize() { m_dwSigns = LRPT_FILE_SIGN; m_dwVersion = LRPT_FILE_VER; memset(&m_ba[0], 0, sizeof(m_ba)); // not yet check because m_uSize is not valid... // from here MD5.... memset(&m_baReserved[0], 0, sizeof(m_baReserved)); m_nLogItems = 0; m_uSize = 0; //SLogItem m_aLogItems[]; CMD5Context::MD5_Digest(m_ba, &m_baReserved[0], (unsigned char*)&this[1] - &m_baReserved[0]); // MD5 signature... } int SLogReport::Check(SYSTEMTIME& st) { if (((m_dwSigns == LRPT_FILE_SIGN) || (m_dwSigns == LRPT_FILE_ERR) || (m_dwSigns == LRPT_FILE_ERR2)) && (m_dwVersion <= LRPT_FILE_VER)) { if ((m_dwSigns != LRPT_FILE_ERR) && (m_dwSigns != LRPT_FILE_ERR2)) { BYTE ba[16]; Fix(&ba[0]); if (memcmp(&ba[0], &m_ba[0], sizeof(ba)) != 0) { MarkErr(true); // STOP Application? } else { if (s_bCached && &st) { if ((st.wYear == s_Time.wYear) && (st.wMonth == s_Time.wMonth) && (st.wDay == s_Time.wDay)) { if (memcmp(&s_ba[0], &m_ba[0], 16) != 0) { MarkErr(); } } } } } if ((0 <= m_nLogItems) && (0 <= m_uSize)) { SLogItem* pStart = GetFirst(); SLogItem* pEnd = GetLast(); while(pStart < pEnd) { if (!pStart->CheckItem()) break; pStart = pStart->GetNext(); } if (pStart == pEnd) return +1; MarkErr(true); // STOP Application? } return 0; } return -1; } void SLogReport::Fix(BYTE* pBDigest/* = NULL*/) { if (!pBDigest) pBDigest = &m_ba[0]; CMD5Context::MD5_Digest(pBDigest, &m_baReserved[0], (unsigned char*)&this[1] - &m_baReserved[0] + m_uSize); // MD5 signature... CMD5Context::MD5_Digest(pBDigest, (unsigned char*)&m_dwSigns, sizeof(m_dwSigns)); // MD5 signature... CMD5Context::MD5_Digest(pBDigest, (unsigned char*)&m_dwVersion, sizeof(m_dwVersion)); // MD5 signature... } void SLogReport::MarkErr(bool bAs2/* = false*/) { if (bAs2) m_dwSigns = LRPT_FILE_ERR2; else m_dwSigns = LRPT_FILE_ERR; } int SLogReport::WriteFile(const char* pcszFile, SYSTEMTIME& st) { int nErr; char szPath[MAX_PATH]; do { nErr = 0; // remove temporary file SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL); strcpy(szPath, pcszFile); strcat(szPath, ".tmp"); DeleteFile(szPath); HANDLE hFile = ::CreateFile(szPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { DWORD dwRet; ::WriteFile(hFile, this, sizeof(SLogReport) + m_uSize, &dwRet, NULL); ::CloseHandle(hFile); hFile = NULL; if (m_nLogItems > 0) { s_bCached = true; s_Time = st; memcpy(&s_ba[0], &m_ba[0], 16); } SLogReport* pCheck = OpenLogReport(szPath, *(SYSTEMTIME*)NULL); if (pCheck && (pCheck->m_uSize == m_uSize) && (memcmp(pCheck, this, sizeof(SLogReport) + m_uSize) == 0)) { FreeLogReport(pCheck); if (MyReplaceFile(pcszFile, szPath)) { // save date/time/MD5... } else { // error in saving... remove(szPath); nErr = -4; // error in replace } } else { FreeLogReport(pCheck); // error in saving... remove(szPath); nErr = -3; // error in closing } } else { nErr = -2; // file creation error } } while(nErr != 0); // CheckCached() for.... sprintf(szPath, "%s\\options.ini", AssetsDirectory1); char szCache[256]; MkCacheDate(szCache, st); int nEnd = strlen(szCache); char* pszEnd = &szCache[nEnd]; for(int nn = 0; nn < 16; nn++) { BYTE bb = m_ba[nn]; sprintf(pszEnd, "%02x", bb); pszEnd += 2; } *pszEnd = '\0'; do { nErr = 0; // remove temporary file SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL); } while(!WritePrivateProfileString("battle tech misc", "lrpt", &szCache[0], szPath)); return nErr; } SLogReport* SLogReport::AddLogItem(const GUID& guid, UINT uBufNames, SLogItem*& pLogItem) { if (GetLogItem(guid)) { MarkErr(); return NULL; } else { UINT uSizeNew = sizeof(SLogReport) + m_uSize + sizeof(SLogItem) + uBufNames; SLogReport* pNew = (SLogReport*)realloc(this, uSizeNew); if (pNew) { pLogItem = (SLogItem*)&((unsigned char*)&pNew[1])[pNew->m_uSize]; pLogItem->m_uSize = uBufNames; pLogItem->m_GUID = guid; memset(&pLogItem->m_szHost[0], 0, sizeof(pLogItem->m_szHost)); pLogItem->m_nLaunched = -1; pLogItem->m_nErr = 0; pNew->m_nLogItems++; pNew->m_uSize += sizeof(SLogItem) + uBufNames; } return pNew; } } SLogItem* SLogReport::GetLogItem(const GUID& guid) const { SLogItem* pStart = GetFirst(); SLogItem* pEnd = GetLast(); while(pStart < pEnd) { if (memcmp(&pStart->m_GUID, &guid, sizeof(guid)) == 0) return pStart; pStart = pStart->GetNext(); } return NULL; }