diff options
Diffstat (limited to 'dep/CascLib/src/common/Common.cpp')
-rw-r--r-- | dep/CascLib/src/common/Common.cpp | 709 |
1 files changed, 381 insertions, 328 deletions
diff --git a/dep/CascLib/src/common/Common.cpp b/dep/CascLib/src/common/Common.cpp index a0455b7c659..d545f52f84a 100644 --- a/dep/CascLib/src/common/Common.cpp +++ b/dep/CascLib/src/common/Common.cpp @@ -65,40 +65,230 @@ unsigned char IntToHexChar[] = "0123456789abcdef"; // GetLastError/SetLastError support for non-Windows platform #ifndef PLATFORM_WINDOWS -static int nLastError = ERROR_SUCCESS; +static DWORD dwLastError = ERROR_SUCCESS; -int GetLastError() +DWORD GetLastError() { - return nLastError; + return dwLastError; } -void SetLastError(int nError) +void SetLastError(DWORD dwErrCode) { - nLastError = nError; + dwLastError = dwErrCode; } #endif //----------------------------------------------------------------------------- -// String manipulation +// Overloaded "new" and "delete" operators -void CopyString(char * szTarget, const char * szSource, size_t cchLength) +void * operator new(size_t size) { - memcpy(szTarget, szSource, cchLength); - szTarget[cchLength] = 0; + return CASC_ALLOC(BYTE, size); } -void CopyString(wchar_t * szTarget, const char * szSource, size_t cchLength) +void * operator new[](size_t size) { - mbstowcs(szTarget, szSource, cchLength); - szTarget[cchLength] = 0; + return CASC_ALLOC(BYTE, size); } -void CopyString(char * szTarget, const wchar_t * szSource, size_t cchLength) +void operator delete(void * ptr) { - wcstombs(szTarget, szSource, cchLength); - szTarget[cchLength] = 0; + CASC_FREE(ptr); } +void operator delete[](void * ptr) +{ + CASC_FREE(ptr); +} + +// For some reason, VS2015 needs this +void operator delete(void * ptr, size_t) +{ + CASC_FREE(ptr); +} + +//----------------------------------------------------------------------------- +// Linear data stream manipulation + +LPBYTE CaptureInteger32(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PDWORD PtrValue) +{ + // Is there enough data? + if((pbDataPtr + sizeof(DWORD)) > pbDataEnd) + return NULL; + + // Give data + PtrValue[0] = *(PDWORD)pbDataPtr; + + // Return the pointer to data following after the integer + return pbDataPtr + sizeof(DWORD); +} + +LPBYTE CaptureInteger32_BE(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PDWORD PtrValue) +{ + // Is there enough data? + if((pbDataPtr + sizeof(DWORD)) > pbDataEnd) + return NULL; + + // Convert data from Little endian to + PtrValue[0] = ConvertBytesToInteger_4(pbDataPtr); + + // Return the pointer to data following after the integer + return pbDataPtr + sizeof(DWORD); +} + +LPBYTE CaptureByteArray(LPBYTE pbDataPtr, LPBYTE pbDataEnd, size_t nLength, LPBYTE pbOutput) +{ + // Is there enough data? + if((pbDataPtr + nLength) > pbDataEnd) + return NULL; + + // Give data + memcpy(pbOutput, pbDataPtr, nLength); + + // Return the pointer to data following after the integer + return pbDataPtr + nLength; +} + +LPBYTE CaptureContentKey(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PCONTENT_KEY * PtrCKey) +{ + // Is there enough data? + if((pbDataPtr + sizeof(CONTENT_KEY)) > pbDataEnd) + return NULL; + + // Give data + PtrCKey[0] = (PCONTENT_KEY)pbDataPtr; + + // Return the pointer to data following after the integer + return pbDataPtr + sizeof(CONTENT_KEY); +} + +LPBYTE CaptureArray_(LPBYTE pbDataPtr, LPBYTE pbDataEnd, LPBYTE * PtrArray, size_t ItemSize, size_t ItemCount) +{ + size_t ArraySize = ItemSize * ItemCount; + + // Is there enough data? + if((pbDataPtr + ArraySize) > pbDataEnd) + return NULL; + + // Give data + PtrArray[0] = pbDataPtr; + + // Return the pointer to data following after the array + return pbDataPtr + ArraySize; +} + +//----------------------------------------------------------------------------- +// String copying and conversion + +void CascStrCopy(char * szTarget, size_t cchTarget, const char * szSource, size_t cchSource) +{ + size_t cchToCopy; + + if (cchTarget > 0) + { + // Make sure we know the length + if (cchSource == -1) + cchSource = strlen(szSource); + cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource); + + // Copy the string + memcpy(szTarget, szSource, cchToCopy); + szTarget[cchToCopy] = 0; + } +} + +void CascStrCopy(char * szTarget, size_t cchTarget, const wchar_t * szSource, size_t cchSource) +{ + size_t cchToCopy; + + if (cchTarget > 0) + { + // Make sure we know the length + if (cchSource == -1) + cchSource = wcslen(szSource); + cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource); + + wcstombs(szTarget, szSource, cchToCopy); + szTarget[cchToCopy] = 0; + } +} + +void CascStrCopy(wchar_t * szTarget, size_t cchTarget, const char * szSource, size_t cchSource) +{ + size_t cchToCopy; + + if (cchTarget > 0) + { + // Make sure we know the length + if (cchSource == -1) + cchSource = strlen(szSource); + cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource); + + mbstowcs(szTarget, szSource, cchToCopy); + szTarget[cchToCopy] = 0; + } +} + +void CascStrCopy(wchar_t * szTarget, size_t cchTarget, const wchar_t * szSource, size_t cchSource) +{ + size_t cchToCopy; + + if (cchTarget > 0) + { + // Make sure we know the length + if (cchSource == -1) + cchSource = wcslen(szSource); + cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource); + + memcpy(szTarget, szSource, cchToCopy * sizeof(wchar_t)); + szTarget[cchToCopy] = 0; + } +} + +//----------------------------------------------------------------------------- +// Safe version of s(w)printf + +size_t CascStrPrintf(char * buffer, size_t nCount, const char * format, ...) +{ + char * buffend; + va_list argList; + + // Start the argument list + va_start(argList, format); + +#ifdef PLATFORM_WINDOWS + StringCchVPrintfExA(buffer, nCount, &buffend, NULL, 0, format, argList); +#else + buffend = buffer + vsnprintf(buffer, nCount, format, argList); +#endif + + // End the argument list + va_end(argList); + return (buffend - buffer); +} + +size_t CascStrPrintf(wchar_t * buffer, size_t nCount, const wchar_t * format, ...) +{ + wchar_t * buffend; + va_list argList; + + // Start the argument list + va_start(argList, format); + +#ifdef PLATFORM_WINDOWS + StringCchVPrintfExW(buffer, nCount, &buffend, NULL, 0, format, argList); +#else + buffend = buffer + vswprintf(buffer, nCount, format, argList); +#endif + + // End the argument list + va_end(argList); + return (buffend - buffer); +} + +//----------------------------------------------------------------------------- +// String allocation + char * CascNewStr(const char * szString, size_t nCharsToReserve) { char * szNewString = NULL; @@ -137,102 +327,144 @@ wchar_t * CascNewStr(const wchar_t * szString, size_t nCharsToReserve) return szNewString; } -TCHAR * CascNewStrFromAnsi(const char * szBegin, const char * szEnd) +template <typename XCHAR> +TCHAR * AppendPathFragment(TCHAR * szBuffer, TCHAR * szBufferEnd, const XCHAR * szPath, char chSeparator, bool bFirstFragment = false) { - TCHAR * szNewString = NULL; - - // Only if the entry is valid - if(szBegin != NULL && szEnd > szBegin) + // The "Path" must not be empty + if(szPath && szPath[0]) { - // Allocate and copy the string - szNewString = CASC_ALLOC(TCHAR, (szEnd - szBegin + 1)); - if(szNewString != NULL) - CopyString(szNewString, szBegin, (szEnd - szBegin)); + // Append the path separator after the first fragment + if(szBuffer < szBufferEnd && bFirstFragment == false) + { + if(szBuffer[-1] != chSeparator) + { + *szBuffer++ = chSeparator; + } + } + + // Copy the sub path + while(szBuffer < szBufferEnd && szPath[0] != 0) + { + // If there is a path separator, we skip it (all of them) and put single separator there + if(szPath[0] == '\\' || szPath[0] == '/') + { + while(szPath[0] == '\\' || szPath[0] == '/') + szPath++; + *szBuffer++ = chSeparator; + } + else + { + *szBuffer++ = *szPath++; + } + } + + // Append end of string + szBuffer[0] = 0; } - // Return the string - return szNewString; + return szBuffer; } -TCHAR * CombinePath(const TCHAR * szDirectory, const TCHAR * szSubDir) +TCHAR * GetLastPathPart(TCHAR * szWorkPath) { - TCHAR * szFullPath = NULL; - TCHAR * szPathPtr; - size_t nLength1 = 0; - size_t nLength2 = 0; + size_t nLength = _tcslen(szWorkPath); - // Calculate lengths of each part - if(szDirectory != NULL) - { - // Get the length of the directory - nLength1 = _tcslen(szDirectory); + // Go one character back + if(nLength > 0) + nLength--; - // Cut all ending backslashes - while(nLength1 > 0 && (szDirectory[nLength1 - 1] == _T('\\') || szDirectory[nLength1 - 1] == _T('/'))) - nLength1--; - } + // Cut ending (back)slashes, if any + while(nLength > 0 && (szWorkPath[nLength] == _T('\\') || szWorkPath[nLength] == _T('/'))) + nLength--; - if(szSubDir != NULL) + // Cut the last path part + while(nLength > 0) { - // Cut all leading backslashes - while(szSubDir[0] == _T(PATH_SEPARATOR)) - szSubDir++; - - // Get the length of the subdir - nLength2 = _tcslen(szSubDir); - - // Cut all ending backslashes - while(nLength2 > 0 && szSubDir[nLength2 - 1] == _T(PATH_SEPARATOR)) - nLength2--; - } - - // Allocate space for the full path - szFullPath = szPathPtr = CASC_ALLOC(TCHAR, nLength1 + nLength2 + 2); - if(szFullPath != NULL) - { - // Copy the directory - if(szDirectory != NULL && nLength1 != 0) + // End of path? + if(szWorkPath[nLength] == _T('\\') || szWorkPath[nLength] == _T('/')) { - memcpy(szPathPtr, szDirectory, (nLength1 * sizeof(TCHAR))); - szPathPtr += nLength1; + return szWorkPath + nLength; } - // Copy the sub-directory - if(szSubDir != NULL && nLength2 != 0) - { - // Append backslash to the previous one - if(szPathPtr > szFullPath) - *szPathPtr++ = _T(PATH_SEPARATOR); + // Go one character back + nLength--; + } - // Copy the string - memcpy(szPathPtr, szSubDir, (nLength2 * sizeof(TCHAR))); - szPathPtr += nLength2; - } + return NULL; +} - // Terminate the string - szPathPtr[0] = 0; - } +bool CutLastPathPart(TCHAR * szWorkPath) +{ + // Get the last part of the path + szWorkPath = GetLastPathPart(szWorkPath); + if(szWorkPath == NULL) + return false; - return szFullPath; + szWorkPath[0] = 0; + return true; } -TCHAR * CombinePathAndString(const TCHAR * szPath, const char * szString, size_t nLength) +TCHAR * CombinePath(const TCHAR * szDirectory, const TCHAR * szSubDir) { + TCHAR * szFullPathEnd; TCHAR * szFullPath = NULL; - TCHAR * szSubDir; + TCHAR * szPathPtr; + size_t nLength1 = (szDirectory != NULL) ? _tcslen(szDirectory) : 0; + size_t nLength2 = (szSubDir != NULL) ? _tcslen(szSubDir) : 0; - // Create the subdir string - szSubDir = CASC_ALLOC(TCHAR, nLength + 1); - if(szSubDir != NULL) + // Allocate the entire buffer + szFullPath = szPathPtr = CASC_ALLOC(TCHAR, nLength1 + nLength2 + 2); + szFullPathEnd = szFullPath + nLength1 + nLength2 + 1; + if(szFullPath != NULL) { - CopyString(szSubDir, szString, nLength); - szFullPath = CombinePath(szPath, szSubDir); - CASC_FREE(szSubDir); + szPathPtr = AppendPathFragment(szPathPtr, szFullPathEnd, szDirectory, PATH_SEP_CHAR, true); + szPathPtr = AppendPathFragment(szPathPtr, szFullPathEnd, szSubDir, PATH_SEP_CHAR); } return szFullPath; } +size_t CombineFilePath(TCHAR * szBuffer, size_t nMaxChars, const TCHAR * szPath, const TCHAR * szSubPath1, const TCHAR * szSubPath2) +{ + TCHAR * szSaveBuffer = szBuffer; + TCHAR * szBufferEnd = szBuffer + nMaxChars - 1; + + // Append all three parts and return length + szBuffer = AppendPathFragment(szBuffer, szBufferEnd, szPath, PATH_SEP_CHAR, true); + szBuffer = AppendPathFragment(szBuffer, szBufferEnd, szSubPath1, PATH_SEP_CHAR); + szBuffer = AppendPathFragment(szBuffer, szBufferEnd, szSubPath2, PATH_SEP_CHAR); + return (szBuffer - szSaveBuffer); +} + +size_t CombineUrlPath(TCHAR * szBuffer, size_t nMaxChars, const TCHAR * szHost, const TCHAR * szSubPath1, const TCHAR * szSubPath2) +{ + TCHAR * szSaveBuffer = szBuffer; + TCHAR * szBufferEnd = szBuffer + nMaxChars - 1; + + // Append all three parts and return length + szBuffer = AppendPathFragment(szBuffer, szBufferEnd, szHost, '/', true); + szBuffer = AppendPathFragment(szBuffer, szBufferEnd, szSubPath1, '/'); + szBuffer = AppendPathFragment(szBuffer, szBufferEnd, szSubPath2, '/'); + return (szBuffer - szSaveBuffer); +} + +size_t CreateCascSubdirectoryName(TCHAR * szBuffer, size_t nMaxChars, const TCHAR * szSubDir, const TCHAR * szExtension, LPBYTE pbEKey) +{ + TCHAR * szSaveBuffer = szBuffer; + TCHAR * szBufferEnd = szBuffer + nMaxChars - 1; + char szHashSubPath[0x80]; + char szHashText[MD5_STRING_SIZE+1]; + + // Prepare the subpath + StringFromBinary(pbEKey, MD5_HASH_SIZE, szHashText); + CascStrPrintf(szHashSubPath, _countof(szHashSubPath), "%02x/%02x/%s", pbEKey[0], pbEKey[1], szHashText); + + szBuffer = AppendPathFragment(szBuffer, szBufferEnd, szSubDir, '/', true); + szBuffer = AppendPathFragment(szBuffer, szBufferEnd, szHashSubPath, '/'); + szBuffer = AppendPathFragment(szBuffer, szBufferEnd, szExtension, '/', true); + return (szBuffer - szSaveBuffer); +} + size_t NormalizeFileName(const unsigned char * NormTable, char * szNormName, const char * szFileName, size_t cchMaxChars) { char * szNormNameEnd = szNormName + cchMaxChars; @@ -257,19 +489,26 @@ size_t NormalizeFileName_LowerSlash(char * szNormName, const char * szFileName, return NormalizeFileName(AsciiToLowerTable_Slash, szNormName, szFileName, cchMaxChars); } -ULONGLONG CalcFileNameHash(const char * szFileName) +ULONGLONG CalcNormNameHash(const char * szNormName, size_t nLength) { - char szNormName[MAX_PATH+1]; uint32_t dwHashHigh = 0; uint32_t dwHashLow = 0; + + // Calculate the HASH value of the normalized file name + hashlittle2(szNormName, nLength, &dwHashHigh, &dwHashLow); + return ((ULONGLONG)dwHashHigh << 0x20) | dwHashLow; +} + +ULONGLONG CalcFileNameHash(const char * szFileName) +{ + char szNormName[MAX_PATH+1]; size_t nLength; // Normalize the file name - convert to uppercase, slashes to backslashes nLength = NormalizeFileName_UpperBkSlash(szNormName, szFileName, MAX_PATH); - // Calculate the HASH value of the normalized file name - hashlittle2(szNormName, nLength, &dwHashHigh, &dwHashLow); - return ((ULONGLONG)dwHashHigh << 0x20) | dwHashLow; + // Calculate hash from the normalized name + return CalcNormNameHash(szNormName, nLength); } int ConvertDigitToInt32(const TCHAR * szString, PDWORD PtrValue) @@ -373,13 +612,16 @@ char * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, char * szBuffer) { char * szSaveBuffer = szBuffer; - // Convert the string to the array of MD5 - // Copy the blob data as text - for(size_t i = 0; i < cbBinary; i++) + // Verify the binary pointer + if(pbBinary && cbBinary) { - *szBuffer++ = IntToHexChar[pbBinary[0] >> 0x04]; - *szBuffer++ = IntToHexChar[pbBinary[0] & 0x0F]; - pbBinary++; + // Convert the string to the array of MD5 + // Copy the blob data as text + for(size_t i = 0; i < cbBinary; i++) + { + *szBuffer++ = IntToHexChar[pbBinary[i] >> 0x04]; + *szBuffer++ = IntToHexChar[pbBinary[i] & 0x0F]; + } } // Terminate the string @@ -395,39 +637,51 @@ char * StringFromMD5(LPBYTE md5, char * szBuffer) //----------------------------------------------------------------------------- // File name utilities -const wchar_t * GetPlainFileName(const wchar_t * szFileName) +bool IsFileDataIdName(const char * szFileName, DWORD & FileDataId) { - const wchar_t * szPlainName = szFileName; + BYTE BinaryValue[4]; - while(*szFileName != 0) + // File name must begin with "File", case insensitive + if(AsciiToUpperTable_BkSlash[szFileName[0]] == 'F' && + AsciiToUpperTable_BkSlash[szFileName[1]] == 'I' && + AsciiToUpperTable_BkSlash[szFileName[2]] == 'L' && + AsciiToUpperTable_BkSlash[szFileName[3]] == 'E') { - if(*szFileName == '\\' || *szFileName == '/') - szPlainName = szFileName + 1; - szFileName++; + // Then, 8 hexadecimal digits must follow + if(ConvertStringToBinary(szFileName + 4, 8, BinaryValue) == ERROR_SUCCESS) + { + // Must be followed by an extension or end-of-string + if(szFileName[0x0C] == 0 || szFileName[0x0C] == '.') + { + FileDataId = ConvertBytesToInteger_4(BinaryValue); + return (FileDataId != CASC_INVALID_ID); + } + } } - return szPlainName; + return false; } -const char * GetPlainFileName(const char * szFileName) +bool IsFileCKeyEKeyName(const char * szFileName, LPBYTE PtrKeyBuffer) { - const char * szPlainName = szFileName; + size_t nLength = strlen(szFileName); - while(*szFileName != 0) + if(nLength == MD5_STRING_SIZE) { - if(*szFileName == '\\' || *szFileName == '/') - szPlainName = szFileName + 1; - szFileName++; + if(ConvertStringToBinary(szFileName, MD5_STRING_SIZE, PtrKeyBuffer) == ERROR_SUCCESS) + { + return true; + } } - return szPlainName; + return false; } -bool CheckWildCard(const char * szString, const char * szWildCard) +bool CascCheckWildCard(const char * szString, const char * szWildCard) { const char * szWildCardPtr; - for(;;) + while(szWildCard && szWildCard[0]) { // If there is '?' in the wildcard, we skip one char while(szWildCard[0] == '?') @@ -455,7 +709,7 @@ bool CheckWildCard(const char * szString, const char * szWildCard) if(AsciiToUpperTable_BkSlash[szWildCardPtr[0]] == AsciiToUpperTable_BkSlash[szString[0]]) { - if(CheckWildCard(szString, szWildCardPtr)) + if(CascCheckWildCard(szString, szWildCardPtr)) return true; } } @@ -476,244 +730,43 @@ bool CheckWildCard(const char * szString, const char * szWildCard) return (szString[0] == 0) ? true : false; } } + return true; } //----------------------------------------------------------------------------- // Hashing functions -bool IsValidMD5(LPBYTE pbMd5) +bool CascIsValidMD5(LPBYTE pbMd5) { - BYTE BitSummary = 0; + PDWORD Int32Array = (PDWORD)pbMd5; - // The MD5 is considered invalid of it is zeroed - BitSummary |= pbMd5[0x00] | pbMd5[0x01] | pbMd5[0x02] | pbMd5[0x03] | pbMd5[0x04] | pbMd5[0x05] | pbMd5[0x06] | pbMd5[0x07]; - BitSummary |= pbMd5[0x08] | pbMd5[0x09] | pbMd5[0x0A] | pbMd5[0x0B] | pbMd5[0x0C] | pbMd5[0x0D] | pbMd5[0x0E] | pbMd5[0x0F]; - return (BitSummary != 0); + // The MD5 is considered invalid if it is zeroed + return (Int32Array[0] | Int32Array[1] | Int32Array[2] | Int32Array[3]) ? true : false; } -bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5) +bool CascVerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5) { - hash_state md5_state; + MD5_CTX md5_ctx; BYTE md5_digest[MD5_HASH_SIZE]; // Don't verify the block if the MD5 is not valid. - if(!IsValidMD5(expected_md5)) + if(!CascIsValidMD5(expected_md5)) return true; // Calculate the MD5 of the data block - md5_init(&md5_state); - md5_process(&md5_state, (unsigned char *)pvDataBlock, cbDataBlock); - md5_done(&md5_state, md5_digest); + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, pvDataBlock, cbDataBlock); + MD5_Final(md5_digest, &md5_ctx); // Does the MD5's match? return (memcmp(md5_digest, expected_md5, MD5_HASH_SIZE) == 0); } -void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash) -{ - hash_state md5_state; - - md5_init(&md5_state); - md5_process(&md5_state, (unsigned char *)pvDataBlock, cbDataBlock); - md5_done(&md5_state, md5_hash); -} - -//----------------------------------------------------------------------------- -// We have our own qsort implementation, optimized for using array of pointers - -#define STKSIZ (8*sizeof(void*) - 2) - -#define SWAP_ENTRIES(index1, index2) \ -{ \ - temp = base[index1]; \ - base[index1] = base[index2]; \ - base[index2] = temp; \ -} - -void qsort_pointer_array(void ** base, size_t num, int (*compare)(const void *, const void *, const void *), const void * context) +void CascCalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash) { - size_t lo, hi; /* ends of sub-array currently sorting */ - size_t mid; /* points to middle of subarray */ - size_t loguy, higuy; /* traveling pointers for partition step */ - size_t size; /* size of the sub-array */ - size_t lostk[STKSIZ], histk[STKSIZ]; - void * temp; - int stkptr; /* stack for saving sub-array to be processed */ - - /* validation section */ - assert(base != NULL); - assert(compare != NULL); - - if (num < 2) - return; /* nothing to do */ - - stkptr = 0; /* initialize stack */ - - lo = 0; - hi = (num-1); /* initialize limits */ - - /* this entry point is for pseudo-recursion calling: setting - lo and hi and jumping to here is like recursion, but stkptr is - preserved, locals aren't, so we preserve stuff on the stack */ -recurse: - - size = (hi - lo) + 1; /* number of el's to sort */ - - /* First we pick a partitioning element. The efficiency of the - algorithm demands that we find one that is approximately the median - of the values, but also that we select one fast. We choose the - median of the first, middle, and last elements, to avoid bad - performance in the face of already sorted data, or data that is made - up of multiple sorted runs appended together. Testing shows that a - median-of-three algorithm provides better performance than simply - picking the middle element for the latter case. */ - - mid = lo + (size / 2); /* find middle element */ - - /* Sort the first, middle, last elements into order */ - if (compare(context, base[lo], base[mid]) > 0) { - SWAP_ENTRIES(lo, mid); - } - if (compare(context, base[lo], base[hi]) > 0) { - SWAP_ENTRIES(lo, hi); - } - if (compare(context, base[mid], base[hi]) > 0) { - SWAP_ENTRIES(mid, hi); - } - - /* We now wish to partition the array into three pieces, one consisting - of elements <= partition element, one of elements equal to the - partition element, and one of elements > than it. This is done - below; comments indicate conditions established at every step. */ - - loguy = lo; - higuy = hi; - - /* Note that higuy decreases and loguy increases on every iteration, - so loop must terminate. */ - for (;;) { - /* lo <= loguy < hi, lo < higuy <= hi, - A[i] <= A[mid] for lo <= i <= loguy, - A[i] > A[mid] for higuy <= i < hi, - A[hi] >= A[mid] */ - - /* The doubled loop is to avoid calling comp(mid,mid), since some - existing comparison funcs don't work when passed the same - value for both pointers. */ - - if (mid > loguy) { - do { - loguy ++; - } while (loguy < mid && compare(context, base[loguy], base[mid]) <= 0); - } - if (mid <= loguy) { - do { - loguy ++; - } while (loguy <= hi && compare(context, base[loguy], base[mid]) <= 0); - } - - /* lo < loguy <= hi+1, A[i] <= A[mid] for lo <= i < loguy, - either loguy > hi or A[loguy] > A[mid] */ - - do { - higuy --; - } while (higuy > mid && compare(context, base[higuy], base[mid]) > 0); - - /* lo <= higuy < hi, A[i] > A[mid] for higuy < i < hi, - either higuy == lo or A[higuy] <= A[mid] */ - - if (higuy < loguy) - break; - - /* if loguy > hi or higuy == lo, then we would have exited, so - A[loguy] > A[mid], A[higuy] <= A[mid], - loguy <= hi, higuy > lo */ - - SWAP_ENTRIES(loguy, higuy); - - /* If the partition element was moved, follow it. Only need - to check for mid == higuy, since before the swap, - A[loguy] > A[mid] implies loguy != mid. */ - - if (mid == higuy) - mid = loguy; - - /* A[loguy] <= A[mid], A[higuy] > A[mid]; so condition at top - of loop is re-established */ - } + MD5_CTX md5_ctx; - /* A[i] <= A[mid] for lo <= i < loguy, - A[i] > A[mid] for higuy < i < hi, - A[hi] >= A[mid] - higuy < loguy - implying: - higuy == loguy-1 - or higuy == hi - 1, loguy == hi + 1, A[hi] == A[mid] */ - - /* Find adjacent elements equal to the partition element. The - doubled loop is to avoid calling comp(mid,mid), since some - existing comparison funcs don't work when passed the same value - for both pointers. */ - - higuy ++; - if (mid < higuy) { - do { - higuy --; - } while (higuy > mid && compare(context, base[higuy], base[mid]) == 0); - } - if (mid >= higuy) { - do { - higuy --; - } while (higuy > lo && compare(context, base[higuy], base[mid]) == 0); - } - - /* OK, now we have the following: - higuy < loguy - lo <= higuy <= hi - A[i] <= A[mid] for lo <= i <= higuy - A[i] == A[mid] for higuy < i < loguy - A[i] > A[mid] for loguy <= i < hi - A[hi] >= A[mid] */ - - /* We've finished the partition, now we want to sort the subarrays - [lo, higuy] and [loguy, hi]. - We do the smaller one first to minimize stack usage. - We only sort arrays of length 2 or more.*/ - - if ( higuy - lo >= hi - loguy ) { - if (lo < higuy) { - lostk[stkptr] = lo; - histk[stkptr] = higuy; - ++stkptr; - } /* save big recursion for later */ - - if (loguy < hi) { - lo = loguy; - goto recurse; /* do small recursion */ - } - } - else { - if (loguy < hi) { - lostk[stkptr] = loguy; - histk[stkptr] = hi; - ++stkptr; /* save big recursion for later */ - } - - if (lo < higuy) { - hi = higuy; - goto recurse; /* do small recursion */ - } - } - - /* We have sorted the array, except for any pending sorts on the stack. - Check if there are any, and do them. */ - - --stkptr; - if (stkptr >= 0) { - lo = lostk[stkptr]; - hi = histk[stkptr]; - goto recurse; /* pop subarray from stack */ - } - else - return; /* all subarrays done */ + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, pvDataBlock, cbDataBlock); + MD5_Final(md5_hash, &md5_ctx); } |