// HighScores.h: interface for the CHighScores class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_HIGHSCORES_H__120B156E_B4C0_436B_9265_FC1B8F1187DB__INCLUDED_) #define AFX_HIGHSCORES_H__120B156E_B4C0_436B_9265_FC1B8F1187DB__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include #include // high scores results const int HS_OK = 0; const int HS_INVALID_PATH = 1; // high scores load results const int HSL_ERROR_OPENING_FILE = 2; const int HSL_ERROR_READING_FILE = 3; // high scores save results const int HSS_ERROR_CREATING_FILE = 4; const int HSS_ERROR_WRITING_TO_FILE = 5; #define HIGH_SCORES_FILE_NAME _T("HighScores.sco") #define HIGH_SCORES_DELIMITER ('|') #define HIGH_SCORES_EOL ('\n') #define HIGH_SCORES_MAX_BUFFER_SIZE 1024 inline LPWSTR ConvertToUnicode(LPCSTR pszStr); inline LPSTR ConvertToMB(LPCWSTR pszStr); inline LPSTR CreateStringCopy(LPCSTR pszStr); inline LPWSTR CreateStringCopy(LPCWSTR pszStr); inline LPSTR CreateConcatString(LPCSTR pszStr1, LPCSTR pszStr2); inline LPTSTR CreateConcatString(LPCTSTR pszStr1, LPCTSTR pszStr2); /* BEGINNING OF MATERIAL FROM md5.h */ #if !defined(AFX_MD5_H__7EF55D65_4E4E_4CB5_923C_3F1E3C1FD57B__INCLUDED_) #define AFX_MD5_H__7EF55D65_4E4E_4CB5_923C_3F1E3C1FD57B__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 // MainStorePage.h : header file // /* Copyright (C) 1999 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /*$Id: md5.h $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321. It is derived directly from the text of the RFC and not from the reference implementation. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef md5_INCLUDED # define md5_INCLUDED /* * This code has some adaptations for the Ghostscript environment, but it * will compile and run correctly in any environment with 8-bit chars and * 32-bit ints. Specifically, it assumes that if the following are * defined, they have the same meaning as in Ghostscript: P1, P2, P3, * ARCH_IS_BIG_ENDIAN. */ typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #ifdef __cplusplus extern "C" { #endif /* Initialize the algorithm. */ #ifdef P1 static void md5_init(P1(md5_state_t *pms)); #else static void md5_init(md5_state_t *pms); #endif /* Append a string to the message. */ #ifdef P3 static void md5_append(P3(md5_state_t *pms, const md5_byte_t *data, int nbytes)); #else static void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); #endif /* Finish the message and return the digest. */ #ifdef P2 static void md5_finish(P2(md5_state_t *pms, md5_byte_t digest[16])); #else static void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #endif #ifdef __cplusplus } /* end extern "C" */ /* * For reference, here is the program that computed the T values. */ #if 0 #include main() { int i; for (i = 1; i <= 64; ++i) { unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); printf("#define T%d 0x%08lx\n", i, v); } return 0; } #endif /* * End of T computation program. */ #define T1 0xd76aa478 #define T2 0xe8c7b756 #define T3 0x242070db #define T4 0xc1bdceee #define T5 0xf57c0faf #define T6 0x4787c62a #define T7 0xa8304613 #define T8 0xfd469501 #define T9 0x698098d8 #define T10 0x8b44f7af #define T11 0xffff5bb1 #define T12 0x895cd7be #define T13 0x6b901122 #define T14 0xfd987193 #define T15 0xa679438e #define T16 0x49b40821 #define T17 0xf61e2562 #define T18 0xc040b340 #define T19 0x265e5a51 #define T20 0xe9b6c7aa #define T21 0xd62f105d #define T22 0x02441453 #define T23 0xd8a1e681 #define T24 0xe7d3fbc8 #define T25 0x21e1cde6 #define T26 0xc33707d6 #define T27 0xf4d50d87 #define T28 0x455a14ed #define T29 0xa9e3e905 #define T30 0xfcefa3f8 #define T31 0x676f02d9 #define T32 0x8d2a4c8a #define T33 0xfffa3942 #define T34 0x8771f681 #define T35 0x6d9d6122 #define T36 0xfde5380c #define T37 0xa4beea44 #define T38 0x4bdecfa9 #define T39 0xf6bb4b60 #define T40 0xbebfbc70 #define T41 0x289b7ec6 #define T42 0xeaa127fa #define T43 0xd4ef3085 #define T44 0x04881d05 #define T45 0xd9d4d039 #define T46 0xe6db99e5 #define T47 0x1fa27cf8 #define T48 0xc4ac5665 #define T49 0xf4292244 #define T50 0x432aff97 #define T51 0xab9423a7 #define T52 0xfc93a039 #define T53 0x655b59c3 #define T54 0x8f0ccc92 #define T55 0xffeff47d #define T56 0x85845dd1 #define T57 0x6fa87e4f #define T58 0xfe2ce6e0 #define T59 0xa3014314 #define T60 0x4e0811a1 #define T61 0xf7537e82 #define T62 0xbd3af235 #define T63 0x2ad7d2bb #define T64 0xeb86d391 static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #ifndef ARCH_IS_BIG_ENDIAN # define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */ #endif #if ARCH_IS_BIG_ENDIAN /* * On big-endian machines, we must arrange the bytes in the right * order. (This also works on machines of unknown byte order.) */ md5_word_t X[16]; const md5_byte_t *xp = data; int i; for (i = 0; i < 16; ++i, xp += 4) X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); #else /* !ARCH_IS_BIG_ENDIAN */ /* * On little-endian machines, we can process properly aligned data * without copying it. */ md5_word_t xbuf[16]; const md5_word_t *X; if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } #endif #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = 0xefcdab89; pms->abcd[2] = 0x98badcfe; pms->abcd[3] = 0x10325476; } void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { const md5_byte_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[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 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } #endif #endif /* md5_INCLUDED */ #endif // !defined(AFX_MD5_H__7EF55D65_4E4E_4CB5_923C_3F1E3C1FD57B__INCLUDED_) /* END OF MATERIAL FROM md5.h */ class CByteStorage { public: CByteStorage() : m_nSize(0), m_nPos(0), m_pBuf(NULL), m_nBufSize(0) { } CByteStorage(const CByteStorage& byteStorage) : m_nSize(0), m_nPos(0), m_pBuf(NULL), m_nBufSize(0) { *this = byteStorage; } ~CByteStorage() { Clear(); } void Clear() { if (m_pBuf) free(m_pBuf); m_pBuf = NULL; m_nBufSize = 0; m_nSize = 0; m_nPos = 0; } DWORD GetSize() const { return m_nSize; } CByteStorage& operator=(const CByteStorage& byteStorage) { Clear(); Write(byteStorage.GetBuf(), byteStorage.GetSize()); return *this; } BOOL SetPos(DWORD nPos) { m_nPos = max(0, min(nPos, m_nSize)); return TRUE; } DWORD GetPos() const { return m_nPos; } BOOL Read(void* pData, DWORD nSize) { if (!nSize) return TRUE; if (!m_pBuf || m_nPos + nSize > m_nSize) return FALSE; if (pData) memcpy(pData, (char*)m_pBuf + m_nPos, nSize); m_nPos += nSize; return TRUE; } BOOL Write(void* pData, DWORD nSize) { if (!pData) return FALSE; if (!nSize) return TRUE; if (!SetSize(m_nPos + nSize)) return FALSE; if (!m_pBuf) return FALSE; memcpy((char*)m_pBuf + m_nPos, pData, nSize); m_nPos += nSize; return TRUE; } BOOL WriteZero(DWORD nSize) { if (!nSize) return TRUE; char szBuf[1024]; memset(szBuf, 0, sizeof(szBuf)); while (nSize) { DWORD nPiece = min(nSize, sizeof(szBuf)); if (nPiece && !Write(szBuf, nPiece)) return FALSE; nSize -= nPiece; } return TRUE; } BOOL WriteNumberAsText(int nValue) { char szNumber[30]; sprintf(szNumber, "%d", nValue); return Write(szNumber, strlen(szNumber)); } BOOL WriteChar(WCHAR ch) { char c; WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, &ch, 1, &c, 1, NULL, NULL); return Write(&c, sizeof(char)); } BOOL WriteStr(LPCWSTR pszStr) { if (!pszStr) return TRUE; LPSTR pszStrMB = ConvertToMB(pszStr); BOOL bOk = TRUE; if (!Write(pszStrMB, strlen(pszStrMB))) bOk = FALSE; free(pszStrMB); return bOk; } BOOL WriteStr(LPCSTR pszStr) { if (!pszStr) return TRUE; BOOL bOk = TRUE; if (!Write((void*)pszStr, strlen(pszStr))) bOk = FALSE; return bOk; } void* GetBuf() const { return m_pBuf; } protected: DWORD m_nSize; DWORD m_nPos; void* m_pBuf; DWORD m_nBufSize; BOOL SetSize(DWORD nNewSize) { if (nNewSize <= m_nSize) return TRUE; DWORD nNewBufSize = max(m_nBufSize, 1); while (nNewBufSize < nNewSize) nNewBufSize <<= 1; if (nNewBufSize > m_nBufSize && !SetBufSize(nNewBufSize)) return FALSE; m_nSize = nNewSize; return TRUE; } BOOL SetBufSize(DWORD nNewBufSize) { if (nNewBufSize <= m_nBufSize) return TRUE; if (!m_pBuf) m_pBuf = malloc(nNewBufSize); else { void* pNewBuf = malloc(nNewBufSize); memcpy(pNewBuf, m_pBuf, m_nSize); free(m_pBuf); m_pBuf = pNewBuf; } m_nBufSize = nNewBufSize; return (m_pBuf != NULL); } }; class CCryptoHashMD5 { public: CCryptoHashMD5() { m_pState = new md5_state_s(); md5_init(m_pState); } ~CCryptoHashMD5() { delete m_pState; } void GetHash(BYTE *pOutput) { md5_state_t tmpState = *m_pState; md5_byte_t digest[16]; md5_finish(m_pState, digest); memcpy(pOutput, digest, 16); *m_pState = tmpState; } int GetHashString(LPTSTR szStringOut) { md5_byte_t digest[16]; GetHash(digest); szStringOut[0] = 0; TCHAR szTmp[20]; int nLength = 0; for (int di = 0; di < 16; ++di) { _stprintf(szTmp, TEXT("%02x"), digest[di]); _tcscat(szStringOut, szTmp); nLength += _tcslen(szTmp); } return nLength; } static void GetHashString(const BYTE* pData, const DWORD dwDataSize, LPTSTR szStringOut) { CCryptoHashMD5 md5; md5_append(md5.m_pState, pData, dwDataSize); md5.GetHashString(szStringOut); } private: md5_state_s* m_pState; }; class CHighScores { private: class CScore { public: CScore(LPCTSTR pszName, int nScore, LPCTSTR pszInfo) : m_pszName(NULL), m_nScore(0), m_pszInfo(NULL) { SetName(pszName); SetScore(nScore); SetInfo(pszInfo); } ~CScore() { if (m_pszName) free(m_pszName); if (m_pszInfo) free(m_pszInfo); } void SetName(LPCTSTR pszName) { if (m_pszName) free(m_pszName); m_pszName = CreateStringCopy(pszName); } void SetScore(int nScore) { m_nScore = nScore; } void SetInfo(LPCTSTR pszInfo) { if (m_pszInfo) free(m_pszInfo); m_pszInfo = CreateStringCopy(pszInfo); } private: LPTSTR m_pszName; int m_nScore; LPTSTR m_pszInfo; friend CHighScores; }; typedef CSimpleValArray CScoresList; public: CHighScores(int nMaxScores, LPCTSTR pszMagic) { m_nMaxScores = nMaxScores; m_pszMagic = CreateStringCopy(pszMagic); m_pszAppName = CreateStringCopy(_T("")); m_nAppID = 0; m_nAppVersion = 0; m_bIsSignatureOk = TRUE; m_nCurScoreIndex = -1; } ~CHighScores() { Clear(); if (m_pszMagic) free(m_pszMagic); } void Sort() { qsort(m_list.GetData(), m_list.GetSize(), sizeof(void*), CompareScoresFunc); for (int i = m_nMaxScores; i < m_list.GetSize(); i++) delete m_list[i]; while (m_list.GetSize() > m_nMaxScores) m_list.RemoveAt(m_list.GetSize() - 1); } BOOL LoadFromBS(CByteStorage& src) { Clear(); src.SetPos(0); LPSTR pszSource = (LPSTR)src.GetBuf(); LPSTR pLastEol = strrchr(pszSource, HIGH_SCORES_EOL); m_bIsSignatureOk = FALSE; if (pLastEol) { if (!strchr(pLastEol + 1, HIGH_SCORES_DELIMITER)) { char szReadHash[50]; char szHash[50]; strcpy(szReadHash, pLastEol + 1); char cSave = pLastEol[1]; pLastEol[1] = 0; MD5(pszSource, szHash); pLastEol[1] = cSave; if (strcmp(szHash, szReadHash) == 0) m_bIsSignatureOk = TRUE; } } BOOL bHeader = FALSE; BOOL bOk = TRUE; char szBuf[HIGH_SCORES_MAX_BUFFER_SIZE]; while (*pszSource && bOk) { // find eol LPSTR pEol = strchr(pszSource, HIGH_SCORES_EOL); if (!pEol) break; if (!bHeader) { if (bOk) { GetNextWord(pszSource, pEol, szBuf); if (sscanf(szBuf, "%u", &m_nAppID) != 1 || m_nAppID == 0) bOk = FALSE; } if (bOk) { GetNextWord(pszSource, pEol, szBuf); if (sscanf(szBuf, "%u", &m_nAppVersion) != 1 || m_nAppVersion == 0) bOk = FALSE; } if (bOk) { GetNextWord(pszSource, pEol, szBuf); if (m_pszAppName) free(m_pszAppName); m_pszAppName = ConvertToUnicode(szBuf); if (!m_pszAppName || !*m_pszAppName) bOk = FALSE; } bHeader = TRUE; } else { CScore* pScore = new CScore(NULL, 0, NULL); if (!pScore) bOk = FALSE; if (bOk) { GetNextWord(pszSource, pEol, szBuf); LPTSTR pszBuf = ConvertToUnicode(szBuf); pScore->SetName(pszBuf); free(pszBuf); if (!pScore->m_pszName || !*pScore->m_pszName) bOk = FALSE; } if (bOk) { GetNextWord(pszSource, pEol, szBuf); int nScore; if (sscanf(szBuf, "%d", &nScore) != 1 || nScore < 0) bOk = FALSE; if (bOk) pScore->SetScore(nScore); } if (bOk) { GetNextWord(pszSource, pEol, szBuf); LPTSTR pszBuf = ConvertToUnicode(szBuf); pScore->SetInfo(pszBuf); free(pszBuf); if (!pScore->m_pszInfo) bOk = FALSE; } if (bOk) m_list.Add(pScore); else delete pScore; } if (bOk) pszSource = pEol + 1; } if (bOk) Sort(); return bOk; } int Load(LPCTSTR pszFilePath) { Clear(); // create file TCHAR szFullFileName[MAX_PATH]; if (!GenerateFullFileName(pszFilePath, szFullFileName)) return HS_INVALID_PATH; HANDLE hFile = ::CreateFile(szFullFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return HSL_ERROR_OPENING_FILE; CByteStorage src; if (!src.WriteZero(::GetFileSize(hFile, NULL))) { ::CloseHandle(hFile); return HSL_ERROR_READING_FILE; } DWORD nNumberOfBytesRead; ::ReadFile(hFile, src.GetBuf(), src.GetSize(), &nNumberOfBytesRead, NULL); ::CloseHandle(hFile); if (nNumberOfBytesRead != src.GetSize()) return HSL_ERROR_READING_FILE; src.SetPos(src.GetSize()); src.WriteChar(0); src.SetPos(0); if (!LoadFromBS(src)) return HSL_ERROR_READING_FILE; return HS_OK; } void SaveToBS(CByteStorage& dest, BOOL bWriteSignatureAnyway = FALSE) const { dest.Clear(); // header dest.WriteNumberAsText(m_nAppID); dest.WriteChar(HIGH_SCORES_DELIMITER); dest.WriteNumberAsText(m_nAppVersion); dest.WriteChar(HIGH_SCORES_DELIMITER); dest.WriteStr(m_pszAppName); dest.WriteChar(HIGH_SCORES_EOL); // records for (int i = 0; i < m_list.GetSize(); i++) { CScore* pScore = m_list[i]; dest.WriteStr(pScore->m_pszName); dest.WriteChar(HIGH_SCORES_DELIMITER); dest.WriteNumberAsText(pScore->m_nScore); dest.WriteChar(HIGH_SCORES_DELIMITER); dest.WriteStr(pScore->m_pszInfo); dest.WriteChar(HIGH_SCORES_EOL); } // signature if (m_bIsSignatureOk || bWriteSignatureAnyway) { char szHash[50]; dest.WriteChar(0); MD5((LPCSTR)dest.GetBuf(), szHash); dest.SetPos(dest.GetPos() - sizeof(char)); dest.WriteStr(szHash); } } int Save(LPCTSTR pszFilePath, BOOL bWriteSignatureAnyway = FALSE) const { // create file TCHAR szFullFileName[MAX_PATH]; if (!GenerateFullFileName(pszFilePath, szFullFileName)) return HS_INVALID_PATH; HANDLE hDestFile = ::CreateFile(szFullFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hDestFile == INVALID_HANDLE_VALUE) return HSS_ERROR_CREATING_FILE; // write to storage CByteStorage dest; SaveToBS(dest, bWriteSignatureAnyway); // write to file DWORD nNumberOfBytesWritten; ::WriteFile(hDestFile, dest.GetBuf(), dest.GetSize(), &nNumberOfBytesWritten, NULL); ::CloseHandle(hDestFile); if (nNumberOfBytesWritten != dest.GetSize()) return HSS_ERROR_WRITING_TO_FILE; return HS_OK; } BOOL IsSignatureOk() const { return m_bIsSignatureOk; } void Clear() { for (int i = 0; i < m_list.GetSize(); i++) delete m_list[i]; m_list.RemoveAll(); if (m_pszAppName) free(m_pszAppName); m_pszAppName = NULL; m_nAppID = 0; m_nAppVersion = 0; m_bIsSignatureOk = TRUE; m_nCurScoreIndex = -1; } BOOL AddScore(LPCTSTR pszName, int nScore, LPCTSTR pszAdditionalInfo) { if (!pszName || !*pszName || nScore < 0) return FALSE; if (_tcschr(pszName, HIGH_SCORES_DELIMITER)) return FALSE; if (!IsHighScore(nScore)) return FALSE; CScore* pScore = new CScore(pszName, nScore, pszAdditionalInfo ? pszAdditionalInfo : _T("")); if (!pScore) return FALSE; m_list.Add(pScore); return TRUE; } int GetNumberOfRecords() const { return m_list.GetSize(); } BOOL OpenRecord(int nRecordIndex) { if (nRecordIndex >= 0 && nRecordIndex < m_list.GetSize()) { m_nCurScoreIndex = nRecordIndex; return TRUE; } m_nCurScoreIndex = -1; return FALSE; } BOOL FirstRecord() { if (m_list.GetSize() > 0) { m_nCurScoreIndex = 0; return TRUE; } m_nCurScoreIndex = -1; return FALSE; } BOOL GetNextRecord() { if (m_nCurScoreIndex >= 0 && m_nCurScoreIndex < m_list.GetSize()) m_nCurScoreIndex++; if (m_nCurScoreIndex >= 0 && m_nCurScoreIndex < m_list.GetSize()) return TRUE; m_nCurScoreIndex = -1; return FALSE; } BOOL GetName(LPTSTR lpString, int nMaxCount) const { if (!lpString || nMaxCount < 1) return FALSE; CScore* pScore = GetCurScore(); if (!pScore) return FALSE; _tcsncpy(lpString, pScore->m_pszName, nMaxCount); lpString[nMaxCount - 1] = 0; return TRUE; } int GetScore() const { CScore* pScore = GetCurScore(); if (!pScore) return -1; return pScore->m_nScore; } BOOL GetAdditionalInfo(LPTSTR lpString, int nMaxCount) const { if (!lpString || nMaxCount < 1) return FALSE; CScore* pScore = GetCurScore(); if (!pScore) return FALSE; _tcsncpy(lpString, pScore->m_pszInfo, nMaxCount); lpString[nMaxCount - 1] = 0; return TRUE; } LPTSTR GetAppName() { return m_pszAppName ? m_pszAppName : _T(""); } DWORD GetAppID() { return m_nAppID; } DWORD GetAppVersion() { return m_nAppVersion; } void SetAppName(LPCTSTR pszAppName) { if (m_pszAppName) free(m_pszAppName); m_pszAppName = CreateStringCopy(pszAppName); } void SetAppID(DWORD nAppID) { m_nAppID = nAppID; } void SetAppVersion(DWORD nAppVersion) { m_nAppVersion = nAppVersion; } private: CScoresList m_list; int m_nMaxScores; LPTSTR m_pszMagic; LPTSTR m_pszAppName; DWORD m_nAppID; DWORD m_nAppVersion; BOOL m_bIsSignatureOk; int m_nCurScoreIndex; static BOOL GenerateFullFileName(LPCTSTR pszFilePath, LPTSTR pszDest) { if (!pszFilePath || !pszDest) return FALSE; int nPathLen = _tcslen(pszFilePath); int nBackSlash = 0; if (nPathLen > 0 && pszFilePath[nPathLen - 1] != _T('\\') && pszFilePath[nPathLen - 1] != _T('/')) { nBackSlash = 1; } int nFileNameLen = _tcslen(HIGH_SCORES_FILE_NAME); if (nPathLen + nBackSlash + nFileNameLen + 1 >= MAX_PATH) return FALSE; _tcscpy(pszDest, pszFilePath); if (nBackSlash) pszDest[nPathLen] = _T('\\'); _tcscpy(pszDest + nPathLen + nBackSlash, HIGH_SCORES_FILE_NAME); pszDest[nPathLen + nBackSlash + nFileNameLen] = 0; return TRUE; } void MD5(LPCSTR pszStr, LPSTR pszDest) const { if (!pszStr || !pszDest) return; LPSTR pszMagicMB = ConvertToMB(m_pszMagic); LPSTR pszConcat = CreateConcatString(pszStr, pszMagicMB); free(pszMagicMB); if (!pszConcat) return; TCHAR szDest[50]; CCryptoHashMD5::GetHashString((const BYTE*)pszConcat, strlen(pszConcat), szDest); free(pszConcat); DWORD nLen = wcslen(szDest); WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, szDest, nLen, pszDest, nLen, NULL, NULL); pszDest[nLen] = 0; } CScore* GetCurScore() const { if (m_nCurScoreIndex >= 0 && m_nCurScoreIndex < m_list.GetSize()) return m_list[m_nCurScoreIndex]; return NULL; } static int CompareInts(int nA, int nB) { if (nA == nB) return 0; return (nA < nB) ? -1 : 1; } static int __cdecl CompareScoresFunc(const void* elem1, const void* elem2) { CScore* pScore1 = *(CScore**)elem1; CScore* pScore2 = *(CScore**)elem2; return CompareInts(pScore2->m_nScore, pScore1->m_nScore); } BOOL IsHighScore(int nScore) const { if (nScore < 0) return FALSE; if (m_list.GetSize() < m_nMaxScores) return TRUE; CScore score(NULL, nScore, NULL); CScore* pScore = &score; CScore* pLastScore = m_list[m_list.GetSize() - 1]; if (CompareScoresFunc(&pScore, &pLastScore) < 0) return TRUE; return FALSE; } void GetNextWord(LPSTR& pszStart, LPSTR pszEnd, LPSTR pszBuf) { if (!pszStart || !pszEnd) return; LPSTR pszCur = pszStart; while (*pszCur && pszCur != pszEnd && *pszCur != HIGH_SCORES_DELIMITER) pszCur++; DWORD nNumCopy = min(pszCur - pszStart, HIGH_SCORES_MAX_BUFFER_SIZE - 1); strncpy(pszBuf, pszStart, nNumCopy); pszBuf[nNumCopy] = 0; pszStart = (pszCur != pszEnd) ? (pszCur + 1) : pszCur; } friend CScore; }; inline LPWSTR ConvertToUnicode(LPCSTR pszStr) { DWORD nLen = strlen(pszStr); LPWSTR pszDest = (LPWSTR)malloc((1 + nLen) * sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, MB_COMPOSITE, pszStr, nLen, pszDest, nLen); pszDest[nLen] = 0; return pszDest; } inline LPSTR ConvertToMB(LPCWSTR pszStr) { DWORD nLen = wcslen(pszStr); LPSTR pszDest = (LPSTR)malloc(1 + nLen); WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, pszStr, nLen, pszDest, nLen, NULL, NULL); pszDest[nLen] = 0; return pszDest; } inline LPSTR CreateStringCopy(LPCSTR pszStr) { if (!pszStr) pszStr = ""; int nLen = strlen(pszStr); LPSTR pszCopy = (LPSTR)malloc(1 + nLen); if (!pszCopy) return NULL; strcpy(pszCopy, pszStr); pszCopy[nLen] = 0; return pszCopy; } inline LPWSTR CreateStringCopy(LPCWSTR pszStr) { if (!pszStr) pszStr = _T(""); int nLen = wcslen(pszStr); LPWSTR pszCopy = (LPWSTR)malloc((1 + nLen) * sizeof(WCHAR)); if (!pszCopy) return NULL; wcscpy(pszCopy, pszStr); pszCopy[nLen] = 0; return pszCopy; } inline LPSTR CreateConcatString(LPCSTR pszStr1, LPCSTR pszStr2) { LPSTR pszNStr1 = (LPSTR)(pszStr1 ? pszStr1 : ""); LPSTR pszNStr2 = (LPSTR)(pszStr2 ? pszStr2 : ""); int nLen1 = strlen(pszNStr1); int nLen2 = strlen(pszNStr2); LPSTR pszCopy = (LPSTR)malloc(1 + nLen1 + nLen2); if (!pszCopy) return NULL; strcpy(pszCopy, pszNStr1); strcpy(pszCopy + nLen1, pszNStr2); pszCopy[nLen1 + nLen2] = 0; return pszCopy; } inline LPTSTR CreateConcatString(LPCTSTR pszStr1, LPCTSTR pszStr2) { LPTSTR pszNStr1 = (LPTSTR)(pszStr1 ? pszStr1 : _T("")); LPTSTR pszNStr2 = (LPTSTR)(pszStr2 ? pszStr2 : _T("")); int nLen1 = _tcslen(pszNStr1); int nLen2 = _tcslen(pszNStr2); LPTSTR pszCopy = (LPTSTR)malloc((1 + nLen1 + nLen2) * sizeof(TCHAR)); if (!pszCopy) return NULL; _tcscpy(pszCopy, pszNStr1); _tcscpy(pszCopy + nLen1, pszNStr2); pszCopy[nLen1 + nLen2] = 0; return pszCopy; } #endif // !defined(AFX_HIGHSCORES_H__120B156E_B4C0_436B_9265_FC1B8F1187DB__INCLUDED_)