solocraft + dynamicxp

This commit is contained in:
mikx
2023-11-05 15:26:19 -05:00
commit 146bd781e2
3402 changed files with 2098316 additions and 0 deletions

45
dep/CMakeLists.txt Normal file
View File

@@ -0,0 +1,45 @@
# Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
string(REGEX REPLACE "/W[0-4] " "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REGEX REPLACE "/W[0-4] " "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
add_definitions(/W0)
else()
add_definitions(-w)
endif()
if( CMAKE_COMPILER_IS_GNUCXX )
add_definitions(--no-warnings)
elseif( MSVC )
add_definitions(/W0)
endif()
add_subdirectory(threads)
add_subdirectory(boost)
add_subdirectory(process)
add_subdirectory(zlib)
add_subdirectory(g3dlite)
add_subdirectory(recastnavigation)
add_subdirectory(fmt)
add_subdirectory(SFMT)
add_subdirectory(utf8cpp)
add_subdirectory(openssl)
add_subdirectory(mysql)
add_subdirectory(readline)
add_subdirectory(gsoap)
add_subdirectory(rapidjson)
add_subdirectory(cds)
add_subdirectory(protobuf)
if(TOOLS)
add_subdirectory(bzip2)
add_subdirectory(CascLib)
endif()

View File

@@ -0,0 +1,63 @@
set(HEADER_FILES
src/CascCommon.h
src/CascLib.h
src/CascMndx.h
src/CascPort.h
src/common/Common.h
src/common/FileStream.h
src/common/ListFile.h
src/common/Map.h
src/jenkins/lookup.h
)
set(SRC_FILES
src/common/Common.cpp
src/common/Directory.cpp
src/common/DumpContext.cpp
src/common/DynamicArray.cpp
src/common/FileStream.cpp
src/common/ListFile.cpp
src/common/Map.cpp
src/common/RootHandler.cpp
src/jenkins/lookup3.c
src/CascCommon.cpp
src/CascDecompress.cpp
src/CascDecrypt.cpp
src/CascDumpData.cpp
src/CascFiles.cpp
src/CascFindFile.cpp
src/CascOpenFile.cpp
src/CascOpenStorage.cpp
src/CascReadFile.cpp
src/CascRootFile_Diablo3.cpp
src/CascRootFile_Mndx.cpp
src/CascRootFile_Ovr.cpp
src/CascRootFile_SC1.cpp
src/CascRootFile_WoW6.cpp
)
set(TOMCRYPT_FILES
src/libtomcrypt/src/hashes/hash_memory.c
src/libtomcrypt/src/hashes/md5.c
src/libtomcrypt/src/misc/crypt_argchk.c
src/libtomcrypt/src/misc/crypt_hash_descriptor.c
src/libtomcrypt/src/misc/crypt_hash_is_valid.c
src/libtomcrypt/src/misc/crypt_libc.c
)
add_library(casc STATIC ${SRC_FILES} ${TOMCRYPT_FILES})
target_include_directories(casc
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
PRIVATE
${CMAKE_SOURCE_DIR}/dep)
target_link_libraries(casc
PUBLIC
zlib)
set_target_properties(casc
PROPERTIES
FOLDER
"dep")

21
dep/CascLib/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Ladislav Zezula
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

4
dep/CascLib/README.md Normal file
View File

@@ -0,0 +1,4 @@
CascLib
=======
An open-source implementation of library for reading CASC storage from Blizzard games since 2014

View File

@@ -0,0 +1,6 @@
CascLib history
===============
Version 1.00
- Created

View File

@@ -0,0 +1,90 @@
/*****************************************************************************/
/* CascCommon.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* Common functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 29.04.14 1.00 Lad The first version of CascCommon.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
//-----------------------------------------------------------------------------
// Conversion of big-endian to integer
// Read the 24-bit big-endian offset into ULONGLONG
DWORD ConvertBytesToInteger_3(LPBYTE ValueAsBytes)
{
DWORD Value = 0;
Value = (Value << 0x08) | ValueAsBytes[0];
Value = (Value << 0x08) | ValueAsBytes[1];
Value = (Value << 0x08) | ValueAsBytes[2];
return Value;
}
// Read the 32-bit big-endian offset into ULONGLONG
DWORD ConvertBytesToInteger_4(LPBYTE ValueAsBytes)
{
DWORD Value = 0;
Value = (Value << 0x08) | ValueAsBytes[0];
Value = (Value << 0x08) | ValueAsBytes[1];
Value = (Value << 0x08) | ValueAsBytes[2];
Value = (Value << 0x08) | ValueAsBytes[3];
return Value;
}
DWORD ConvertBytesToInteger_4_LE(LPBYTE ValueAsBytes)
{
DWORD Value = 0;
Value = (Value << 0x08) | ValueAsBytes[3];
Value = (Value << 0x08) | ValueAsBytes[2];
Value = (Value << 0x08) | ValueAsBytes[1];
Value = (Value << 0x08) | ValueAsBytes[0];
return Value;
}
// Read the 40-bit big-endian offset into ULONGLONG
ULONGLONG ConvertBytesToInteger_5(LPBYTE ValueAsBytes)
{
ULONGLONG Value = 0;
Value = (Value << 0x08) | ValueAsBytes[0];
Value = (Value << 0x08) | ValueAsBytes[1];
Value = (Value << 0x08) | ValueAsBytes[2];
Value = (Value << 0x08) | ValueAsBytes[3];
Value = (Value << 0x08) | ValueAsBytes[4];
return Value;
}
void ConvertIntegerToBytes_4(DWORD Value, LPBYTE ValueAsBytes)
{
ValueAsBytes[0] = (Value >> 0x18) & 0xFF;
ValueAsBytes[1] = (Value >> 0x10) & 0xFF;
ValueAsBytes[2] = (Value >> 0x08) & 0xFF;
ValueAsBytes[3] = (Value >> 0x00) & 0xFF;
}
//-----------------------------------------------------------------------------
// Common fre routine of a CASC blob
void FreeCascBlob(PQUERY_KEY pBlob)
{
if(pBlob != NULL)
{
if(pBlob->pbData != NULL)
CASC_FREE(pBlob->pbData);
pBlob->pbData = NULL;
pBlob->cbData = 0;
}
}

View File

@@ -0,0 +1,363 @@
/*****************************************************************************/
/* CascCommon.h Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* Common functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 29.04.14 1.00 Lad The first version of CascCommon.h */
/*****************************************************************************/
#ifndef __CASCCOMMON_H__
#define __CASCCOMMON_H__
//-----------------------------------------------------------------------------
// Compression support
// Include functions from zlib
#ifndef __SYS_ZLIB
#include "zlib/zlib.h"
#else
#include <zlib.h>
#endif
#include "CascPort.h"
#include "common/Common.h"
#include "common/DynamicArray.h"
#include "common/Map.h"
#include "common/FileStream.h"
#include "common/Directory.h"
#include "common/ListFile.h"
#include "common/DumpContext.h"
#include "common/RootHandler.h"
// Headers from LibTomCrypt
#include "libtomcrypt/src/headers/tomcrypt.h"
// For HashStringJenkins
#include "jenkins/lookup.h"
//-----------------------------------------------------------------------------
// CascLib private defines
#define CASC_GAME_HOTS 0x00010000 // Heroes of the Storm
#define CASC_GAME_WOW6 0x00020000 // World of Warcraft - Warlords of Draenor
#define CASC_GAME_DIABLO3 0x00030000 // Diablo 3 since PTR 2.2.0
#define CASC_GAME_OVERWATCH 0x00040000 // Overwatch since PTR 24919
#define CASC_GAME_STARCRAFT2 0x00050000 // Starcraft II - Legacy of the Void, since build 38996
#define CASC_GAME_STARCRAFT1 0x00060000 // Starcraft 1 (remastered)
#define CASC_GAME_MASK 0xFFFF0000 // Mask for getting game ID
#define CASC_INDEX_COUNT 0x10
#define CASC_FILE_KEY_SIZE 0x09 // Size of the file key
#define CASC_MAX_DATA_FILES 0x100
#define CASC_EXTRA_FILES 0x20 // Number of extra entries to be reserved for additionally inserted files
#define CASC_SEARCH_HAVE_NAME 0x0001 // Indicated that previous search found a name
#define BLTE_HEADER_SIGNATURE 0x45544C42 // 'BLTE' header in the data files
#define BLTE_HEADER_DELTA 0x1E // Distance of BLTE header from begin of the header area
#define MAX_HEADER_AREA_SIZE 0x2A // Length of the file header area
// File header area in the data.nnn:
// BYTE HeaderHash[MD5_HASH_SIZE]; // MD5 of the frame array
// DWORD dwFileSize; // Size of the file (see comment before CascGetFileSize for details)
// BYTE SomeSize[4]; // Some size (big endian)
// BYTE Padding[6]; // Padding (?)
// DWORD dwSignature; // Must be "BLTE"
// BYTE HeaderSizeAsBytes[4]; // Header size in bytes (big endian)
// BYTE MustBe0F; // Must be 0x0F. Optional, only if HeaderSizeAsBytes != 0
// BYTE FrameCount[3]; // Frame count (big endian). Optional, only if HeaderSizeAsBytes != 0
// Prevent problems with CRT "min" and "max" functions,
// as they are not defined on all platforms
#define CASCLIB_MIN(a, b) ((a < b) ? a : b)
#define CASCLIB_MAX(a, b) ((a > b) ? a : b)
#define CASCLIB_UNUSED(p) ((void)(p))
#define CASC_PACKAGE_BUFFER 0x1000
#ifndef _maxchars
#define _maxchars(buff) ((sizeof(buff) / sizeof(buff[0])) - 1)
#endif
//-----------------------------------------------------------------------------
// In-memory structures
// See http://pxr.dk/wowdev/wiki/index.php?title=CASC for more information
struct TFileStream;
typedef enum _CBLD_TYPE
{
CascBuildNone = 0, // No build type found
CascBuildInfo, // .build.info
CascBuildDb, // .build.db (older storages)
} CBLD_TYPE, *PCBLD_TYPE;
typedef struct _ENCODING_KEY
{
BYTE Value[MD5_HASH_SIZE]; // MD5 of the file
} ENCODING_KEY, *PENCODING_KEY;
typedef struct _CASC_INDEX_ENTRY
{
BYTE IndexKey[CASC_FILE_KEY_SIZE]; // The first 9 bytes of the encoding key
BYTE FileOffsetBE[5]; // Index of data file and offset within (big endian).
BYTE FileSizeLE[4]; // Size occupied in the storage file (data.###). See comment before CascGetFileSize for details
} CASC_INDEX_ENTRY, *PCASC_INDEX_ENTRY;
typedef struct _CASC_MAPPING_TABLE
{
TCHAR * szFileName; // Name of the key mapping file
LPBYTE pbFileData; // Pointer to the file data
DWORD cbFileData; // Length of the file data
BYTE ExtraBytes; // (?) Extra bytes in the key record
BYTE SpanSizeBytes; // Size of field with file size
BYTE SpanOffsBytes; // Size of field with file offset
BYTE KeyBytes; // Size of the file key
BYTE SegmentBits; // Number of bits for the file offset (rest is archive index)
ULONGLONG MaxFileOffset;
PCASC_INDEX_ENTRY pIndexEntries; // Sorted array of index entries
DWORD nIndexEntries; // Number of index entries
} CASC_MAPPING_TABLE, *PCASC_MAPPING_TABLE;
typedef struct _CASC_FILE_FRAME
{
DWORD FrameArchiveOffset; // Archive file pointer corresponding to the begin of the frame
DWORD FrameFileOffset; // File pointer corresponding to the begin of the frame
DWORD CompressedSize; // Compressed size of the file
DWORD FrameSize; // Size of the frame
BYTE md5[MD5_HASH_SIZE]; // MD5 hash of the file sector
} CASC_FILE_FRAME, *PCASC_FILE_FRAME;
// The encoding file is in the form of:
// * File header
// * String block #1
// * Table A header
// * Table A entries
// * Table B header
// * Table B entries
// * String block #2
// http://pxr.dk/wowdev/wiki/index.php?title=CASC#Key_CASC_Files
typedef struct _CASC_ENCODING_HEADER
{
BYTE Magic[2]; // "EN"
BYTE Version; // Expected to be 1 by CascLib
BYTE ChecksumSizeA; // The length of the checksums in Encoding Table
BYTE ChecksumSizeB; // The length of the checksums in Encoding Layout Table
BYTE Flags_TableA[2]; // Flags for Encoding Table
BYTE Flags_TableB[2]; // Flags for Encoding Layout Table
BYTE Entries_TableA[4]; // Number of segments in Encoding Table (big endian)
BYTE Entries_TableB[4]; // Number of segments in Encoding Layout Table (big endian)
BYTE field_11;
BYTE Size_StringTable1[4]; // Size of the string block #1
} CASC_ENCODING_HEADER, *PCASC_ENCODING_HEADER;
typedef struct _CASC_ENCODING_ENTRY
{
USHORT KeyCount; // Number of index keys
BYTE FileSizeBE[4]; // Compressed file size (header area + frame headers + compressed frames), in bytes
BYTE EncodingKey[MD5_HASH_SIZE]; // File encoding key
// Followed by the index keys
// (number of items = KeyCount)
// Followed by the index keys (number of items = KeyCount)
} CASC_ENCODING_ENTRY, *PCASC_ENCODING_ENTRY;
// A version of CASC_ENCODING_ENTRY with one index key
typedef struct _CASC_ENCODING_ENTRY_1
{
USHORT KeyCount; // Number of index keys
BYTE FileSizeBE[4]; // Compressed file size (header area + frame headers + compressed frames), in bytes
BYTE EncodingKey[MD5_HASH_SIZE]; // File encoding key
BYTE IndexKey[MD5_HASH_SIZE]; // File index key
} CASC_ENCODING_ENTRY_1, *PCASC_ENCODING_ENTRY_1;
#define GET_INDEX_KEY(pEncodingEntry) (pEncodingEntry->EncodingKey + MD5_HASH_SIZE)
#define FAKE_ENCODING_ENTRY_SIZE (sizeof(CASC_ENCODING_ENTRY) + MD5_HASH_SIZE)
//-----------------------------------------------------------------------------
// Structures for CASC storage and CASC file
typedef struct _TCascStorage
{
const char * szClassName; // "TCascStorage"
const TCHAR * szIndexFormat; // Format of the index file name
TCHAR * szRootPath; // This is the game directory
TCHAR * szDataPath; // This is the directory where data files are
TCHAR * szBuildFile; // Build file name (.build.info or .build.db)
TCHAR * szIndexPath; // This is the directory where index files are
TCHAR * szUrlPath; // URL to the Blizzard servers
DWORD dwRefCount; // Number of references
DWORD dwGameInfo; // Game type
DWORD dwBuildNumber; // Game build number
DWORD dwFileBeginDelta; // This is number of bytes to shift back from archive offset (from index entry) to actual begin of file data
DWORD dwDefaultLocale; // Default locale, read from ".build.info"
CBLD_TYPE BuildFileType; // Type of the build file
QUERY_KEY CdnConfigKey;
QUERY_KEY CdnBuildKey;
QUERY_KEY ArchivesGroup; // Key array of the "archive-group"
QUERY_KEY ArchivesKey; // Key array of the "archives"
QUERY_KEY PatchArchivesKey; // Key array of the "patch-archives"
QUERY_KEY PatchArchivesGroup; // Key array of the "patch-archive-group"
QUERY_KEY RootKey;
QUERY_KEY PatchKey;
QUERY_KEY DownloadKey;
QUERY_KEY InstallKey;
QUERY_KEY EncodingKey;
TFileStream * DataFileArray[CASC_MAX_DATA_FILES]; // Data file handles
CASC_MAPPING_TABLE KeyMapping[CASC_INDEX_COUNT]; // Key mapping
PCASC_MAP pIndexEntryMap; // Map of index entries
QUERY_KEY EncodingFile; // Content of the ENCODING file
PCASC_MAP pEncodingMap; // Map of encoding entries
DYNAMIC_ARRAY ExtraEntries; // Extra encoding entries
TRootHandler * pRootHandler; // Common handler for various ROOT file formats
} TCascStorage;
typedef struct _TCascFile
{
TCascStorage * hs; // Pointer to storage structure
TFileStream * pStream; // An open data stream
const char * szClassName; // "TCascFile"
DWORD FilePointer; // Current file pointer
DWORD ArchiveIndex; // Index of the archive (data.###)
DWORD HeaderOffset; // Offset of the BLTE header, relative to the begin of the archive
DWORD HeaderSize; // Length of the BLTE header
DWORD FramesOffset; // Offset of the frame data, relative to the begin of the archive
DWORD CompressedSize; // Compressed size of the file (in bytes)
DWORD FileSize; // Size of file, in bytes
BYTE FrameArrayHash[MD5_HASH_SIZE]; // MD5 hash of the frame array
PCASC_FILE_FRAME pFrames; // Array of file frames
DWORD FrameCount; // Number of the file frames
LPBYTE pbFileCache; // Pointer to file cache
DWORD cbFileCache; // Size of the file cache
DWORD CacheStart; // Starting offset in the cache
DWORD CacheEnd; // Ending offset in the cache
#ifdef CASCLIB_TEST // Extra fields for analyzing the file size problem
DWORD FileSize_RootEntry; // File size, from the root entry
DWORD FileSize_EncEntry; // File size, from the encoding entry
DWORD FileSize_IdxEntry; // File size, from the index entry
DWORD FileSize_HdrArea; // File size, as stated in the file header area
DWORD FileSize_FrameSum; // File size as sum of frame sizes
#endif
} TCascFile;
typedef struct _TCascSearch
{
TCascStorage * hs; // Pointer to the storage handle
const char * szClassName; // Contains "TCascSearch"
TCHAR * szListFile; // Name of the listfile
void * pCache; // Listfile cache
char * szMask; // Search mask
char szFileName[MAX_PATH]; // Buffer for the file name
// Provider-specific data
void * pRootContext; // Root-specific search context
size_t IndexLevel1; // Root-specific search context
size_t IndexLevel2; // Root-specific search context
DWORD dwState; // Pointer to the search state (0 = listfile, 1 = nameless, 2 = done)
BYTE BitArray[1]; // Bit array of encoding keys. Set for each entry that has already been reported
} TCascSearch;
//-----------------------------------------------------------------------------
// Memory management
//
// We use our own macros for allocating/freeing memory. If you want
// to redefine them, please keep the following rules:
//
// - The memory allocation must return NULL if not enough memory
// (i.e not to throw exception)
// - The allocating function does not need to fill the allocated buffer with zeros
// - The reallocating function must support NULL as the previous block
// - Memory freeing function doesn't have to test the pointer to NULL
//
#if defined(_MSC_VER) && defined(_DEBUG)
#define CASC_REALLOC(type, ptr, count) (type *)HeapReAlloc(GetProcessHeap(), 0, ptr, ((count) * sizeof(type)))
#define CASC_ALLOC(type, count) (type *)HeapAlloc(GetProcessHeap(), 0, ((count) * sizeof(type)))
#define CASC_FREE(ptr) HeapFree(GetProcessHeap(), 0, ptr)
#else
#define CASC_REALLOC(type, ptr, count) (type *)realloc(ptr, (count) * sizeof(type))
#define CASC_ALLOC(type, count) (type *)malloc((count) * sizeof(type))
#define CASC_FREE(ptr) free(ptr)
#endif
//-----------------------------------------------------------------------------
// Big endian number manipulation
DWORD ConvertBytesToInteger_3(LPBYTE ValueAsBytes);
DWORD ConvertBytesToInteger_4(LPBYTE ValueAsBytes);
DWORD ConvertBytesToInteger_4_LE(LPBYTE ValueAsBytes);
ULONGLONG ConvertBytesToInteger_5(LPBYTE ValueAsBytes);
void ConvertIntegerToBytes_4(DWORD Value, LPBYTE ValueAsBytes);
void FreeCascBlob(PQUERY_KEY pQueryKey);
//-----------------------------------------------------------------------------
// Text file parsing (CascFiles.cpp)
int LoadBuildInfo(TCascStorage * hs);
int CheckGameDirectory(TCascStorage * hs, TCHAR * szDirectory);
int GetRootVariableIndex(const char * szLinePtr, const char * szLineEnd, const char * szVariableName, int * PtrIndex);
int ParseRootFileLine(const char * szLinePtr, const char * szLineEnd, int nFileNameIndex, PQUERY_KEY pEncodingKey, char * szFileName, size_t nMaxChars);
//-----------------------------------------------------------------------------
// Internal file functions
TCascStorage * IsValidStorageHandle(HANDLE hStorage);
TCascFile * IsValidFileHandle(HANDLE hFile);
PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, PDWORD PtrIndex);
PCASC_INDEX_ENTRY FindIndexEntry(TCascStorage * hs, PQUERY_KEY pIndexKey);
int CascDecompress(LPBYTE pvOutBuffer, PDWORD pcbOutBuffer, LPBYTE pvInBuffer, DWORD cbInBuffer);
int CascDecrypt (LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer, DWORD dwFrameIndex);
int CascDirectCopy(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer);
//-----------------------------------------------------------------------------
// Support for ROOT file
int RootHandler_CreateMNDX(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);
int RootHandler_CreateDiablo3(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);
int RootHandler_CreateOverwatch(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);
int RootHandler_CreateWoW6(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile, DWORD dwLocaleMask);
int RootHandler_CreateSC1(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);
//-----------------------------------------------------------------------------
// Dumping CASC data structures
#ifdef _DEBUG
void CascDumpSparseArray(const char * szFileName, void * pvSparseArray);
void CascDumpNameFragTable(const char * szFileName, void * pvMarFile);
void CascDumpFileNames(const char * szFileName, void * pvMarFile);
void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs);
void CascDumpEncodingEntry(TCascStorage * hs, TDumpContext * dc, PCASC_ENCODING_ENTRY pEncodingEntry, int nDumpLevel);
void CascDumpFile(const char * szFileName, HANDLE hFile);
#endif // _DEBUG
#endif // __CASCCOMMON_H__

View File

@@ -0,0 +1,46 @@
/*****************************************************************************/
/* CascDecompress.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* Decompression functions */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 02.05.14 1.00 Lad The first version of CascDecompress.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
//-----------------------------------------------------------------------------
// Public functions
int CascDecompress(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer)
{
z_stream z; // Stream information for zlib
int nResult;
// Fill the stream structure for zlib
z.next_in = pbInBuffer;
z.avail_in = cbInBuffer;
z.total_in = cbInBuffer;
z.next_out = pbOutBuffer;
z.avail_out = *pcbOutBuffer;
z.total_out = 0;
z.zalloc = NULL;
z.zfree = NULL;
// Initialize the decompression structure
if((nResult = inflateInit(&z)) == Z_OK)
{
// Call zlib to decompress the data
nResult = inflate(&z, Z_NO_FLUSH);
inflateEnd(&z);
// Give the size of the uncompressed data
*pcbOutBuffer = z.total_out;
}
// Return an error code
return (nResult == Z_OK || nResult == Z_STREAM_END) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT;
}

View File

@@ -0,0 +1,394 @@
/*****************************************************************************/
/* CascDecrypt.cpp Copyright (c) Ladislav Zezula 2015 */
/*---------------------------------------------------------------------------*/
/* Decryption functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 31.10.15 1.00 Lad The first version of CascDecrypt.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
//-----------------------------------------------------------------------------
// Local structures
typedef struct _CASC_ENCRYPTION_KEY
{
ULONGLONG KeyName; // "Name" of the key
BYTE Key[0x10]; // The key itself
} CASC_ENCRYPTION_KEY, *PCASC_ENCRYPTION_KEY;
typedef struct _CASC_SALSA20
{
DWORD Key[0x10];
DWORD dwRounds;
} CASC_SALSA20, *PCASC_SALSA20;
//-----------------------------------------------------------------------------
// Known encryption keys. See https://wowdev.wiki/CASC for updates
static CASC_ENCRYPTION_KEY CascKeys[] =
{
// Key Name Encryption key Seen in
// ---------------------- ------------------------------------------------------------------------------------------------ -----------
// Battle.net app
{ 0x2C547F26A2613E01ULL, { 0x37, 0xC5, 0x0C, 0x10, 0x2D, 0x4C, 0x9E, 0x3A, 0x5A, 0xC0, 0x69, 0xF0, 0x72, 0xB1, 0x41, 0x7D } }, // Battle.net App Alpha 1.5.0
// Overwatch
{ 0xFB680CB6A8BF81F3ULL, { 0x62, 0xD9, 0x0E, 0xFA, 0x7F, 0x36, 0xD7, 0x1C, 0x39, 0x8A, 0xE2, 0xF1, 0xFE, 0x37, 0xBD, 0xB9 } }, // 0.8.0.24919_retailx64 (hardcoded)
{ 0x402CD9D8D6BFED98ULL, { 0xAE, 0xB0, 0xEA, 0xDE, 0xA4, 0x76, 0x12, 0xFE, 0x6C, 0x04, 0x1A, 0x03, 0x95, 0x8D, 0xF2, 0x41 } }, // 0.8.0.24919_retailx64 (hardcoded)
{ 0xDBD3371554F60306ULL, { 0x34, 0xE3, 0x97, 0xAC, 0xE6, 0xDD, 0x30, 0xEE, 0xFD, 0xC9, 0x8A, 0x2A, 0xB0, 0x93, 0xCD, 0x3C } }, // 0.8.0.24919_retailx64 (streamed from server)
{ 0x11A9203C9881710AULL, { 0x2E, 0x2C, 0xB8, 0xC3, 0x97, 0xC2, 0xF2, 0x4E, 0xD0, 0xB5, 0xE4, 0x52, 0xF1, 0x8D, 0xC2, 0x67 } }, // 0.8.0.24919_retailx64 (streamed from server)
{ 0xA19C4F859F6EFA54ULL, { 0x01, 0x96, 0xCB, 0x6F, 0x5E, 0xCB, 0xAD, 0x7C, 0xB5, 0x28, 0x38, 0x91, 0xB9, 0x71, 0x2B, 0x4B } }, // 0.8.0.24919_retailx64 (streamed from server)
{ 0x87AEBBC9C4E6B601ULL, { 0x68, 0x5E, 0x86, 0xC6, 0x06, 0x3D, 0xFD, 0xA6, 0xC9, 0xE8, 0x52, 0x98, 0x07, 0x6B, 0x3D, 0x42 } }, // 0.8.0.24919_retailx64 (streamed from server)
{ 0xDEE3A0521EFF6F03ULL, { 0xAD, 0x74, 0x0C, 0xE3, 0xFF, 0xFF, 0x92, 0x31, 0x46, 0x81, 0x26, 0x98, 0x57, 0x08, 0xE1, 0xB9 } }, // 0.8.0.24919_retailx64 (streamed from server)
{ 0x8C9106108AA84F07ULL, { 0x53, 0xD8, 0x59, 0xDD, 0xA2, 0x63, 0x5A, 0x38, 0xDC, 0x32, 0xE7, 0x2B, 0x11, 0xB3, 0x2F, 0x29 } }, // 0.8.0.24919_retailx64 (streamed from server)
{ 0x49166D358A34D815ULL, { 0x66, 0x78, 0x68, 0xCD, 0x94, 0xEA, 0x01, 0x35, 0xB9, 0xB1, 0x6C, 0x93, 0xB1, 0x12, 0x4A, 0xBA } }, // 0.8.0.24919_retailx64 (streamed from server)
{ 0x1463A87356778D14ULL, { 0x69, 0xBD, 0x2A, 0x78, 0xD0, 0x5C, 0x50, 0x3E, 0x93, 0x99, 0x49, 0x59, 0xB3, 0x0E, 0x5A, 0xEC } }, // ? 1.0.3.0 (streamed from server)
{ 0x5E152DE44DFBEE01ULL, { 0xE4, 0x5A, 0x17, 0x93, 0xB3, 0x7E, 0xE3, 0x1A, 0x8E, 0xB8, 0x5C, 0xEE, 0x0E, 0xEE, 0x1B, 0x68 } }, // ? 1.0.3.0 (streamed from server)
{ 0x9B1F39EE592CA415ULL, { 0x54, 0xA9, 0x9F, 0x08, 0x1C, 0xAD, 0x0D, 0x08, 0xF7, 0xE3, 0x36, 0xF4, 0x36, 0x8E, 0x89, 0x4C } }, // ? 1.0.3.0 (streamed from server)
{ 0x24C8B75890AD5917ULL, { 0x31, 0x10, 0x0C, 0x00, 0xFD, 0xE0, 0xCE, 0x18, 0xBB, 0xB3, 0x3F, 0x3A, 0xC1, 0x5B, 0x30, 0x9F } }, // ? 1.0.3.0 (included in game)
{ 0xEA658B75FDD4890FULL, { 0xDE, 0xC7, 0xA4, 0xE7, 0x21, 0xF4, 0x25, 0xD1, 0x33, 0x03, 0x98, 0x95, 0xC3, 0x60, 0x36, 0xF8 } }, // ? 1.0.3.0 (included in game)
{ 0x026FDCDF8C5C7105ULL, { 0x8F, 0x41, 0x80, 0x9D, 0xA5, 0x53, 0x66, 0xAD, 0x41, 0x6D, 0x3C, 0x33, 0x74, 0x59, 0xEE, 0xE3 } }, // (included in game)
{ 0xCAE3FAC925F20402ULL, { 0x98, 0xB7, 0x8E, 0x87, 0x74, 0xBF, 0x27, 0x50, 0x93, 0xCB, 0x1B, 0x5F, 0xC7, 0x14, 0x51, 0x1B } }, // (included in game)
{ 0x061581CA8496C80CULL, { 0xDA, 0x2E, 0xF5, 0x05, 0x2D, 0xB9, 0x17, 0x38, 0x0B, 0x8A, 0xA6, 0xEF, 0x7A, 0x5F, 0x8E, 0x6A } }, //
{ 0xBE2CB0FAD3698123ULL, { 0x90, 0x2A, 0x12, 0x85, 0x83, 0x6C, 0xE6, 0xDA, 0x58, 0x95, 0x02, 0x0D, 0xD6, 0x03, 0xB0, 0x65 } }, //
{ 0x57A5A33B226B8E0AULL, { 0xFD, 0xFC, 0x35, 0xC9, 0x9B, 0x9D, 0xB1, 0x1A, 0x32, 0x62, 0x60, 0xCA, 0x24, 0x6A, 0xCB, 0x41 } }, // 1.1.0.0.30200 Ana
{ 0x42B9AB1AF5015920ULL, { 0xC6, 0x87, 0x78, 0x82, 0x3C, 0x96, 0x4C, 0x6F, 0x24, 0x7A, 0xCC, 0x0F, 0x4A, 0x25, 0x84, 0xF8 } }, // 1.2.0.1.30684 Summer Games
{ 0x4F0FE18E9FA1AC1AULL, { 0x89, 0x38, 0x1C, 0x74, 0x8F, 0x65, 0x31, 0xBB, 0xFC, 0xD9, 0x77, 0x53, 0xD0, 0x6C, 0xC3, 0xCD } }, // 1.2.0.1.30684
{ 0x7758B2CF1E4E3E1BULL, { 0x3D, 0xE6, 0x0D, 0x37, 0xC6, 0x64, 0x72, 0x35, 0x95, 0xF2, 0x7C, 0x5C, 0xDB, 0xF0, 0x8B, 0xFA } }, // 1.2.0.1.30684
{ 0xE5317801B3561125ULL, { 0x7D, 0xD0, 0x51, 0x19, 0x9F, 0x84, 0x01, 0xF9, 0x5E, 0x4C, 0x03, 0xC8, 0x84, 0xDC, 0xEA, 0x33 } }, // 1.4.0.2.32143 Halloween Terror
{ 0x16B866D7BA3A8036ULL, { 0x13, 0x95, 0xE8, 0x82, 0xBF, 0x25, 0xB4, 0x81, 0xF6, 0x1A, 0x4D, 0x62, 0x11, 0x41, 0xDA, 0x6E } }, // 1.4.1.0.31804 Bastion Blizzcon 2016 skin
{ 0x11131FFDA0D18D30ULL, { 0xC3, 0x2A, 0xD1, 0xB8, 0x25, 0x28, 0xE0, 0xA4, 0x56, 0x89, 0x7B, 0x3C, 0xE1, 0xC2, 0xD2, 0x7E } }, // 1.5.0.1.32795 Sombra
{ 0xCAC6B95B2724144AULL, { 0x73, 0xE4, 0xBE, 0xA1, 0x45, 0xDF, 0x2B, 0x89, 0xB6, 0x5A, 0xEF, 0x02, 0xF8, 0x3F, 0xA2, 0x60 } }, // 1.5.0.1.32795 Ecopoint: Antarctica
{ 0xB7DBC693758A5C36ULL, { 0xBC, 0x3A, 0x92, 0xBF, 0xE3, 0x02, 0x51, 0x8D, 0x91, 0xCC, 0x30, 0x79, 0x06, 0x71, 0xBF, 0x10 } }, // 1.5.0.1.32795 Genji Oni skin
{ 0x90CA73B2CDE3164BULL, { 0x5C, 0xBF, 0xF1, 0x1F, 0x22, 0x72, 0x0B, 0xAC, 0xC2, 0xAE, 0x6A, 0xAD, 0x8F, 0xE5, 0x33, 0x17 } }, // 1.6.1.0.33236 Oasis map
{ 0x6DD3212FB942714AULL, { 0xE0, 0x2C, 0x16, 0x43, 0x60, 0x2E, 0xC1, 0x6C, 0x3A, 0xE2, 0xA4, 0xD2, 0x54, 0xA0, 0x8F, 0xD9 } }, // 1.6.1.0.33236
{ 0x11DDB470ABCBA130ULL, { 0x66, 0x19, 0x87, 0x66, 0xB1, 0xC4, 0xAF, 0x75, 0x89, 0xEF, 0xD1, 0x3A, 0xD4, 0xDD, 0x66, 0x7A } }, // 1.6.1.0.33236 Winter Wonderland
{ 0x5BEF27EEE95E0B4BULL, { 0x36, 0xBC, 0xD2, 0xB5, 0x51, 0xFF, 0x1C, 0x84, 0xAA, 0x3A, 0x39, 0x94, 0xCC, 0xEB, 0x03, 0x3E } }, //
{ 0x9359B46E49D2DA42ULL, { 0x17, 0x3D, 0x65, 0xE7, 0xFC, 0xAE, 0x29, 0x8A, 0x93, 0x63, 0xBD, 0x6A, 0xA1, 0x89, 0xF2, 0x00 } }, // Diablo's 20th anniversary
{ 0x1A46302EF8896F34ULL, { 0x80, 0x29, 0xAD, 0x54, 0x51, 0xD4, 0xBC, 0x18, 0xE9, 0xD0, 0xF5, 0xAC, 0x44, 0x9D, 0xC0, 0x55 } }, // 1.7.0.2.34156 Year of the Rooster
{ 0x693529F7D40A064CULL, { 0xCE, 0x54, 0x87, 0x3C, 0x62, 0xDA, 0xA4, 0x8E, 0xFF, 0x27, 0xFC, 0xC0, 0x32, 0xBD, 0x07, 0xE3 } }, // 1.8.0.0.34470 CTF Maps
{ 0x388B85AEEDCB685DULL, { 0xD9, 0x26, 0xE6, 0x59, 0xD0, 0x4A, 0x09, 0x6B, 0x24, 0xC1, 0x91, 0x51, 0x07, 0x6D, 0x37, 0x9A } }, // 1.8.0.0.34470 Numbani Update (Doomfist teaser)
{ 0xE218F69AAC6C104DULL, { 0xF4, 0x3D, 0x12, 0xC9, 0x4A, 0x9A, 0x52, 0x84, 0x97, 0x97, 0x1F, 0x1C, 0xBE, 0x41, 0xAD, 0x4D } }, // 1.9.0.0.34986 Orisa
{ 0xF432F0425363F250ULL, { 0xBA, 0x69, 0xF2, 0xB3, 0x3C, 0x27, 0x68, 0xF5, 0xF2, 0x9B, 0xFE, 0x78, 0xA5, 0xA1, 0xFA, 0xD5 } }, // 1.10.0.0.35455 Uprising
{ 0x061D52F86830B35DULL, { 0xD7, 0x79, 0xF9, 0xC6, 0xCC, 0x9A, 0x4B, 0xE1, 0x03, 0xA4, 0xE9, 0x0A, 0x73, 0x38, 0xF7, 0x93 } }, // 1.10.0.0.35455 D.Va Officer Skin (HotS Nexus Challenge 2)
{ 0x1275C84CF113EF65ULL, { 0xCF, 0x58, 0xB6, 0x93, 0x3E, 0xAF, 0x98, 0xAF, 0x53, 0xE7, 0x6F, 0x84, 0x26, 0xCC, 0x7E, 0x6C } }, //
{ 0xD9C7C7AC0F14C868ULL, { 0x3A, 0xFD, 0xF6, 0x8E, 0x3A, 0x5D, 0x63, 0xBA, 0xBA, 0x1E, 0x68, 0x21, 0x88, 0x3F, 0x06, 0x7D } }, //
{ 0xBD4E42661A432951ULL, { 0x6D, 0xE8, 0xE2, 0x8C, 0x85, 0x11, 0x64, 0x4D, 0x55, 0x95, 0xFC, 0x45, 0xE5, 0x35, 0x14, 0x72 } }, // 1.11.0.0.36376 Anniversary event
{ 0xC43CB14355249451ULL, { 0x0E, 0xA2, 0xB4, 0x4F, 0x96, 0xA2, 0x69, 0xA3, 0x86, 0x85, 0x6D, 0x04, 0x9A, 0x3D, 0xEC, 0x86 } }, // 1.12.0.0.37104 Horizon Lunar Colony
{ 0xE6D914F8E4744953ULL, { 0xC8, 0x47, 0x7C, 0x28, 0x9D, 0xCE, 0x66, 0xD9, 0x13, 0x65, 0x07, 0xA3, 0x3A, 0xA3, 0x33, 0x01 } }, // 1.13.0.0.37646 Doomfist
{ 0x5694C503F8C80178ULL, { 0x7F, 0x4C, 0xF1, 0xC1, 0xFB, 0xBA, 0xD9, 0x2B, 0x18, 0x43, 0x36, 0xD6, 0x77, 0xEB, 0xF9, 0x37 } }, // 1.13.0.0.37646 Doomfist
{ 0x21DBFD65F3E54269ULL, { 0xAB, 0x58, 0x0C, 0x38, 0x37, 0xCA, 0xF8, 0xA4, 0x61, 0xF2, 0x43, 0xA5, 0x66, 0xB2, 0xAE, 0x4D } }, // 1.13.0.0.37646 Summer Games 2017
// { 0x27ABA5F88DD8D078ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??}}, // 1.13.0.0.37646
{ 0x21E1F90E71D33C71ULL, { 0x32, 0x87, 0x42, 0x33, 0x91, 0x62, 0xB3, 0x26, 0x76, 0xC8, 0x03, 0xC2, 0x25, 0x59, 0x31, 0xA6 } }, // 1.14.1.0.39083 Deathmatch
{ 0xD9CB055BCDD40B6EULL, { 0x49, 0xFB, 0x44, 0x77, 0xA4, 0xA0, 0x82, 0x53, 0x27, 0xE9, 0xA7, 0x36, 0x82, 0xBE, 0xCD, 0x0C } }, // 1.15.0.0.????? Junkertown
{ 0x8175CE3C694C6659ULL, { 0xE3, 0xF3, 0xFA, 0x77, 0x26, 0xC7, 0x0D, 0x26, 0xAE, 0x13, 0x0D, 0x96, 0x9D, 0xDD, 0xF3, 0x99 } }, // 1.16.0.0.40011 Halloween 2017
{ 0xB8DE51690075435AULL, { 0xC0, 0x7E, 0x92, 0x60, 0xBB, 0x71, 0x12, 0x17, 0xE7, 0xDE, 0x6F, 0xED, 0x91, 0x1F, 0x42, 0x96 } }, // 1.16.0.0.????? Winston Blizzcon 2017 skin
{ 0xF6CF23955B5D437DULL, { 0xAE, 0xBA, 0x22, 0x73, 0x28, 0xA5, 0xB0, 0xAA, 0x9F, 0x51, 0xDA, 0xE3, 0xF6, 0xA7, 0xDF, 0xE4 } }, // 1.17.0.2.41350 Moira
// Streamed WoW keys
{ 0xFA505078126ACB3EULL, { 0xBD, 0xC5, 0x18, 0x62, 0xAB, 0xED, 0x79, 0xB2, 0xDE, 0x48, 0xC8, 0xE7, 0xE6, 0x6C, 0x62, 0x00 } }, // 15 WOW-20740patch7.0.1_Beta
{ 0xFF813F7D062AC0BCULL, { 0xAA, 0x0B, 0x5C, 0x77, 0xF0, 0x88, 0xCC, 0xC2, 0xD3, 0x90, 0x49, 0xBD, 0x26, 0x7F, 0x06, 0x6D } }, // 25 WOW-20740patch7.0.1_Beta
{ 0xD1E9B5EDF9283668ULL, { 0x8E, 0x4A, 0x25, 0x79, 0x89, 0x4E, 0x38, 0xB4, 0xAB, 0x90, 0x58, 0xBA, 0x5C, 0x73, 0x28, 0xEE } }, // 39 WOW-20740patch7.0.1_Beta Enchanted Torch pet
{ 0xB76729641141CB34ULL, { 0x98, 0x49, 0xD1, 0xAA, 0x7B, 0x1F, 0xD0, 0x98, 0x19, 0xC5, 0xC6, 0x62, 0x83, 0xA3, 0x26, 0xEC } }, // 40 WOW-20740patch7.0.1_Beta Enchanted Pen pet
{ 0xFFB9469FF16E6BF8ULL, { 0xD5, 0x14, 0xBD, 0x19, 0x09, 0xA9, 0xE5, 0xDC, 0x87, 0x03, 0xF4, 0xB8, 0xBB, 0x1D, 0xFD, 0x9A } }, // 41 WOW-20740patch7.0.1_Beta
{ 0x23C5B5DF837A226CULL, { 0x14, 0x06, 0xE2, 0xD8, 0x73, 0xB6, 0xFC, 0x99, 0x21, 0x7A, 0x18, 0x08, 0x81, 0xDA, 0x8D, 0x62 } }, // 42 WOW-20740patch7.0.1_Beta Enchanted Cauldron pet
// {0x3AE403EF40AC3037ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??}}, // 51 WOW-21249patch7.0.3_Beta
{ 0xE2854509C471C554ULL, { 0x43, 0x32, 0x65, 0xF0, 0xCD, 0xEB, 0x2F, 0x4E, 0x65, 0xC0, 0xEE, 0x70, 0x08, 0x71, 0x4D, 0x9E } }, // 52 WOW-21249patch7.0.3_Beta Warcraft movie items
{ 0x8EE2CB82178C995AULL, { 0xDA, 0x6A, 0xFC, 0x98, 0x9E, 0xD6, 0xCA, 0xD2, 0x79, 0x88, 0x59, 0x92, 0xC0, 0x37, 0xA8, 0xEE } }, // 55 WOW-21531patch7.0.3_Beta BlizzCon 2016 Murlocs
{ 0x5813810F4EC9B005ULL, { 0x01, 0xBE, 0x8B, 0x43, 0x14, 0x2D, 0xD9, 0x9A, 0x9E, 0x69, 0x0F, 0xAD, 0x28, 0x8B, 0x60, 0x82 } }, // 56 WOW-21531patch7.0.3_Beta Fel Kitten
{ 0x7F9E217166ED43EAULL, { 0x05, 0xFC, 0x92, 0x7B, 0x9F, 0x4F, 0x5B, 0x05, 0x56, 0x81, 0x42, 0x91, 0x2A, 0x05, 0x2B, 0x0F } }, // 57 WOW-21531patch7.0.3_Beta Legion music
{ 0xC4A8D364D23793F7ULL, { 0xD1, 0xAC, 0x20, 0xFD, 0x14, 0x95, 0x7F, 0xAB, 0xC2, 0x71, 0x96, 0xE9, 0xF6, 0xE7, 0x02, 0x4A } }, // 58 WOW-21691patch7.0.3_Beta Demon Hunter #1 cinematic (legion_dh1)
{ 0x40A234AEBCF2C6E5ULL, { 0xC6, 0xC5, 0xF6, 0xC7, 0xF7, 0x35, 0xD7, 0xD9, 0x4C, 0x87, 0x26, 0x7F, 0xA4, 0x99, 0x4D, 0x45 } }, // 59 WOW-21691patch7.0.3_Beta Demon Hunter #2 cinematic (legion_dh2)
{ 0x9CF7DFCFCBCE4AE5ULL, { 0x72, 0xA9, 0x7A, 0x24, 0xA9, 0x98, 0xE3, 0xA5, 0x50, 0x0F, 0x38, 0x71, 0xF3, 0x76, 0x28, 0xC0 } }, // 60 WOW-21691patch7.0.3_Beta Val'sharah #1 cinematic (legion_val_yd)
{ 0x4E4BDECAB8485B4FULL, { 0x38, 0x32, 0xD7, 0xC4, 0x2A, 0xAC, 0x92, 0x68, 0xF0, 0x0B, 0xE7, 0xB6, 0xB4, 0x8E, 0xC9, 0xAF } }, // 61 WOW-21691patch7.0.3_Beta Val'sharah #2 cinematic (legion_val_yx)
{ 0x94A50AC54EFF70E4ULL, { 0xC2, 0x50, 0x1A, 0x72, 0x65, 0x4B, 0x96, 0xF8, 0x63, 0x50, 0xC5, 0xA9, 0x27, 0x96, 0x2F, 0x7A } }, // 62 WOW-21691patch7.0.3_Beta Sylvanas warchief cinematic (legion_org_vs)
{ 0xBA973B0E01DE1C2CULL, { 0xD8, 0x3B, 0xBC, 0xB4, 0x6C, 0xC4, 0x38, 0xB1, 0x7A, 0x48, 0xE7, 0x6C, 0x4F, 0x56, 0x54, 0xA3 } }, // 63 WOW-21691patch7.0.3_Beta Stormheim Sylvanas vs Greymane cinematic (legion_sth)
{ 0x494A6F8E8E108BEFULL, { 0xF0, 0xFD, 0xE1, 0xD2, 0x9B, 0x27, 0x4F, 0x6E, 0x7D, 0xBD, 0xB7, 0xFF, 0x81, 0x5F, 0xE9, 0x10 } }, // 64 WOW-21691patch7.0.3_Beta Harbingers Gul'dan video (legion_hrb_g)
{ 0x918D6DD0C3849002ULL, { 0x85, 0x70, 0x90, 0xD9, 0x26, 0xBB, 0x28, 0xAE, 0xDA, 0x4B, 0xF0, 0x28, 0xCA, 0xCC, 0x4B, 0xA3 } }, // 65 WOW-21691patch7.0.3_Beta Harbingers Khadgar video (legion_hrb_k)
{ 0x0B5F6957915ADDCAULL, { 0x4D, 0xD0, 0xDC, 0x82, 0xB1, 0x01, 0xC8, 0x0A, 0xBA, 0xC0, 0xA4, 0xD5, 0x7E, 0x67, 0xF8, 0x59 } }, // 66 WOW-21691patch7.0.3_Beta Harbingers Illidan video (legion_hrb_i)
{ 0x794F25C6CD8AB62BULL, { 0x76, 0x58, 0x3B, 0xDA, 0xCD, 0x52, 0x57, 0xA3, 0xF7, 0x3D, 0x15, 0x98, 0xA2, 0xCA, 0x2D, 0x99 } }, // 67 WOW-21846patch7.0.3_Beta Suramar cinematic (legion_su_i)
{ 0xA9633A54C1673D21ULL, { 0x1F, 0x8D, 0x46, 0x7F, 0x5D, 0x6D, 0x41, 0x1F, 0x8A, 0x54, 0x8B, 0x63, 0x29, 0xA5, 0x08, 0x7E } }, // 68 WOW-21846patch7.0.3_Beta legion_su_r cinematic
{ 0x5E5D896B3E163DEAULL, { 0x8A, 0xCE, 0x8D, 0xB1, 0x69, 0xE2, 0xF9, 0x8A, 0xC3, 0x6A, 0xD5, 0x2C, 0x08, 0x8E, 0x77, 0xC1 } }, // 69 WOW-21846patch7.0.3_Beta Broken Shore intro cinematic (legion_bs_i)
{ 0x0EBE36B5010DFD7FULL, { 0x9A, 0x89, 0xCC, 0x7E, 0x3A, 0xCB, 0x29, 0xCF, 0x14, 0xC6, 0x0B, 0xC1, 0x3B, 0x1E, 0x46, 0x16 } }, // 70 WOW-21846patch7.0.3_Beta Alliance Broken Shore cinematic (legion_bs_a)
{ 0x01E828CFFA450C0FULL, { 0x97, 0x2B, 0x6E, 0x74, 0x42, 0x0E, 0xC5, 0x19, 0xE6, 0xF9, 0xD9, 0x7D, 0x59, 0x4A, 0xA3, 0x7C } }, // 71 WOW-21846patch7.0.3_Beta Horde Broken Shore cinematic (legion_bs_h)
{ 0x4A7BD170FE18E6AEULL, { 0xAB, 0x55, 0xAE, 0x1B, 0xF0, 0xC7, 0xC5, 0x19, 0xAF, 0xF0, 0x28, 0xC1, 0x56, 0x10, 0xA4, 0x5B } }, // 72 WOW-21846patch7.0.3_Beta Khadgar & Light's Heart cinematic (legion_iq_lv)
{ 0x69549CB975E87C4FULL, { 0x7B, 0x6F, 0xA3, 0x82, 0xE1, 0xFA, 0xD1, 0x46, 0x5C, 0x85, 0x1E, 0x3F, 0x47, 0x34, 0xA1, 0xB3 } }, // 73 WOW-21846patch7.0.3_Beta legion_iq_id cinematic
{ 0x460C92C372B2A166ULL, { 0x94, 0x6D, 0x56, 0x59, 0xF2, 0xFA, 0xF3, 0x27, 0xC0, 0xB7, 0xEC, 0x82, 0x8B, 0x74, 0x8A, 0xDB } }, // 74 WOW-21952patch7.0.3_Beta Stormheim Alliance cinematic (legion_g_a_sth)
{ 0x8165D801CCA11962ULL, { 0xCD, 0x0C, 0x0F, 0xFA, 0xAD, 0x93, 0x63, 0xEC, 0x14, 0xDD, 0x25, 0xEC, 0xDD, 0x2A, 0x5B, 0x62 } }, // 75 WOW-21952patch7.0.3_Beta Stormheim Horde cinematic (legion_g_h_sth)
{ 0xA3F1C999090ADAC9ULL, { 0xB7, 0x2F, 0xEF, 0x4A, 0x01, 0x48, 0x8A, 0x88, 0xFF, 0x02, 0x28, 0x0A, 0xA0, 0x7A, 0x92, 0xBB } }, // 81 WOW-22578patch7.1.0_PTR Firecat Mount
// {0x18AFDF5191923610ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 82 WOW-22578patch7.1.0_PTR
// {0x3C258426058FBD93ULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 91 WOW-23436patch7.2.0_PTR
{ 0x094E9A0474876B98ULL, { 0xE5, 0x33, 0xBB, 0x6D, 0x65, 0x72, 0x7A, 0x58, 0x32, 0x68, 0x0D, 0x62, 0x0B, 0x0B, 0xC1, 0x0B } }, // 92 WOW-23910patch7.2.5_PTR
{ 0x3DB25CB86A40335EULL, { 0x02, 0x99, 0x0B, 0x12, 0x26, 0x0C, 0x1E, 0x9F, 0xDD, 0x73, 0xFE, 0x47, 0xCB, 0xAB, 0x70, 0x24 } }, // 93 WOW-23789patch7.2.0_PTR
{ 0x0DCD81945F4B4686ULL, { 0x1B, 0x78, 0x9B, 0x87, 0xFB, 0x3C, 0x92, 0x38, 0xD5, 0x28, 0x99, 0x7B, 0xFA, 0xB4, 0x41, 0x86 } }, // 94 WOW-23789patch7.2.0_PTR
{ 0x486A2A3A2803BE89ULL, { 0x32, 0x67, 0x9E, 0xA7, 0xB0, 0xF9, 0x9E, 0xBF, 0x4F, 0xA1, 0x70, 0xE8, 0x47, 0xEA, 0x43, 0x9A } }, // 95 WOW-23789patch7.2.0_PTR
{ 0x71F69446AD848E06ULL, { 0xE7, 0x9A, 0xEB, 0x88, 0xB1, 0x50, 0x9F, 0x62, 0x8F, 0x38, 0x20, 0x82, 0x01, 0x74, 0x1C, 0x30 } }, // 97 WOW-24473patch7.3.0_PTR BlizzCon 2017 Mounts (AllianceShipMount and HordeZeppelinMount)
{ 0x211FCD1265A928E9ULL, { 0xA7, 0x36, 0xFB, 0xF5, 0x8D, 0x58, 0x7B, 0x39, 0x72, 0xCE, 0x15, 0x4A, 0x86, 0xAE, 0x45, 0x40 } }, // 98 WOW-24473patch7.3.0_PTR "Shadow" fox pet (store)
{ 0x0ADC9E327E42E98CULL, { 0x01, 0x7B, 0x34, 0x72, 0xC1, 0xDE, 0xE3, 0x04, 0xFA, 0x0B, 0x2F, 0xF8, 0xE5, 0x3F, 0xF7, 0xD6 } }, // 99 WOW-23910patch7.2.5_PTR
{ 0xBAE9F621B60174F1ULL, { 0x38, 0xC3, 0xFB, 0x39, 0xB4, 0x97, 0x17, 0x60, 0xB4, 0xB9, 0x82, 0xFE, 0x9F, 0x09, 0x50, 0x14 } }, // 100 WOW-24473patch7.3.0_PTR Rejection of the Gift cinematic (legion_73_agi)
{ 0x34DE1EEADC97115EULL, { 0x2E, 0x3A, 0x53, 0xD5, 0x9A, 0x49, 0x1E, 0x5C, 0xD1, 0x73, 0xF3, 0x37, 0xF7, 0xCD, 0x8C, 0x61 } }, // 101 WOW-24473patch7.3.0_PTR Resurrection of Alleria Windrunner cinematic (legion_73_avt)
// { 0xE07E107F1390A3DFULL, {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 102 WOW-25079patch7.3.2_PTR Tottle battle pet, Raptor mount, Horse mount (104 files)
{ 0x32690BF74DE12530ULL, { 0xA2, 0x55, 0x62, 0x10, 0xAE, 0x54, 0x22, 0xE6, 0xD6, 0x1E, 0xDA, 0xAF, 0x12, 0x2C, 0xB6, 0x37 } }, // 103 WOW-24781patch7.3.0_PTR legion_73_pan
{ 0xBF3734B1DCB04696ULL, { 0x48, 0x94, 0x61, 0x23, 0x05, 0x0B, 0x00, 0xA7, 0xEF, 0xB1, 0xC0, 0x29, 0xEE, 0x6C, 0xC4, 0x38 } }, // 104 WOW-25079patch7.3.2_PTR legion_73_afn
{ 0x74F4F78002A5A1BEULL, { 0xC1, 0x4E, 0xEC, 0x8D, 0x5A, 0xEE, 0xF9, 0x3F, 0xA8, 0x11, 0xD4, 0x50, 0xB4, 0xE4, 0x6E, 0x91 } }, // 105 WOW-25079patch7.3.2_PTR SilithusPhase01 map
// { 0x423F07656CA27D23ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // WOW-25600patch7.3.5_PTR
// { 0x0691678F83E8A75DULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // WOW-25600patch7.3.5_PTR
// { 0xC02C78F40BEF5998ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // WOW-25600patch7.3.5_PTR
// { 0x324498590F550556ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // WOW-25600patch7.3.5_PTR
// { 0x8E00C6F405873583ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // WOW-25600patch7.3.5_PTR
// { 0x78482170E4CFD4A6ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // WOW-25600patch7.3.5_PTR
// { 0xB1EB52A64BFAF7BFULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // WOW-25600patch7.3.5_PTR
{ 0, { 0 } }
};
static const char * szKeyConstant16 = "expand 16-byte k";
static const char * szKeyConstant32 = "expand 32-byte k";
//-----------------------------------------------------------------------------
// Local functions
static DWORD Rol32(DWORD dwValue, DWORD dwRolCount)
{
return (dwValue << dwRolCount) | (dwValue >> (32 - dwRolCount));
}
static LPBYTE FindCascKey(ULONGLONG KeyName)
{
// Search the known keys
for(size_t i = 0; CascKeys[i].KeyName != 0; i++)
{
if(CascKeys[i].KeyName == KeyName)
return CascKeys[i].Key;
}
// Key not found
return NULL;
}
static void Initialize(PCASC_SALSA20 pState, LPBYTE pbKey, DWORD cbKeyLength, LPBYTE pbVector)
{
const char * szConstants = (cbKeyLength == 32) ? szKeyConstant32 : szKeyConstant16;
DWORD KeyIndex = cbKeyLength - 0x10;
memset(pState, 0, sizeof(CASC_SALSA20));
pState->Key[0] = *(PDWORD)(szConstants + 0x00);
pState->Key[1] = *(PDWORD)(pbKey + 0x00);
pState->Key[2] = *(PDWORD)(pbKey + 0x04);
pState->Key[3] = *(PDWORD)(pbKey + 0x08);
pState->Key[4] = *(PDWORD)(pbKey + 0x0C);
pState->Key[5] = *(PDWORD)(szConstants + 0x04);
pState->Key[6] = *(PDWORD)(pbVector + 0x00);
pState->Key[7] = *(PDWORD)(pbVector + 0x04);
pState->Key[8] = 0;
pState->Key[9] = 0;
pState->Key[10] = *(PDWORD)(szConstants + 0x08);
pState->Key[11] = *(PDWORD)(pbKey + KeyIndex + 0x00);
pState->Key[12] = *(PDWORD)(pbKey + KeyIndex + 0x04);
pState->Key[13] = *(PDWORD)(pbKey + KeyIndex + 0x08);
pState->Key[14] = *(PDWORD)(pbKey + KeyIndex + 0x0C);
pState->Key[15] = *(PDWORD)(szConstants + 0x0C);
pState->dwRounds = 20;
}
static int Decrypt(PCASC_SALSA20 pState, LPBYTE pbOutBuffer, LPBYTE pbInBuffer, size_t cbInBuffer)
{
LPBYTE pbXorValue;
DWORD KeyMirror[0x10];
DWORD XorValue[0x10];
DWORD BlockSize;
DWORD i;
// Repeat until we have data to read
while(cbInBuffer > 0)
{
// Create the copy of the key
memcpy(KeyMirror, pState->Key, sizeof(KeyMirror));
// Shuffle the key
for(i = 0; i < pState->dwRounds; i += 2)
{
KeyMirror[0x04] ^= Rol32((KeyMirror[0x00] + KeyMirror[0x0C]), 0x07);
KeyMirror[0x08] ^= Rol32((KeyMirror[0x04] + KeyMirror[0x00]), 0x09);
KeyMirror[0x0C] ^= Rol32((KeyMirror[0x08] + KeyMirror[0x04]), 0x0D);
KeyMirror[0x00] ^= Rol32((KeyMirror[0x0C] + KeyMirror[0x08]), 0x12);
KeyMirror[0x09] ^= Rol32((KeyMirror[0x05] + KeyMirror[0x01]), 0x07);
KeyMirror[0x0D] ^= Rol32((KeyMirror[0x09] + KeyMirror[0x05]), 0x09);
KeyMirror[0x01] ^= Rol32((KeyMirror[0x0D] + KeyMirror[0x09]), 0x0D);
KeyMirror[0x05] ^= Rol32((KeyMirror[0x01] + KeyMirror[0x0D]), 0x12);
KeyMirror[0x0E] ^= Rol32((KeyMirror[0x0A] + KeyMirror[0x06]), 0x07);
KeyMirror[0x02] ^= Rol32((KeyMirror[0x0E] + KeyMirror[0x0A]), 0x09);
KeyMirror[0x06] ^= Rol32((KeyMirror[0x02] + KeyMirror[0x0E]), 0x0D);
KeyMirror[0x0A] ^= Rol32((KeyMirror[0x06] + KeyMirror[0x02]), 0x12);
KeyMirror[0x03] ^= Rol32((KeyMirror[0x0F] + KeyMirror[0x0B]), 0x07);
KeyMirror[0x07] ^= Rol32((KeyMirror[0x03] + KeyMirror[0x0F]), 0x09);
KeyMirror[0x0B] ^= Rol32((KeyMirror[0x07] + KeyMirror[0x03]), 0x0D);
KeyMirror[0x0F] ^= Rol32((KeyMirror[0x0B] + KeyMirror[0x07]), 0x12);
KeyMirror[0x01] ^= Rol32((KeyMirror[0x00] + KeyMirror[0x03]), 0x07);
KeyMirror[0x02] ^= Rol32((KeyMirror[0x01] + KeyMirror[0x00]), 0x09);
KeyMirror[0x03] ^= Rol32((KeyMirror[0x02] + KeyMirror[0x01]), 0x0D);
KeyMirror[0x00] ^= Rol32((KeyMirror[0x03] + KeyMirror[0x02]), 0x12);
KeyMirror[0x06] ^= Rol32((KeyMirror[0x05] + KeyMirror[0x04]), 0x07);
KeyMirror[0x07] ^= Rol32((KeyMirror[0x06] + KeyMirror[0x05]), 0x09);
KeyMirror[0x04] ^= Rol32((KeyMirror[0x07] + KeyMirror[0x06]), 0x0D);
KeyMirror[0x05] ^= Rol32((KeyMirror[0x04] + KeyMirror[0x07]), 0x12);
KeyMirror[0x0B] ^= Rol32((KeyMirror[0x0A] + KeyMirror[0x09]), 0x07);
KeyMirror[0x08] ^= Rol32((KeyMirror[0x0B] + KeyMirror[0x0A]), 0x09);
KeyMirror[0x09] ^= Rol32((KeyMirror[0x08] + KeyMirror[0x0B]), 0x0D);
KeyMirror[0x0A] ^= Rol32((KeyMirror[0x09] + KeyMirror[0x08]), 0x12);
KeyMirror[0x0C] ^= Rol32((KeyMirror[0x0F] + KeyMirror[0x0E]), 0x07);
KeyMirror[0x0D] ^= Rol32((KeyMirror[0x0C] + KeyMirror[0x0F]), 0x09);
KeyMirror[0x0E] ^= Rol32((KeyMirror[0x0D] + KeyMirror[0x0C]), 0x0D);
KeyMirror[0x0F] ^= Rol32((KeyMirror[0x0E] + KeyMirror[0x0D]), 0x12);
}
// Set the number of remaining bytes
pbXorValue = (LPBYTE)XorValue;
BlockSize = (DWORD)CASCLIB_MIN(cbInBuffer, 0x40);
// Prepare the XOR constants
for(i = 0; i < 16; i++)
{
XorValue[i] = KeyMirror[i] + pState->Key[i];
}
// Decrypt the block
for(i = 0; i < BlockSize; i++)
{
pbOutBuffer[i] = pbInBuffer[i] ^ pbXorValue[i];
}
pState->Key[8] = pState->Key[8] + 1;
if(pState->Key[8] == 0)
pState->Key[9] = pState->Key[9] + 1;
// Adjust buffers
pbOutBuffer += BlockSize;
pbInBuffer += BlockSize;
cbInBuffer -= BlockSize;
}
return ERROR_SUCCESS;
}
static int Decrypt_Salsa20(LPBYTE pbOutBuffer, LPBYTE pbInBuffer, size_t cbInBuffer, LPBYTE pbKey, DWORD cbKeySize, LPBYTE pbVector)
{
CASC_SALSA20 SalsaState;
Initialize(&SalsaState, pbKey, cbKeySize, pbVector);
return Decrypt(&SalsaState, pbOutBuffer, pbInBuffer, cbInBuffer);
}
//-----------------------------------------------------------------------------
// Public functions
int CascDecrypt(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer, DWORD dwFrameIndex)
{
ULONGLONG KeyName = 0;
LPBYTE pbBufferEnd = pbInBuffer + cbInBuffer;
LPBYTE pbKey;
DWORD KeyNameSize;
DWORD dwShift = 0;
DWORD IVSize;
BYTE Vector[0x08];
BYTE EncryptionType;
int nError;
// Verify and retrieve the key name size
if(pbInBuffer >= pbBufferEnd)
return ERROR_FILE_CORRUPT;
if(pbInBuffer[0] != 0 && pbInBuffer[0] != 8)
return ERROR_NOT_SUPPORTED;
KeyNameSize = *pbInBuffer++;
// Copy the key name
if((pbInBuffer + KeyNameSize) >= pbBufferEnd)
return ERROR_FILE_CORRUPT;
memcpy(&KeyName, pbInBuffer, KeyNameSize);
pbInBuffer += KeyNameSize;
// Verify and retrieve the Vector size
if(pbInBuffer >= pbBufferEnd)
return ERROR_FILE_CORRUPT;
if(pbInBuffer[0] != 4 && pbInBuffer[0] != 8)
return ERROR_NOT_SUPPORTED;
IVSize = *pbInBuffer++;
// Copy the initialization vector
if((pbInBuffer + IVSize) >= pbBufferEnd)
return ERROR_FILE_CORRUPT;
memset(Vector, 0, sizeof(Vector));
memcpy(Vector, pbInBuffer, IVSize);
pbInBuffer += IVSize;
// Verify and retrieve the encryption type
if(pbInBuffer >= pbBufferEnd)
return ERROR_FILE_CORRUPT;
if(pbInBuffer[0] != 'S' && pbInBuffer[0] != 'A')
return ERROR_NOT_SUPPORTED;
EncryptionType = *pbInBuffer++;
// Do we have enough space in the output buffer?
if((DWORD)(pbBufferEnd - pbInBuffer) > pcbOutBuffer[0])
return ERROR_INSUFFICIENT_BUFFER;
// Check if we know the key
pbKey = FindCascKey(KeyName);
if(pbKey == NULL)
return ERROR_FILE_ENCRYPTED;
// Shuffle the Vector with the block index
// Note that there's no point to go beyond 32 bits, unless the file has
// more than 0xFFFFFFFF frames.
for(int i = 0; i < sizeof(dwFrameIndex); i++)
{
Vector[i] = Vector[i] ^ (BYTE)((dwFrameIndex >> dwShift) & 0xFF);
dwShift += 8;
}
// Perform the decryption-specific action
switch(EncryptionType)
{
case 'S': // Salsa20
nError = Decrypt_Salsa20(pbOutBuffer, pbInBuffer, (pbBufferEnd - pbInBuffer), pbKey, 0x10, Vector);
if(nError != ERROR_SUCCESS)
return nError;
// Supply the size of the output buffer
pcbOutBuffer[0] = (DWORD)(pbBufferEnd - pbInBuffer);
return ERROR_SUCCESS;
// case 'A':
// return ERROR_NOT_SUPPORTED;
}
assert(false);
return ERROR_NOT_SUPPORTED;
}
int CascDirectCopy(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer)
{
// Check the buffer size
if((cbInBuffer - 1) > pcbOutBuffer[0])
return ERROR_INSUFFICIENT_BUFFER;
// Copy the data
memcpy(pbOutBuffer, pbInBuffer, cbInBuffer);
pcbOutBuffer[0] = cbInBuffer;
return ERROR_SUCCESS;
}

View File

@@ -0,0 +1,335 @@
/*****************************************************************************/
/* CascDumpData.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* System-dependent directory functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 07.05.14 1.00 Lad The first version of CascDumpData.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
#include "CascMndx.h"
#ifdef _DEBUG // The entire feature is only valid for debug purposes
//-----------------------------------------------------------------------------
// Forward definitions
//LPBYTE VerifyLocaleBlock(PROOT_BLOCK_INFO pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd);
//-----------------------------------------------------------------------------
// Sort compare functions
static int CompareIndexEntries_FilePos(const void *, const void * pvIndexEntry1, const void * pvIndexEntry2)
{
PCASC_INDEX_ENTRY pIndexEntry1 = (PCASC_INDEX_ENTRY)pvIndexEntry1;
PCASC_INDEX_ENTRY pIndexEntry2 = (PCASC_INDEX_ENTRY)pvIndexEntry2;
ULONGLONG FileOffset1 = ConvertBytesToInteger_5(pIndexEntry1->FileOffsetBE);
ULONGLONG FileOffset2 = ConvertBytesToInteger_5(pIndexEntry2->FileOffsetBE);
DWORD ArchIndex1 = (DWORD)(FileOffset1 >> 0x1E);
DWORD ArchIndex2 = (DWORD)(FileOffset2 >> 0x1E);
// First, compare the archive index
if(ArchIndex1 < ArchIndex2)
return -1;
if(ArchIndex1 > ArchIndex2)
return +1;
// Second, compare the archive offset
FileOffset1 &= 0x3FFFFFFF;
FileOffset2 &= 0x3FFFFFFF;
if(FileOffset1 < FileOffset2)
return -1;
if(FileOffset1 > FileOffset2)
return +1;
return 0;
}
//-----------------------------------------------------------------------------
// Public functions
void CascDumpSparseArray(const char * szFileName, void * pvSparseArray)
{
TSparseArray * pSparseArray = (TSparseArray *)pvSparseArray;
FILE * fp;
// Create the dump file
fp = fopen(szFileName, "wt");
if(fp != NULL)
{
// Write header
fprintf(fp, "## Value\n-- -----\n");
// Write the values
for(DWORD i = 0; i < pSparseArray->TotalItemCount; i++)
{
DWORD Value = 0;
if(pSparseArray->IsItemPresent(i))
{
Value = pSparseArray->GetItemValue(i);
fprintf(fp, "%02X %02X\n", i, Value);
}
else
{
fprintf(fp, "%02X --\n", i);
}
}
fclose(fp);
}
}
void CascDumpNameFragTable(const char * szFileName, void * pMarFile)
{
TFileNameDatabase * pDB = ((PMAR_FILE)pMarFile)->pDatabasePtr->pDB;
FILE * fp;
// Create the dump file
fp = fopen(szFileName, "wt");
if(fp != NULL)
{
PNAME_FRAG pNameTable = pDB->NameFragTable.NameFragArray;
const char * szNames = pDB->IndexStruct_174.NameFragments.CharArray;
const char * szLastEntry;
char szMatchType[0x100];
// Dump the table header
fprintf(fp, "Indx ThisHash NextHash FragOffs\n");
fprintf(fp, "---- -------- -------- --------\n");
// Dump all name entries
for(DWORD i = 0; i < pDB->NameFragTable.ItemCount; i++)
{
// Reset both match types
szMatchType[0] = 0;
szLastEntry = "";
// Only if the table entry is not empty
if(pNameTable->ItemIndex != 0xFFFFFFFF)
{
// Prepare the entry
if(IS_SINGLE_CHAR_MATCH(pDB->NameFragTable, i))
sprintf(szMatchType, "SINGLE_CHAR (\'%c\')", (pNameTable->FragOffs & 0xFF));
else
sprintf(szMatchType, "NAME_FRAGMT (\"%s\")", szNames + pNameTable->FragOffs);
}
// Dump the entry
fprintf(fp, "0x%02X %08x %08x %08x %s%s\n", i, pNameTable->ItemIndex,
pNameTable->NextIndex,
pNameTable->FragOffs,
szMatchType,
szLastEntry);
pNameTable++;
}
fclose(fp);
}
}
void CascDumpFileNames(const char * szFileName, void * pvMarFile)
{
TMndxFindResult Struct1C;
PMAR_FILE pMarFile = (PMAR_FILE)pvMarFile;
FILE * fp;
char szNameBuff[0x200];
bool bFindResult;
// Create the dump file
fp = fopen(szFileName, "wt");
if(fp != NULL)
{
// Set an empty path as search mask (?)
Struct1C.SetSearchPath("", 0);
// Keep searching
for(;;)
{
// Search the next file name
pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C, &bFindResult);
// Stop the search in case of failure
if(!bFindResult)
break;
// Printf the found file name
memcpy(szNameBuff, Struct1C.szFoundPath, Struct1C.cchFoundPath);
szNameBuff[Struct1C.cchFoundPath] = 0;
fprintf(fp, "%s\n", szNameBuff);
}
fclose(fp);
}
// Free the search structures
Struct1C.FreeStruct40();
}
void CascDumpIndexEntry(
TCascStorage * /* hs */,
TDumpContext * dc,
PCASC_INDEX_ENTRY pIndexEntry,
int /* nDumpLevel */)
{
if(pIndexEntry != NULL)
{
ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE);
DWORD ArchIndex = (DWORD)(FileOffset >> 0x1E);
DWORD FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE);
// Mask the file offset
FileOffset &= 0x3FFFFFFF;
dump_print(dc, " data.%03u at 0x%08x (0x%lx bytes)\n",
ArchIndex,
(DWORD)FileOffset,
FileSize);
//if(nDumpLevel > 2)
//{
// QueryKey.pbData = pIndexEntry->IndexKey;
// QueryKey.cbData = MD5_HASH_SIZE;
// if(CascOpenFileByIndexKey((HANDLE)hs, &QueryKey, 0, &hFile))
// {
// // Make sure that the data file is open and frame header loaded
// CascGetFileSize(hFile, NULL);
// hf = IsValidFileHandle(hFile);
// assert(hf->pStream != NULL);
// // Read the header area
// FileOffset = hf->HeaderOffset - BLTE_HEADER_DELTA;
// FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea));
// CascCloseFile(hFile);
// // Dump the header area
// dump_print(dc, " FileSize: %X Rest: %s\n",
// ConvertBytesToInteger_4_LE(&HeaderArea[0x10]),
// StringFromBinary(&HeaderArea[0x14], 10, szBuffer));
// }
//}
}
else
{
dump_print(dc, " NO INDEX ENTRY\n");
}
}
void CascDumpEncodingEntry(
TCascStorage * hs,
TDumpContext * dc,
PCASC_ENCODING_ENTRY pEncodingEntry,
int nDumpLevel)
{
PCASC_INDEX_ENTRY pIndexEntry;
QUERY_KEY QueryKey;
LPBYTE pbIndexKey;
char szMd5[MD5_STRING_SIZE+1];
// If the encoding key exists
if(pEncodingEntry != NULL)
{
dump_print(dc, " Size %lx Key Count: %u\n",
ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE),
pEncodingEntry->KeyCount);
// Dump all index keys
pbIndexKey = pEncodingEntry->EncodingKey + MD5_HASH_SIZE;
for(DWORD j = 0; j < pEncodingEntry->KeyCount; j++, pbIndexKey += MD5_HASH_SIZE)
{
// Dump the index key
dump_print(dc, " %s\n", StringFromMD5(pbIndexKey, szMd5));
// Dump the index entry as well
if(nDumpLevel >= DUMP_LEVEL_INDEX_ENTRIES)
{
QueryKey.pbData = pbIndexKey;
QueryKey.cbData = MD5_HASH_SIZE;
pIndexEntry = FindIndexEntry(hs, &QueryKey);
CascDumpIndexEntry(hs, dc, pIndexEntry, nDumpLevel);
}
}
}
else
{
dump_print(dc, " NO ENCODING KEYS\n");
}
}
void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs)
{
PCASC_INDEX_ENTRY * ppIndexEntries;
FILE * fp;
size_t nIndexEntries = hs->pIndexEntryMap->ItemCount;
char szIndexKey[0x40];
// Create the dump file
fp = fopen(szFileName, "wt");
if(fp != NULL)
{
// Create linear aray
ppIndexEntries = CASC_ALLOC(PCASC_INDEX_ENTRY, nIndexEntries);
if(ppIndexEntries != NULL)
{
// Obtain the linear array of index entries
Map_EnumObjects(hs->pIndexEntryMap, (void **)ppIndexEntries);
// Sort the array by archive number and archive offset
qsort_pointer_array((void **)ppIndexEntries, nIndexEntries, CompareIndexEntries_FilePos, NULL);
// Parse the array
fprintf(fp, "ArNo ArOffset FileSize IndexKey\n==== ======== ======== ================================\n");
for(size_t i = 0; i < nIndexEntries; i++)
{
PCASC_INDEX_ENTRY pIndexEntry = ppIndexEntries[i];
ULONGLONG ArchOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE);
DWORD ArchIndex = (DWORD)(ArchOffset >> 0x1E);
DWORD FileSize;
FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE);
ArchOffset &= 0x3FFFFFFF;
fprintf(fp, " %02X %08X %08X %s\n", ArchIndex, (DWORD)ArchOffset, FileSize, StringFromBinary(pIndexEntry->IndexKey, CASC_FILE_KEY_SIZE, szIndexKey));
}
CASC_FREE(ppIndexEntries);
}
fclose(fp);
}
}
void CascDumpFile(const char * szFileName, HANDLE hFile)
{
FILE * fp;
DWORD dwBytesRead = 1;
DWORD dwFilePos = CascSetFilePointer(hFile, 0, NULL, FILE_BEGIN);
BYTE Buffer[0x1000];
// Create the dump file
fp = fopen(szFileName, "wb");
if(fp != NULL)
{
// Read data as long as we can, write as long as we can
while(dwBytesRead != 0)
{
// Read from the source file
if(!CascReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead))
break;
// Write to the destination file
if(fwrite(Buffer, 1, dwBytesRead, fp) != dwBytesRead)
break;
}
// Close the local file
fclose(fp);
// Restore the file pointer
CascSetFilePointer(hFile, dwFilePos, NULL, FILE_BEGIN);
}
}
#endif // _DEBUG

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,326 @@
/*****************************************************************************/
/* CascFindFile.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* System-dependent directory functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 10.05.14 1.00 Lad The first version of CascFindFile.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
//-----------------------------------------------------------------------------
// Local functions
static TCascSearch * IsValidSearchHandle(HANDLE hFind)
{
TCascSearch * pSearch = (TCascSearch *)hFind;
return (pSearch != NULL && pSearch->szClassName != NULL && !strcmp(pSearch->szClassName, "TCascSearch") && pSearch->szMask != NULL) ? pSearch : NULL;
}
static void FreeSearchHandle(TCascSearch * pSearch)
{
// Only if the storage handle is valid
assert(pSearch != NULL);
// Close (dereference) the archive handle
if(pSearch->hs != NULL)
{
// Give root handler chance to free their stuff
RootHandler_EndSearch(pSearch->hs->pRootHandler, pSearch);
// Dereference the storage handle
CascCloseStorage((HANDLE)pSearch->hs);
pSearch->hs = NULL;
}
// Free the file cache and frame array
if(pSearch->szMask != NULL)
CASC_FREE(pSearch->szMask);
if(pSearch->szListFile != NULL)
CASC_FREE(pSearch->szListFile);
// if(pSearch->pStruct1C != NULL)
// delete pSearch->pStruct1C;
if(pSearch->pCache != NULL)
ListFile_Free(pSearch->pCache);
// Free the structure itself
pSearch->szClassName = NULL;
CASC_FREE(pSearch);
}
static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szListFile, const char * szMask)
{
TCascSearch * pSearch;
size_t cbToAllocate;
// When using the MNDX info, do not allocate the extra bit array
cbToAllocate = sizeof(TCascSearch) + ((hs->pEncodingMap->TableSize + 7) / 8);
pSearch = (TCascSearch *)CASC_ALLOC(BYTE, cbToAllocate);
if(pSearch != NULL)
{
// Initialize the structure
memset(pSearch, 0, cbToAllocate);
pSearch->szClassName = "TCascSearch";
// Save the search handle
pSearch->hs = hs;
hs->dwRefCount++;
// If the mask was not given, use default
if(szMask == NULL)
szMask = "*";
// Save the other variables
if(szListFile != NULL)
{
pSearch->szListFile = CascNewStr(szListFile, 0);
if(pSearch->szListFile == NULL)
{
FreeSearchHandle(pSearch);
return NULL;
}
}
// Allocate the search mask
pSearch->szMask = CascNewStr(szMask, 0);
if(pSearch->szMask == NULL)
{
FreeSearchHandle(pSearch);
return NULL;
}
}
return pSearch;
}
// Perform searching using root-specific provider.
// The provider may need the listfile
static bool DoStorageSearch_RootFile(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)
{
PCASC_ENCODING_ENTRY pEncodingEntry;
PCASC_INDEX_ENTRY pIndexEntry;
QUERY_KEY EncodingKey;
QUERY_KEY IndexKey;
LPBYTE pbEncodingKey;
DWORD EncodingIndex = 0;
DWORD ByteIndex;
DWORD BitMask;
for(;;)
{
DWORD LocaleFlags = 0;
DWORD FileDataId = CASC_INVALID_ID;
DWORD FileSize = CASC_INVALID_SIZE;
// Attempt to find (the next) file from the root entry
pbEncodingKey = RootHandler_Search(pSearch->hs->pRootHandler, pSearch, &FileSize, &LocaleFlags, &FileDataId);
if(pbEncodingKey == NULL)
return false;
// Verify whether the encoding key exists in the encoding table
EncodingKey.pbData = pbEncodingKey;
EncodingKey.cbData = MD5_HASH_SIZE;
pEncodingEntry = FindEncodingEntry(pSearch->hs, &EncodingKey, &EncodingIndex);
if(pEncodingEntry != NULL)
{
// Mark the item as already found
// Note: Duplicate items are allowed while we are searching using file names
// Do not exclude items from search if they were found before
ByteIndex = (DWORD)(EncodingIndex / 8);
BitMask = 1 << (EncodingIndex & 0x07);
pSearch->BitArray[ByteIndex] |= BitMask;
// Locate the index entry
IndexKey.pbData = GET_INDEX_KEY(pEncodingEntry);
IndexKey.cbData = MD5_HASH_SIZE;
pIndexEntry = FindIndexEntry(pSearch->hs, &IndexKey);
if(pIndexEntry == NULL)
continue;
// If we retrieved the file size directly from the root provider, use it
// Otherwise, we need to retrieve it from the encoding entry
if(FileSize == CASC_INVALID_SIZE)
FileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE);
// Fill-in the found file
strcpy(pFindData->szFileName, pSearch->szFileName);
memcpy(pFindData->EncodingKey, pEncodingEntry->EncodingKey, MD5_HASH_SIZE);
pFindData->szPlainName = (char *)GetPlainFileName(pFindData->szFileName);
pFindData->dwLocaleFlags = LocaleFlags;
pFindData->dwFileDataId = FileDataId;
pFindData->dwFileSize = FileSize;
return true;
}
}
}
static bool DoStorageSearch_EncodingKey(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)
{
PCASC_ENCODING_ENTRY pEncodingEntry;
PCASC_INDEX_ENTRY pIndexEntry;
TCascStorage * hs = pSearch->hs;
QUERY_KEY IndexKey;
DWORD ByteIndex;
DWORD BitMask;
// Check for encoding keys that haven't been found yet
while(pSearch->IndexLevel1 < hs->pEncodingMap->TableSize)
{
// Check if that entry has been reported before
ByteIndex = (DWORD)(pSearch->IndexLevel1 / 8);
BitMask = 1 << (pSearch->IndexLevel1 & 0x07);
if((pSearch->BitArray[ByteIndex] & BitMask) == 0)
{
// Locate the index entry
pEncodingEntry = (PCASC_ENCODING_ENTRY)hs->pEncodingMap->HashTable[pSearch->IndexLevel1];
if(pEncodingEntry != NULL)
{
IndexKey.pbData = GET_INDEX_KEY(pEncodingEntry);
IndexKey.cbData = MD5_HASH_SIZE;
pIndexEntry = FindIndexEntry(pSearch->hs, &IndexKey);
if(pIndexEntry != NULL)
{
// Fill-in the found file
memcpy(pFindData->EncodingKey, pEncodingEntry->EncodingKey, MD5_HASH_SIZE);
pFindData->szFileName[0] = 0;
pFindData->szPlainName = pFindData->szFileName;
pFindData->dwLocaleFlags = CASC_LOCALE_NONE;
pFindData->dwFileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE);
// Mark the entry as already-found
pSearch->BitArray[ByteIndex] |= BitMask;
return true;
}
}
}
// Go to the next encoding entry
pSearch->IndexLevel1++;
}
// Nameless search ended
return false;
}
static bool DoStorageSearch(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)
{
// State 0: No search done yet
if(pSearch->dwState == 0)
{
// Does the search specify listfile?
if(pSearch->szListFile != NULL)
pSearch->pCache = ListFile_OpenExternal(pSearch->szListFile);
// Move the search phase to the listfile searching
pSearch->IndexLevel1 = 0;
pSearch->dwState++;
}
// State 1: Searching the list file
if(pSearch->dwState == 1)
{
if(DoStorageSearch_RootFile(pSearch, pFindData))
return true;
// Move to the nameless search state
pSearch->IndexLevel1 = 0;
pSearch->dwState++;
}
// State 2: Searching the remaining entries
if(pSearch->dwState == 2 && (pSearch->szMask == NULL || !strcmp(pSearch->szMask, "*")))
{
if(DoStorageSearch_EncodingKey(pSearch, pFindData))
return true;
// Move to the final search state
pSearch->dwState++;
}
return false;
}
//-----------------------------------------------------------------------------
// Public functions
HANDLE WINAPI CascFindFirstFile(
HANDLE hStorage,
const char * szMask,
PCASC_FIND_DATA pFindData,
const TCHAR * szListFile)
{
TCascStorage * hs;
TCascSearch * pSearch = NULL;
int nError = ERROR_SUCCESS;
// Check parameters
if((hs = IsValidStorageHandle(hStorage)) == NULL)
nError = ERROR_INVALID_HANDLE;
if(szMask == NULL || pFindData == NULL)
nError = ERROR_INVALID_PARAMETER;
// Init the search structure and search handle
if(nError == ERROR_SUCCESS)
{
// Clear the entire search structure
memset(pFindData, 0, sizeof(CASC_FIND_DATA));
// Allocate the search handle
pSearch = AllocateSearchHandle(hs, szListFile, szMask);
if(pSearch == NULL)
nError = ERROR_NOT_ENOUGH_MEMORY;
}
// Perform search
if(nError == ERROR_SUCCESS)
{
if(!DoStorageSearch(pSearch, pFindData))
nError = ERROR_NO_MORE_FILES;
}
if(nError != ERROR_SUCCESS)
{
if(pSearch != NULL)
FreeSearchHandle(pSearch);
pSearch = (TCascSearch *)INVALID_HANDLE_VALUE;
}
return (HANDLE)pSearch;
}
bool WINAPI CascFindNextFile(
HANDLE hFind,
PCASC_FIND_DATA pFindData)
{
TCascSearch * pSearch;
pSearch = IsValidSearchHandle(hFind);
if(pSearch == NULL || pFindData == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// Perform search
return DoStorageSearch(pSearch, pFindData);
}
bool WINAPI CascFindClose(HANDLE hFind)
{
TCascSearch * pSearch;
pSearch = IsValidSearchHandle(hFind);
if(pSearch == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
FreeSearchHandle(pSearch);
return true;
}

View File

@@ -0,0 +1,29 @@
;
; Export file for Windows
; Copyright (c) 2015 Ladislav Zezula
; ladik@zezula.net
;
LIBRARY CascLib.dll
EXPORTS
CascOpenStorage
CascGetStorageInfo
CascCloseStorage
CascOpenFileByIndexKey
CascOpenFileByEncodingKey
CascOpenFile
CascGetFileSize
CascSetFilePointer
CascReadFile
CascCloseFile
CascFindFirstFile
CascFindNextFile
CascFindClose
GetLastError=Kernel32.GetLastError
SetLastError=Kernel32.SetLastError

180
dep/CascLib/src/CascLib.h Normal file
View File

@@ -0,0 +1,180 @@
/*****************************************************************************/
/* CascLib.h Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* CascLib library v 1.00 */
/* */
/* Author : Ladislav Zezula */
/* E-mail : ladik@zezula.net */
/* WWW : http://www.zezula.net */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 29.04.14 1.00 Lad Created */
/*****************************************************************************/
#ifndef __CASCLIB_H__
#define __CASCLIB_H__
#ifdef _MSC_VER
#pragma warning(disable:4668) // 'XXX' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
#pragma warning(disable:4820) // 'XXX' : '2' bytes padding added after data member 'XXX::yyy'
#endif
#include "CascPort.h"
#ifdef __cplusplus
extern "C" {
#endif
//-----------------------------------------------------------------------------
// Defines
#define CASCLIB_VERSION 0x0100 // Current version of CascLib (1.0)
#define CASCLIB_VERSION_STRING "1.00" // String version of CascLib version
// Values for CascOpenStorage
#define CASC_STOR_XXXXX 0x00000001 // Not used
// Values for CascOpenFile
#define CASC_OPEN_BY_ENCODING_KEY 0x00000001 // The name is just the encoding key; skip ROOT file processing
#define CASC_LOCALE_ALL 0xFFFFFFFF
#define CASC_LOCALE_NONE 0x00000000
#define CASC_LOCALE_UNKNOWN1 0x00000001
#define CASC_LOCALE_ENUS 0x00000002
#define CASC_LOCALE_KOKR 0x00000004
#define CASC_LOCALE_RESERVED 0x00000008
#define CASC_LOCALE_FRFR 0x00000010
#define CASC_LOCALE_DEDE 0x00000020
#define CASC_LOCALE_ZHCN 0x00000040
#define CASC_LOCALE_ESES 0x00000080
#define CASC_LOCALE_ZHTW 0x00000100
#define CASC_LOCALE_ENGB 0x00000200
#define CASC_LOCALE_ENCN 0x00000400
#define CASC_LOCALE_ENTW 0x00000800
#define CASC_LOCALE_ESMX 0x00001000
#define CASC_LOCALE_RURU 0x00002000
#define CASC_LOCALE_PTBR 0x00004000
#define CASC_LOCALE_ITIT 0x00008000
#define CASC_LOCALE_PTPT 0x00010000
#define CASC_LOCALE_BIT_ENUS 0x01
#define CASC_LOCALE_BIT_KOKR 0x02
#define CASC_LOCALE_BIT_RESERVED 0x03
#define CASC_LOCALE_BIT_FRFR 0x04
#define CASC_LOCALE_BIT_DEDE 0x05
#define CASC_LOCALE_BIT_ZHCN 0x06
#define CASC_LOCALE_BIT_ESES 0x07
#define CASC_LOCALE_BIT_ZHTW 0x08
#define CASC_LOCALE_BIT_ENGB 0x09
#define CASC_LOCALE_BIT_ENCN 0x0A
#define CASC_LOCALE_BIT_ENTW 0x0B
#define CASC_LOCALE_BIT_ESMX 0x0C
#define CASC_LOCALE_BIT_RURU 0x0D
#define CASC_LOCALE_BIT_PTBR 0x0E
#define CASC_LOCALE_BIT_ITIT 0x0F
#define CASC_LOCALE_BIT_PTPT 0x10
#define MAX_CASC_KEY_LENGTH 0x10 // Maximum length of the key (equal to MD5 hash)
#ifndef MD5_HASH_SIZE
#define MD5_HASH_SIZE 0x10
#define MD5_STRING_SIZE 0x20
#endif
#ifndef SHA1_DIGEST_SIZE
#define SHA1_DIGEST_SIZE 0x14 // 160 bits
#endif
#ifndef LANG_NEUTRAL
#define LANG_NEUTRAL 0x00 // Neutral locale
#endif
// Return value for CascGetFileSize and CascSetFilePointer
#define CASC_INVALID_SIZE 0xFFFFFFFF
#define CASC_INVALID_POS 0xFFFFFFFF
#define CASC_INVALID_ID 0xFFFFFFFF
// Flags for CascGetStorageInfo
#define CASC_FEATURE_LISTFILE 0x00000001 // The storage supports listfile
//-----------------------------------------------------------------------------
// Structures
typedef enum _CASC_STORAGE_INFO_CLASS
{
CascStorageFileCount,
CascStorageFeatures,
CascStorageGameInfo,
CascStorageGameBuild,
CascStorageInstalledLocales,
CascStorageInfoClassMax
} CASC_STORAGE_INFO_CLASS, *PCASC_STORAGE_INFO_CLASS;
typedef struct _QUERY_KEY
{
LPBYTE pbData;
DWORD cbData;
} QUERY_KEY, *PQUERY_KEY;
// Structure for SFileFindFirstFile and SFileFindNextFile
typedef struct _CASC_FIND_DATA
{
char szFileName[MAX_PATH]; // Full name of the found file
char * szPlainName; // Plain name of the found file
BYTE EncodingKey[MD5_HASH_SIZE]; // Encoding key
DWORD dwLocaleFlags; // Locale flags (WoW only)
DWORD dwFileDataId; // File data ID (WoW only)
DWORD dwFileSize; // Size of the file
} CASC_FIND_DATA, *PCASC_FIND_DATA;
//-----------------------------------------------------------------------------
// Callback functions
typedef struct TFileStream TFileStream;
typedef void (WINAPI * STREAM_DOWNLOAD_CALLBACK)(void * pvUserData, ULONGLONG ByteOffset, DWORD dwTotalBytes);
//-----------------------------------------------------------------------------
// We have our own qsort implementation, optimized for sorting array of pointers
void qsort_pointer_array(void ** base, size_t num, int (*compare)(const void *, const void *, const void *), const void * context);
//-----------------------------------------------------------------------------
// Functions for storage manipulation
bool WINAPI CascOpenStorage(const TCHAR * szDataPath, DWORD dwLocaleMask, HANDLE * phStorage);
bool WINAPI CascGetStorageInfo(HANDLE hStorage, CASC_STORAGE_INFO_CLASS InfoClass, void * pvStorageInfo, size_t cbStorageInfo, size_t * pcbLengthNeeded);
bool WINAPI CascCloseStorage(HANDLE hStorage);
bool WINAPI CascOpenFileByIndexKey(HANDLE hStorage, PQUERY_KEY pIndexKey, DWORD dwFlags, HANDLE * phFile);
bool WINAPI CascOpenFileByEncodingKey(HANDLE hStorage, PQUERY_KEY pEncodingKey, DWORD dwFlags, HANDLE * phFile);
bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocale, DWORD dwFlags, HANDLE * phFile);
DWORD WINAPI CascGetFileSize(HANDLE hFile, PDWORD pdwFileSizeHigh);
DWORD WINAPI CascGetFileId(HANDLE hStorage, const char * szFileName);
DWORD WINAPI CascSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod);
bool WINAPI CascReadFile(HANDLE hFile, void * lpBuffer, DWORD dwToRead, PDWORD pdwRead);
bool WINAPI CascCloseFile(HANDLE hFile);
HANDLE WINAPI CascFindFirstFile(HANDLE hStorage, const char * szMask, PCASC_FIND_DATA pFindData, const TCHAR * szListFile);
bool WINAPI CascFindNextFile(HANDLE hFind, PCASC_FIND_DATA pFindData);
bool WINAPI CascFindClose(HANDLE hFind);
//-----------------------------------------------------------------------------
// GetLastError/SetLastError support for non-Windows platform
#ifndef PLATFORM_WINDOWS
int GetLastError();
void SetLastError(int nError);
#endif // PLATFORM_WINDOWS
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __CASCLIB_H__

359
dep/CascLib/src/CascMndx.h Normal file
View File

@@ -0,0 +1,359 @@
/*****************************************************************************/
/* CascMndxRoot.h Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* Interface file for MNDX structures */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 15.05.14 1.00 Lad Created */
/*****************************************************************************/
#ifndef __CASC_MNDX_ROOT__
#define __CASC_MNDX_ROOT__
class TFileNameDatabase;
#define CASC_MAX_MAR_FILES 3 // Maximum of 3 MAR files are supported
#define CASC_MNDX_SIGNATURE 0x58444E4D // 'MNDX'
#define CASC_MAX_ENTRIES(type) (0xFFFFFFFF / sizeof(type))
#define CASC_SEARCH_INITIALIZING 0
#define CASC_SEARCH_SEARCHING 2
#define CASC_SEARCH_FINISHED 4
typedef struct _TRIPLET
{
DWORD BaseValue;
DWORD Value2;
DWORD Value3;
} TRIPLET, *PTRIPLET;
typedef struct _NAME_FRAG
{
DWORD ItemIndex; // Back index to various tables
DWORD NextIndex; // The following item index
DWORD FragOffs; // Higher 24 bits are 0xFFFFFF00 --> A single matching character
// Otherwise --> Offset to the name fragment table
} NAME_FRAG, *PNAME_FRAG;
typedef struct _PATH_STOP
{
DWORD ItemIndex;
DWORD field_4;
DWORD field_8;
DWORD field_C;
DWORD field_10;
} PATH_STOP, *PPATH_STOP;
typedef union _ARRAY_POINTER
{
LPBYTE Bytes; // Pointer to an octet
char * Chars; // Pointer to a character
PDWORD Uint32s; // Pointer to a DWORD
PTRIPLET Triplets; // Pointer to TRIPLET
PNAME_FRAG NameFrags; // Pointer to name fragment entry
PPATH_STOP PathStopPtr; // Pointer to path checkpoint
PULONGLONG Int64Ptr; // Pointer to 64-bit integer
} ARRAY_POINTER, *PARRAY_POINTER;
// Simple access to various tables within TGenericArray
#define ByteArray ArrayPointer.Bytes
#define CharArray ArrayPointer.Chars
#define Uint32Array ArrayPointer.Uint32s
#define TripletArray ArrayPointer.Triplets
#define NameFragArray ArrayPointer.NameFrags
class TByteStream
{
public:
TByteStream();
void ExchangeWith(TByteStream & Target);
int GetBytes(DWORD cbByteCount, PARRAY_POINTER PtrArray);
int SkipBytes(DWORD cbByteCount);
int SetByteBuffer(LPBYTE pbNewMarData, DWORD cbNewMarData);
int GetValue_DWORD(DWORD & Value);
int GetValue_ItemCount(DWORD & NumberOfBytes, DWORD & ItemCount, DWORD ItemSize);
int GetArray_DWORDs(PARRAY_POINTER PtrArray, DWORD ItemCount);
int GetArray_Triplets(PARRAY_POINTER PtrArray, DWORD ItemCount);
int GetArray_NameTable(PARRAY_POINTER PtrArray, DWORD ItemCount);
int GetArray_BYTES(PARRAY_POINTER PtrArray, DWORD ItemCount);
LPBYTE pbByteData;
void * pvMappedFile;
DWORD cbByteData;
DWORD field_C;
HANDLE hFile;
HANDLE hMap;
};
class TGenericArray
{
public:
TGenericArray();
~TGenericArray();
int SetArrayValid();
void ExchangeWith(TGenericArray & Target);
void CopyFrom(TGenericArray & Source);
void SetMaxItems_CHARS(DWORD NewMaxItemCount);
void SetMaxItems_PATH_STOP(DWORD NewMaxItemCount);
void InsertOneItem_CHAR(char OneChar);
void InsertOneItem_PATH_STOP(PATH_STOP & NewItem);
void sub_19583A0(DWORD NewItemCount);
int LoadDwordsArray(TByteStream & InStream);
int LoadTripletsArray(TByteStream & InStream);
int LoadByteArray(TByteStream & InStream);
int LoadFragmentInfos(TByteStream & InStream);
int LoadStrings(TByteStream & InStream);
int LoadDwordsArray_Copy(TByteStream & InStream);
int LoadTripletsArray_Copy(TByteStream & InStream);
int LoadBytes_Copy(TByteStream & InStream);
int LoadFragmentInfos_Copy(TByteStream & InStream);
int LoadStringsWithCopy(TByteStream & InStream);
ARRAY_POINTER DataBuffer;
ARRAY_POINTER FirstValid;
ARRAY_POINTER ArrayPointer;
DWORD ItemCount; // Number of items in the array
DWORD MaxItemCount; // Capacity of the array
bool bIsValidArray;
};
class TBitEntryArray : public TGenericArray
{
public:
TBitEntryArray();
~TBitEntryArray();
DWORD GetBitEntry(DWORD EntryIndex)
{
DWORD dwItemIndex = (EntryIndex * BitsPerEntry) >> 0x05;
DWORD dwStartBit = (EntryIndex * BitsPerEntry) & 0x1F;
DWORD dwEndBit = dwStartBit + BitsPerEntry;
DWORD dwResult;
// If the end bit index is greater than 32,
// we also need to load from the next 32-bit item
if(dwEndBit > 0x20)
{
dwResult = (Uint32Array[dwItemIndex + 1] << (0x20 - dwStartBit)) | (Uint32Array[dwItemIndex] >> dwStartBit);
}
else
{
dwResult = Uint32Array[dwItemIndex] >> dwStartBit;
}
// Now we also need to mask the result by the bit mask
return dwResult & EntryBitMask;
}
void ExchangeWith(TBitEntryArray & Target);
int LoadFromStream(TByteStream & InStream);
int LoadFromStream_Exchange(TByteStream & InStream);
DWORD BitsPerEntry;
DWORD EntryBitMask;
DWORD TotalEntries;
};
class TStruct40
{
public:
TStruct40();
void InitSearchBuffers();
TGenericArray array_00;
TGenericArray PathStops; // Array of path checkpoints
DWORD ItemIndex; // Current name fragment: Index to various tables
DWORD CharIndex;
DWORD ItemCount;
DWORD SearchPhase; // 0 = initializing, 2 = searching, 4 = finished
};
class TMndxFindResult
{
public:
TMndxFindResult();
~TMndxFindResult();
int CreateStruct40();
void FreeStruct40();
int SetSearchPath(const char * szNewSearchPath, size_t cchNewSearchPath);
const char * szSearchMask; // Search mask without wildcards
size_t cchSearchMask; // Length of the search mask
DWORD field_8;
const char * szFoundPath; // Found path name
size_t cchFoundPath; // Length of the found path name
DWORD FileNameIndex; // Index of the file name
TStruct40 * pStruct40;
};
class TSparseArray
{
public:
TSparseArray();
void ExchangeWith(TSparseArray & TargetObject);
int LoadFromStream(TByteStream & InStream);
int LoadFromStream_Exchange(TByteStream & InStream);
// Returns true if the item at n-th position is present
DWORD IsItemPresent(DWORD ItemIndex)
{
return (ItemBits.Uint32Array[ItemIndex >> 0x05] & (1 << (ItemIndex & 0x1F)));
}
DWORD GetItemValue(DWORD ItemIndex);
TGenericArray ItemBits; // Bit array for each item (1 = item is present)
DWORD TotalItemCount; // Total number of items in the array
DWORD ValidItemCount; // Number of present items in the array
TGenericArray BaseValues; // Array of base values for item indexes >= 0x200
TGenericArray ArrayDwords_38;
TGenericArray ArrayDwords_50;
};
class TNameIndexStruct
{
public:
TNameIndexStruct();
~TNameIndexStruct();
bool CheckNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs);
bool CheckAndCopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs);
void CopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs);
void ExchangeWith(TNameIndexStruct & Target);
int LoadFromStream(TByteStream & InStream);
int LoadFromStream_Exchange(TByteStream & InStream);
TGenericArray NameFragments;
TSparseArray Struct68;
};
class TStruct10
{
public:
TStruct10();
void CopyFrom(TStruct10 & Target);
int sub_1956FD0(DWORD dwBitMask);
int sub_1957050(DWORD dwBitMask);
int sub_19572E0(DWORD dwBitMask);
int sub_1957800(DWORD dwBitMask);
DWORD field_0;
DWORD field_4;
DWORD field_8;
DWORD field_C;
};
class TFileNameDatabasePtr
{
public:
TFileNameDatabasePtr();
~TFileNameDatabasePtr();
int FindFileInDatabase(TMndxFindResult * pStruct1C);
int sub_1956CE0(TMndxFindResult * pStruct1C, bool * pbFindResult);
int GetFileNameCount(PDWORD PtrFileNameCount);
int CreateDatabase(LPBYTE pbMarData, DWORD cbMarData);
int SetDatabase(TFileNameDatabase * pNewDB);
TFileNameDatabase * pDB;
};
class TFileNameDatabase
{
public:
TFileNameDatabase();
void ExchangeWith(TFileNameDatabase & Target);
int LoadFromStream(TByteStream & InStream);
int LoadFromStream_Exchange(TByteStream & InStream);
DWORD sub_1959CB0(DWORD dwHashValue);
DWORD sub_1959F50(DWORD arg_0);
// Retrieves the name fragment distance
// HOTS: 19573D0/inlined
DWORD GetNameFragmentOffsetEx(DWORD LoBitsIndex, DWORD HiBitsIndex)
{
return (FrgmDist_HiBits.GetBitEntry(HiBitsIndex) << 0x08) | FrgmDist_LoBits.ByteArray[LoBitsIndex];
}
// HOTS: 1957350, inlined
DWORD GetNameFragmentOffset(DWORD LoBitsIndex)
{
return GetNameFragmentOffsetEx(LoBitsIndex, Struct68_D0.GetItemValue(LoBitsIndex));
}
bool sub_1957B80(TMndxFindResult * pStruct1C, DWORD dwKey);
bool CheckNextPathFragment(TMndxFindResult * pStruct1C);
bool FindFileInDatabase(TMndxFindResult * pStruct1C);
void sub_1958D70(TMndxFindResult * pStruct1C, DWORD arg_4);
bool sub_1959010(TMndxFindResult * pStruct1C, DWORD arg_4);
bool sub_1958B00(TMndxFindResult * pStruct1C);
bool sub_1959460(TMndxFindResult * pStruct1C);
TSparseArray Struct68_00;
TSparseArray FileNameIndexes; // Array of file name indexes
TSparseArray Struct68_D0;
// This pair of arrays serves for fast conversion from name hash to fragment offset
TGenericArray FrgmDist_LoBits; // Array of lower 8 bits of name fragment offset
TBitEntryArray FrgmDist_HiBits; // Array of upper x bits of name fragment offset
TNameIndexStruct IndexStruct_174;
TFileNameDatabasePtr NextDB;
TGenericArray NameFragTable;
DWORD NameFragIndexMask;
DWORD field_214;
TStruct10 Struct10;
TByteStream MarStream;
};
typedef struct _MAR_FILE
{
TFileNameDatabasePtr * pDatabasePtr;
LPBYTE pbMarData;
DWORD cbMarData;
} MAR_FILE, *PMAR_FILE;
//-----------------------------------------------------------------------------
// Macros
// Returns nonzero if the name fragment match is a single-char match
inline bool IS_SINGLE_CHAR_MATCH(TGenericArray & Table, DWORD ItemIndex)
{
return ((Table.NameFragArray[ItemIndex].FragOffs & 0xFFFFFF00) == 0xFFFFFF00);
}
#endif // __CASC_MNDX_ROOT__

View File

@@ -0,0 +1,322 @@
/*****************************************************************************/
/* CascOpenFile.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* System-dependent directory functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 01.05.14 1.00 Lad The first version of CascOpenFile.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
//-----------------------------------------------------------------------------
// Local functions
TCascFile * IsValidFileHandle(HANDLE hFile)
{
TCascFile * hf = (TCascFile *)hFile;
return (hf != NULL && hf->hs != NULL && hf->szClassName != NULL && !strcmp(hf->szClassName, "TCascFile")) ? hf : NULL;
}
PCASC_INDEX_ENTRY FindIndexEntry(TCascStorage * hs, PQUERY_KEY pIndexKey)
{
PCASC_INDEX_ENTRY pIndexEntry = NULL;
if(hs->pIndexEntryMap != NULL)
pIndexEntry = (PCASC_INDEX_ENTRY)Map_FindObject(hs->pIndexEntryMap, pIndexKey->pbData, NULL);
return pIndexEntry;
}
PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, PDWORD PtrIndex)
{
PCASC_ENCODING_ENTRY pEncodingEntry = NULL;
if(hs->pEncodingMap != NULL)
pEncodingEntry = (PCASC_ENCODING_ENTRY)Map_FindObject(hs->pEncodingMap, pEncodingKey->pbData, PtrIndex);
return pEncodingEntry;
}
static TCascFile * CreateFileHandle(TCascStorage * hs, PCASC_INDEX_ENTRY pIndexEntry)
{
ULONGLONG FileOffsMask = ((ULONGLONG)1 << hs->KeyMapping[0].SegmentBits) - 1;
ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE);
TCascFile * hf;
// Allocate the CASC file structure
hf = (TCascFile *)CASC_ALLOC(TCascFile, 1);
if(hf != NULL)
{
// Initialize the structure
memset(hf, 0, sizeof(TCascFile));
hf->ArchiveIndex = (DWORD)(FileOffset >> hs->KeyMapping[0].SegmentBits);
hf->HeaderOffset = (DWORD)(FileOffset & FileOffsMask);
hf->szClassName = "TCascFile";
// Copy the file size. Note that for all files except ENCODING,
// this is the compressed file size
hf->CompressedSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE);
// For now, we set the file size to be equal to compressed size
// This is used when loading the ENCODING file, which does not
// have entry in the encoding table
hf->FileSize = hf->CompressedSize;
// Increment the number of references to the archive
hs->dwRefCount++;
hf->hs = hs;
}
return hf;
}
static bool OpenFileByIndexKey(TCascStorage * hs, PQUERY_KEY pIndexKey, DWORD dwFlags, TCascFile ** ppCascFile)
{
PCASC_INDEX_ENTRY pIndexEntry;
int nError = ERROR_SUCCESS;
CASCLIB_UNUSED(dwFlags);
// Find the key entry in the array of file keys
pIndexEntry = FindIndexEntry(hs, pIndexKey);
if(pIndexEntry == NULL)
nError = ERROR_FILE_NOT_FOUND;
// Create the file handle structure
if(nError == ERROR_SUCCESS)
{
ppCascFile[0] = CreateFileHandle(hs, pIndexEntry);
if(ppCascFile[0] == NULL)
nError = ERROR_FILE_NOT_FOUND;
}
#ifdef CASCLIB_TEST
if(nError == ERROR_SUCCESS && ppCascFile[0] != NULL)
{
ppCascFile[0]->FileSize_IdxEntry = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE);
}
#endif
if(nError != ERROR_SUCCESS)
SetLastError(nError);
return (nError == ERROR_SUCCESS);
}
static bool OpenFileByEncodingKey(TCascStorage * hs, PQUERY_KEY pEncodingKey, DWORD dwFlags, TCascFile ** ppCascFile)
{
PCASC_ENCODING_ENTRY pEncodingEntry;
QUERY_KEY IndexKey;
// Find the encoding entry
pEncodingEntry = FindEncodingEntry(hs, pEncodingKey, NULL);
if(pEncodingEntry == NULL)
{
SetLastError(ERROR_FILE_NOT_FOUND);
return false;
}
// Prepare the file index and open the file by index
// Note: We don't know what to do if there is more than just one index key
// We always take the first file present. Is that correct?
IndexKey.pbData = GET_INDEX_KEY(pEncodingEntry);
IndexKey.cbData = MD5_HASH_SIZE;
if(OpenFileByIndexKey(hs, &IndexKey, dwFlags, ppCascFile))
{
// Check if the file handle was created
if(ppCascFile[0] != NULL)
{
// Fill-in the file size. For all files except ENCODING,
// this overrides the value stored in the index entry.
ppCascFile[0]->FileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE);
#ifdef CASCLIB_TEST
ppCascFile[0]->FileSize_EncEntry = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE);
#endif
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Public functions
bool WINAPI CascOpenFileByIndexKey(HANDLE hStorage, PQUERY_KEY pIndexKey, DWORD dwFlags, HANDLE * phFile)
{
TCascStorage * hs;
// Validate the storage handle
hs = IsValidStorageHandle(hStorage);
if(hs == NULL)
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
// Validate the other parameters
if(pIndexKey == NULL || pIndexKey->pbData == NULL || pIndexKey->cbData == 0 || phFile == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// Use the internal function to open the file
return OpenFileByIndexKey(hs, pIndexKey, dwFlags, (TCascFile **)phFile);
}
bool WINAPI CascOpenFileByEncodingKey(HANDLE hStorage, PQUERY_KEY pEncodingKey, DWORD dwFlags, HANDLE * phFile)
{
TCascStorage * hs;
// Validate the storage handle
hs = IsValidStorageHandle(hStorage);
if(hs == NULL)
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
// Validate the other parameters
if(pEncodingKey == NULL || pEncodingKey->pbData == NULL || pEncodingKey->cbData == 0 || phFile == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// Use the internal function fo open the file
return OpenFileByEncodingKey(hs, pEncodingKey, dwFlags, (TCascFile **)phFile);
}
bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocale, DWORD dwFlags, HANDLE * phFile)
{
TCascStorage * hs;
QUERY_KEY EncodingKey;
LPBYTE pbEncodingKey;
BYTE KeyBuffer[MD5_HASH_SIZE];
int nError = ERROR_SUCCESS;
CASCLIB_UNUSED(dwLocale);
// Validate the storage handle
hs = IsValidStorageHandle(hStorage);
if(hs == NULL)
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
// Validate the other parameters
if(szFileName == NULL || szFileName[0] == 0 || phFile == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// If the user is opening the file via encoding key, skip the ROOT file processing
if((dwFlags & CASC_OPEN_BY_ENCODING_KEY) == 0)
{
// Let the root directory provider get us the encoding key
pbEncodingKey = RootHandler_GetKey(hs->pRootHandler, szFileName);
if(pbEncodingKey == NULL)
{
SetLastError(ERROR_FILE_NOT_FOUND);
return false;
}
// Setup the encoding key
EncodingKey.pbData = pbEncodingKey;
EncodingKey.cbData = MD5_HASH_SIZE;
}
else
{
// Check the length of the file name
if(strlen(szFileName) < MD5_STRING_SIZE)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// Convert the file name to binary blob
EncodingKey.pbData = KeyBuffer;
EncodingKey.cbData = MD5_HASH_SIZE;
nError = ConvertStringToBinary(szFileName, MD5_STRING_SIZE, KeyBuffer);
}
// Use the encoding key to find the file in the encoding table entry
if(nError == ERROR_SUCCESS)
{
if(!OpenFileByEncodingKey(hs, &EncodingKey, dwFlags, (TCascFile **)phFile))
{
assert(GetLastError() != ERROR_SUCCESS);
nError = GetLastError();
}
}
#ifdef CASCLIB_TEST
// if(phFile[0] != NULL && pRootEntryMndx != NULL)
// {
// ((TCascFile *)(phFile[0]))->FileSize_RootEntry = pRootEntryMndx->FileSize;
// }
#endif
if(nError != ERROR_SUCCESS)
SetLastError(nError);
return (nError == ERROR_SUCCESS);
}
DWORD WINAPI CascGetFileId(HANDLE hStorage, const char * szFileName)
{
TCascStorage * hs;
// Validate the storage handle
hs = IsValidStorageHandle(hStorage);
if (hs == NULL)
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
// Validate the other parameters
if (szFileName == NULL || szFileName[0] == 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
return RootHandler_GetFileId(hs->pRootHandler, szFileName);
}
bool WINAPI CascCloseFile(HANDLE hFile)
{
TCascFile * hf;
hf = IsValidFileHandle(hFile);
if(hf != NULL)
{
// Close (dereference) the archive handle
if(hf->hs != NULL)
CascCloseStorage((HANDLE)hf->hs);
hf->hs = NULL;
// Free the file cache and frame array
if(hf->pbFileCache != NULL)
CASC_FREE(hf->pbFileCache);
if(hf->pFrames != NULL)
CASC_FREE(hf->pFrames);
// Free the structure itself
hf->szClassName = NULL;
CASC_FREE(hf);
return true;
}
SetLastError(ERROR_INVALID_HANDLE);
return false;
}

File diff suppressed because it is too large Load Diff

276
dep/CascLib/src/CascPort.h Normal file
View File

@@ -0,0 +1,276 @@
/*****************************************************************************/
/* CascPort.h Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* Portability module for the CascLib library. Contains a wrapper symbols */
/* to make the compilation under Linux work */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 29.04.14 1.00 Lad Created */
/*****************************************************************************/
#ifndef __CASCPORT_H__
#define __CASCPORT_H__
#ifndef __cplusplus
#define bool char
#define true 1
#define false 0
#endif
//-----------------------------------------------------------------------------
// Defines for Windows
#if !defined(PLATFORM_DEFINED) && (defined(_WIN32) || defined(_WIN64))
// In MSVC 8.0, there are some functions declared as deprecated.
#if _MSC_VER >= 1400
#ifndef _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE
#endif
#ifndef _CRT_NON_CONFORMING_SWPRINTFS
#define _CRT_NON_CONFORMING_SWPRINTFS
#endif
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <tchar.h>
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <windows.h>
#include <wininet.h>
#include <sys/types.h>
#define PLATFORM_LITTLE_ENDIAN
#ifdef _WIN64
#define PLATFORM_64BIT
#else
#define PLATFORM_32BIT
#endif
#define PATH_SEPARATOR '\\'
#define CREATE_DIRECTORY(name) CreateDirectory(name, NULL);
#define PLATFORM_WINDOWS
#define PLATFORM_DEFINED // The platform is known now
#endif
//-----------------------------------------------------------------------------
// Defines for Mac
#if !defined(PLATFORM_DEFINED) && defined(__APPLE__) // Mac BSD API
// Macintosh
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <stddef.h>
// Support for PowerPC on Max OS X
#if (__ppc__ == 1) || (__POWERPC__ == 1) || (_ARCH_PPC == 1)
#include <stdint.h>
#include <CoreFoundation/CFByteOrder.h>
#endif
#define PKEXPORT
#define __SYS_ZLIB
#define __SYS_BZLIB
#ifndef __BIG_ENDIAN__
#define PLATFORM_LITTLE_ENDIAN
#endif
#define PATH_SEPARATOR '/'
#define CREATE_DIRECTORY(name) mkdir(name, 0755)
#define PLATFORM_MAC
#define PLATFORM_DEFINED // The platform is known now
#define FIELD_OFFSET(t,f) offsetof(t,f)
#endif
//-----------------------------------------------------------------------------
// Assumption: we are not on Windows nor Macintosh, so this must be linux *grin*
#if !defined(PLATFORM_DEFINED)
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <errno.h>
#define PATH_SEPARATOR '/'
#define CREATE_DIRECTORY(name) mkdir(name, 0755)
#define PLATFORM_LITTLE_ENDIAN
#define PLATFORM_LINUX
#define PLATFORM_DEFINED
#define FIELD_OFFSET(t,f) offsetof(t,f)
#endif
//-----------------------------------------------------------------------------
// Definition of Windows-specific types for non-Windows platforms
#ifndef PLATFORM_WINDOWS
#if __LP64__
#define PLATFORM_64BIT
#else
#define PLATFORM_32BIT
#endif
// Typedefs for ANSI C
typedef unsigned char BYTE;
typedef unsigned short USHORT;
typedef int LONG;
typedef unsigned int DWORD;
typedef unsigned long DWORD_PTR;
typedef long LONG_PTR;
typedef long INT_PTR;
typedef long long LONGLONG;
typedef unsigned long long ULONGLONG;
typedef unsigned long long *PULONGLONG;
typedef void * HANDLE;
typedef void * LPOVERLAPPED; // Unsupported on Linux and Mac
typedef char TCHAR;
typedef unsigned int LCID;
typedef LONG * PLONG;
typedef DWORD * PDWORD;
typedef BYTE * LPBYTE;
typedef char * LPSTR;
#ifdef PLATFORM_32BIT
#define _LZMA_UINT32_IS_ULONG
#endif
// Some Windows-specific defines
#ifndef MAX_PATH
#define MAX_PATH 1024
#endif
#define WINAPI
#define FILE_BEGIN SEEK_SET
#define FILE_CURRENT SEEK_CUR
#define FILE_END SEEK_END
#define INVALID_HANDLE_VALUE ((HANDLE)-1)
#define _T(x) x
#define _tcslen strlen
#define _tcscpy strcpy
#define _tcscat strcat
#define _tcschr strchr
#define _tcsrchr strrchr
#define _tcsstr strstr
#define _tcsspn strspn
#define _tcsncmp strncmp
#define _tprintf printf
#define _stprintf sprintf
#define _tremove remove
#define _tmkdir mkdir
#define _stricmp strcasecmp
#define _strnicmp strncasecmp
#define _tcsicmp strcasecmp
#define _tcsnicmp strncasecmp
#endif // !PLATFORM_WINDOWS
// 64-bit calls are supplied by "normal" calls on Mac
#if defined(PLATFORM_MAC)
#define stat64 stat
#define fstat64 fstat
#define lseek64 lseek
#define ftruncate64 ftruncate
#define off64_t off_t
#define O_LARGEFILE 0
#endif
// Platform-specific error codes for UNIX-based platforms
#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
#define ERROR_SUCCESS 0
#define ERROR_FILE_NOT_FOUND ENOENT
#define ERROR_ACCESS_DENIED EPERM
#define ERROR_INVALID_HANDLE EBADF
#define ERROR_NOT_ENOUGH_MEMORY ENOMEM
#define ERROR_NOT_SUPPORTED ENOTSUP
#define ERROR_INVALID_PARAMETER EINVAL
#define ERROR_DISK_FULL ENOSPC
#define ERROR_ALREADY_EXISTS EEXIST
#define ERROR_INSUFFICIENT_BUFFER ENOBUFS
#define ERROR_BAD_FORMAT 1000 // No such error code under Linux
#define ERROR_NO_MORE_FILES 1001 // No such error code under Linux
#define ERROR_HANDLE_EOF 1002 // No such error code under Linux
#define ERROR_CAN_NOT_COMPLETE 1003 // No such error code under Linux
#define ERROR_FILE_CORRUPT 1004 // No such error code under Linux
#define ERROR_FILE_ENCRYPTED 1005 // Returned by encrypted stream when can't find file key
#endif
#ifndef ERROR_FILE_INCOMPLETE
#define ERROR_FILE_INCOMPLETE 1006 // The required file part is missing
#endif
//-----------------------------------------------------------------------------
// Swapping functions
#ifdef PLATFORM_LITTLE_ENDIAN
#define BSWAP_INT16_UNSIGNED(a) (a)
#define BSWAP_INT16_SIGNED(a) (a)
#define BSWAP_INT32_UNSIGNED(a) (a)
#define BSWAP_INT32_SIGNED(a) (a)
#define BSWAP_INT64_SIGNED(a) (a)
#define BSWAP_INT64_UNSIGNED(a) (a)
#define BSWAP_ARRAY16_UNSIGNED(a,b) {}
#define BSWAP_ARRAY32_UNSIGNED(a,b) {}
#define BSWAP_ARRAY64_UNSIGNED(a,b) {}
#else
#ifdef __cplusplus
extern "C" {
#endif
int16_t SwapInt16(uint16_t);
uint16_t SwapUInt16(uint16_t);
int32_t SwapInt32(uint32_t);
uint32_t SwapUInt32(uint32_t);
int64_t SwapInt64(uint64_t);
uint64_t SwapUInt64(uint64_t);
void ConvertUInt16Buffer(void * ptr, size_t length);
void ConvertUInt32Buffer(void * ptr, size_t length);
void ConvertUInt64Buffer(void * ptr, size_t length);
#ifdef __cplusplus
}
#endif
#define BSWAP_INT16_SIGNED(a) SwapInt16((a))
#define BSWAP_INT16_UNSIGNED(a) SwapUInt16((a))
#define BSWAP_INT32_SIGNED(a) SwapInt32((a))
#define BSWAP_INT32_UNSIGNED(a) SwapUInt32((a))
#define BSWAP_INT64_SIGNED(a) SwapInt64((a))
#define BSWAP_INT64_UNSIGNED(a) SwapUInt64((a))
#define BSWAP_ARRAY16_UNSIGNED(a,b) ConvertUInt16Buffer((a),(b))
#define BSWAP_ARRAY32_UNSIGNED(a,b) ConvertUInt32Buffer((a),(b))
#define BSWAP_ARRAY64_UNSIGNED(a,b) ConvertUInt64Buffer((a),(b))
#endif
#endif // __CASCPORT_H__

View File

@@ -0,0 +1,620 @@
/*****************************************************************************/
/* CascOpenFile.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* System-dependent directory functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 01.05.14 1.00 Lad The first version of CascOpenFile.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
//-----------------------------------------------------------------------------
// Local structures
typedef struct _BLTE_FRAME
{
BYTE CompressedSize[4]; // Compressed file size as big endian
BYTE FrameSize[4]; // File size as big endian
BYTE md5[MD5_HASH_SIZE]; // Hash of the compressed frame
} BLTE_FRAME, *PBLTE_FRAME;
//-----------------------------------------------------------------------------
// Local functions
TCascFile * IsValidFileHandle(HANDLE hFile); // In CascOpenFile.cpp
static int EnsureDataStreamIsOpen(TCascFile * hf)
{
TCascStorage * hs = hf->hs;
TFileStream * pStream = NULL;
TCHAR * szDataFile;
TCHAR szPlainName[0x40];
// If the file is not open yet, do it
if(hs->DataFileArray[hf->ArchiveIndex] == NULL)
{
// Prepare the name of the data file
_stprintf(szPlainName, _T("data.%03u"), hf->ArchiveIndex);
szDataFile = CombinePath(hs->szIndexPath, szPlainName);
// Open the data file
if(szDataFile != NULL)
{
// Open the stream
pStream = FileStream_OpenFile(szDataFile, STREAM_FLAG_READ_ONLY | STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE);
hs->DataFileArray[hf->ArchiveIndex] = pStream;
CASC_FREE(szDataFile);
}
}
// Return error or success
hf->pStream = hs->DataFileArray[hf->ArchiveIndex];
return (hf->pStream != NULL) ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND;
}
static int LoadFileFrames(TCascFile * hf)
{
PBLTE_FRAME pFileFrames;
PBLTE_FRAME pFileFrame;
ULONGLONG ArchiveFileOffset;
DWORD FrameOffset = 0;
DWORD FileSize = 0;
int nError = ERROR_SUCCESS;
assert(hf != NULL);
assert(hf->pStream != NULL);
assert(hf->pFrames != NULL);
// Allocate frame array
pFileFrames = pFileFrame = CASC_ALLOC(BLTE_FRAME, hf->FrameCount);
if(pFileFrames != NULL)
{
// Load the frame array
ArchiveFileOffset = hf->FramesOffset;
if(FileStream_Read(hf->pStream, &ArchiveFileOffset, pFileFrames, hf->FrameCount * sizeof(BLTE_FRAME)))
{
// Move the raw archive offset
ArchiveFileOffset += (hf->FrameCount * sizeof(BLTE_FRAME));
// Copy the frames to the file structure
for(DWORD i = 0; i < hf->FrameCount; i++, pFileFrame++)
{
hf->pFrames[i].FrameArchiveOffset = (DWORD)ArchiveFileOffset;
hf->pFrames[i].FrameFileOffset = FrameOffset;
hf->pFrames[i].CompressedSize = ConvertBytesToInteger_4(pFileFrame->CompressedSize);
hf->pFrames[i].FrameSize = ConvertBytesToInteger_4(pFileFrame->FrameSize);
memcpy(hf->pFrames[i].md5, pFileFrame->md5, MD5_HASH_SIZE);
ArchiveFileOffset += hf->pFrames[i].CompressedSize;
FrameOffset += hf->pFrames[i].FrameSize;
FileSize += hf->pFrames[i].FrameSize;
}
}
else
nError = GetLastError();
// Note: on ENCODING file, this value is almost always bigger
// then the real size of ENCODING. We handle this problem
// by calculating size of the ENCODIG file from its header.
hf->FileSize = FileSize;
#ifdef CASCLIB_TEST
hf->FileSize_FrameSum = FileSize;
#endif
// Free the array
CASC_FREE(pFileFrames);
}
else
nError = ERROR_NOT_ENOUGH_MEMORY;
return nError;
}
static int EnsureHeaderAreaIsLoaded(TCascFile * hf)
{
TCascStorage * hs = hf->hs;
ULONGLONG FileOffset = hf->HeaderOffset;
LPBYTE pbHeaderArea;
DWORD FileSignature;
DWORD FileSize;
BYTE HeaderArea[MAX_HEADER_AREA_SIZE];
int nError;
// We need the data file to be open
nError = EnsureDataStreamIsOpen(hf);
if(nError != ERROR_SUCCESS)
return nError;
// Make sure that we already know the shift
// to the begin of file data.
// Note that older builds of Heroes of the Storm have entries pointing
// to the beginning of the header area.
// Newer versions of HOTS have encoding entries pointing directly to
// the BLTE header
if(hs->dwFileBeginDelta == 0xFFFFFFFF)
{
FileSignature = 0;
FileOffset = hf->HeaderOffset;
if(!FileStream_Read(hf->pStream, &FileOffset, &FileSignature, sizeof(DWORD)))
return ERROR_FILE_CORRUPT;
hs->dwFileBeginDelta = (FileSignature == BLTE_HEADER_SIGNATURE) ? BLTE_HEADER_DELTA : 0;
}
// If the file size is not loaded yet, do it
if(hf->FrameCount == 0)
{
// Load the part before BLTE header + header itself
FileOffset = hf->HeaderOffset - hs->dwFileBeginDelta;
if(!FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea)))
return ERROR_FILE_CORRUPT;
// Copy the MD5 hash of the frame array
memcpy(hf->FrameArrayHash, HeaderArea, MD5_HASH_SIZE);
pbHeaderArea = HeaderArea + MD5_HASH_SIZE;
// Copy the file size
FileSize = ConvertBytesToInteger_4_LE(pbHeaderArea);
pbHeaderArea += 0x0E;
// Verify the BLTE signature
if(ConvertBytesToInteger_4_LE(pbHeaderArea) != BLTE_HEADER_SIGNATURE)
return ERROR_BAD_FORMAT;
pbHeaderArea += sizeof(DWORD);
// Load the size of the frame headers
hf->HeaderSize = ConvertBytesToInteger_4(pbHeaderArea);
if(hf->HeaderSize & 0x80000000)
return ERROR_BAD_FORMAT;
pbHeaderArea += sizeof(DWORD);
// Read the header size
assert(hs->dwFileBeginDelta <= BLTE_HEADER_DELTA);
hf->HeaderOffset += (BLTE_HEADER_DELTA - hs->dwFileBeginDelta);
hf->FrameCount = 1;
// Retrieve the frame count, if different from 1
if(hf->HeaderSize != 0)
{
// The next byte must be 0x0F
if(pbHeaderArea[0] != 0x0F)
return ERROR_BAD_FORMAT;
pbHeaderArea++;
// Next three bytes form number of frames
hf->FrameCount = ConvertBytesToInteger_3(pbHeaderArea);
}
#ifdef CASCLIB_TEST
hf->FileSize_HdrArea = FileSize;
#endif
}
return ERROR_SUCCESS;
}
static int EnsureFrameHeadersLoaded(TCascFile * hf)
{
int nError;
// Make sure we have header area loaded
nError = EnsureHeaderAreaIsLoaded(hf);
if(nError != ERROR_SUCCESS)
return nError;
// If the frame headers are not loaded yet, do it
if(hf->pFrames == NULL)
{
// Allocate the frame array
hf->pFrames = CASC_ALLOC(CASC_FILE_FRAME, hf->FrameCount);
if(hf->pFrames != NULL)
{
// Either load the frames from the file or supply them on our own
if(hf->HeaderSize != 0)
{
hf->FramesOffset = hf->HeaderOffset + sizeof(DWORD) + sizeof(DWORD) + sizeof(DWORD);
nError = LoadFileFrames(hf);
}
else
{
// Offset of the first frame is right after the file frames
hf->FramesOffset = hf->HeaderOffset + sizeof(DWORD) + sizeof(DWORD);
hf->pFrames[0].FrameArchiveOffset = hf->FramesOffset;
hf->pFrames[0].FrameFileOffset = 0;
hf->pFrames[0].CompressedSize = hf->CompressedSize;
hf->pFrames[0].FrameSize = hf->FileSize;
memset(hf->pFrames[0].md5, 0, MD5_HASH_SIZE);
}
}
// Return result
return (hf->pFrames != NULL) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT;
}
return ERROR_SUCCESS;
}
static PCASC_FILE_FRAME FindFileFrame(TCascFile * hf, DWORD FilePointer)
{
PCASC_FILE_FRAME pFrame = hf->pFrames;
DWORD FrameBegin;
DWORD FrameEnd;
// Sanity checks
assert(hf->pFrames != NULL);
assert(hf->FrameCount != 0);
// Find the frame where to read from
for(DWORD i = 0; i < hf->FrameCount; i++, pFrame++)
{
// Does the read request fit into the current frame?
FrameBegin = pFrame->FrameFileOffset;
FrameEnd = FrameBegin + pFrame->FrameSize;
if(FrameBegin <= FilePointer && FilePointer < FrameEnd)
return pFrame;
}
// Not found, sorry
return NULL;
}
static int ProcessFileFrame(
LPBYTE pbOutBuffer,
DWORD cbOutBuffer,
LPBYTE pbInBuffer,
DWORD cbInBuffer,
DWORD dwFrameIndex)
{
LPBYTE pbTempBuffer;
LPBYTE pbWorkBuffer;
DWORD cbTempBuffer = CASCLIB_MAX(cbInBuffer, cbOutBuffer);
DWORD cbWorkBuffer = cbOutBuffer + 1;
DWORD dwStepCount = 0;
bool bWorkComplete = false;
int nError = ERROR_SUCCESS;
// Allocate the temporary buffer that will serve as output
pbWorkBuffer = pbTempBuffer = CASC_ALLOC(BYTE, cbTempBuffer);
if(pbWorkBuffer == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Perform the loop
for(;;)
{
// Set the output buffer.
// Even operations: extract to temporary buffer
// Odd operations: extract to output buffer
pbWorkBuffer = (dwStepCount & 0x01) ? pbOutBuffer : pbTempBuffer;
cbWorkBuffer = (dwStepCount & 0x01) ? cbOutBuffer : cbTempBuffer;
// Perform the operation specific to the operation ID
switch(pbInBuffer[0])
{
case 'E': // Encrypted files
nError = CascDecrypt(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1, dwFrameIndex);
bWorkComplete = (nError != ERROR_SUCCESS);
break;
case 'Z': // ZLIB compressed files
nError = CascDecompress(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1);
bWorkComplete = true;
break;
case 'N': // Normal stored files
nError = CascDirectCopy(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1);
bWorkComplete = true;
break;
case 'F': // Recursive frames - not supported
default: // Unrecognized - if we unpacked something, we consider it done
nError = ERROR_NOT_SUPPORTED;
bWorkComplete = true;
assert(false);
break;
}
// Are we done?
if(bWorkComplete)
break;
// Set the input buffer to the work buffer
pbInBuffer = pbWorkBuffer;
cbInBuffer = cbWorkBuffer;
dwStepCount++;
}
// If the data are currently in the temporary buffer,
// we need to copy them to output buffer
if(nError == ERROR_SUCCESS && pbWorkBuffer != pbOutBuffer)
{
if(cbWorkBuffer != cbOutBuffer)
nError = ERROR_INSUFFICIENT_BUFFER;
memcpy(pbOutBuffer, pbWorkBuffer, cbOutBuffer);
}
// Free the temporary buffer
CASC_FREE(pbTempBuffer);
return nError;
}
//-----------------------------------------------------------------------------
// Public functions
//
// THE FILE SIZE PROBLEM
//
// There are members called "FileSize" in many CASC-related structure
// For various files, these variables have different meaning.
//
// Storage FileName FileSize FrameSum HdrArea IdxEntry EncEntry RootEntry
// ----------- -------- ---------- -------- -------- -------- -------- ---------
// HotS(29049) ENCODING 0x0024BA45 - 0x0024b98a 0x0024BA45 0x0024BA45 n/a n/a
// HotS(29049) ROOT 0x00193340 - 0x00193340 0x0010db65 0x0010db65 0x00193340 n/a
// HotS(29049) (other) 0x00001080 - 0x00001080 0x000008eb 0x000008eb 0x00001080 0x00001080
//
// WoW(18888) ENCODING 0x030d487b - 0x030dee79 0x030d487b 0x030d487b n/a n/a
// WoW(18888) ROOT 0x016a9800 - n/a 0x0131313d 0x0131313d 0x016a9800 n/a
// WoW(18888) (other) 0x000007d0 - 0x000007d0 0x00000397 0x00000397 0x000007d0 n/a
//
DWORD WINAPI CascGetFileSize(HANDLE hFile, PDWORD pdwFileSizeHigh)
{
TCascFile * hf;
int nError;
CASCLIB_UNUSED(pdwFileSizeHigh);
// Validate the file handle
if((hf = IsValidFileHandle(hFile)) == NULL)
{
SetLastError(ERROR_INVALID_HANDLE);
return CASC_INVALID_SIZE;
}
// Make sure that the file header area is loaded
nError = EnsureFrameHeadersLoaded(hf);
if(nError != ERROR_SUCCESS)
{
SetLastError(nError);
return CASC_INVALID_SIZE;
}
// Give the file size to the caller
if(pdwFileSizeHigh != NULL)
*pdwFileSizeHigh = 0;
return hf->FileSize;
}
DWORD WINAPI CascSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod)
{
TCascFile * hf;
ULONGLONG FilePosition;
ULONGLONG MoveOffset;
DWORD dwFilePosHi;
// If the hFile is not a valid file handle, return an error.
hf = IsValidFileHandle(hFile);
if(hf == NULL)
{
SetLastError(ERROR_INVALID_HANDLE);
return CASC_INVALID_POS;
}
// Get the relative point where to move from
switch(dwMoveMethod)
{
case FILE_BEGIN:
FilePosition = 0;
break;
case FILE_CURRENT:
FilePosition = hf->FilePointer;
break;
case FILE_END:
FilePosition = hf->FileSize;
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return CASC_INVALID_POS;
}
// Now get the move offset. Note that both values form
// a signed 64-bit value (a file pointer can be moved backwards)
if(plFilePosHigh != NULL)
dwFilePosHi = *plFilePosHigh;
else
dwFilePosHi = (lFilePos & 0x80000000) ? 0xFFFFFFFF : 0;
MoveOffset = MAKE_OFFSET64(dwFilePosHi, lFilePos);
// Now calculate the new file pointer
// Do not allow the file pointer to overflow
FilePosition = ((FilePosition + MoveOffset) >= FilePosition) ? (FilePosition + MoveOffset) : 0;
// CASC files can't be bigger than 4 GB.
// We don't allow to go past 4 GB
if(FilePosition >> 32)
{
SetLastError(ERROR_INVALID_PARAMETER);
return CASC_INVALID_POS;
}
// Change the file position
hf->FilePointer = (DWORD)FilePosition;
// Return the new file position
if(plFilePosHigh != NULL)
*plFilePosHigh = 0;
return hf->FilePointer;
}
bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDWORD pdwBytesRead)
{
PCASC_FILE_FRAME pFrame = NULL;
ULONGLONG StreamSize;
ULONGLONG FileOffset;
TCascFile * hf;
LPBYTE pbBuffer = (LPBYTE)pvBuffer;
DWORD dwStartPointer = 0;
DWORD dwFilePointer = 0;
DWORD dwEndPointer = 0;
DWORD dwFrameSize;
bool bReadResult;
int nError = ERROR_SUCCESS;
// The buffer must be valid
if(pvBuffer == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// Validate the file handle
if((hf = IsValidFileHandle(hFile)) == NULL)
{
SetLastError(ERROR_INVALID_HANDLE);
return false;
}
// If the file frames are not loaded yet, do it now
if(nError == ERROR_SUCCESS)
{
nError = EnsureFrameHeadersLoaded(hf);
}
// If the file position is at or beyond end of file, do nothing
if(nError == ERROR_SUCCESS && hf->FilePointer >= hf->FileSize)
{
*pdwBytesRead = 0;
return true;
}
// Find the file frame where to read from
if(nError == ERROR_SUCCESS)
{
// Get the frame
pFrame = FindFileFrame(hf, hf->FilePointer);
if(pFrame == NULL || pFrame->CompressedSize < 1)
nError = ERROR_FILE_CORRUPT;
}
// Perform the read
if(nError == ERROR_SUCCESS)
{
// If not enough bytes in the file remaining, cut them
dwStartPointer = dwFilePointer = hf->FilePointer;
dwEndPointer = dwStartPointer + dwBytesToRead;
if(dwEndPointer > hf->FileSize)
dwEndPointer = hf->FileSize;
// Perform block read from each file frame
while(dwFilePointer < dwEndPointer)
{
LPBYTE pbFrameData = NULL;
DWORD dwFrameStart = pFrame->FrameFileOffset;
DWORD dwFrameEnd = pFrame->FrameFileOffset + pFrame->FrameSize;
// Shall we populate the cache with a new data?
if(dwFrameStart != hf->CacheStart || hf->CacheEnd != dwFrameEnd)
{
// Shall we reallocate the cache buffer?
if(pFrame->FrameSize > hf->cbFileCache)
{
if(hf->pbFileCache != NULL)
CASC_FREE(hf->pbFileCache);
hf->pbFileCache = CASC_ALLOC(BYTE, pFrame->FrameSize);
hf->cbFileCache = pFrame->FrameSize;
}
// We also need to allocate buffer for the raw data
pbFrameData = CASC_ALLOC(BYTE, pFrame->CompressedSize);
if(pbFrameData == NULL)
{
nError = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// Load the raw file data to memory
FileOffset = pFrame->FrameArchiveOffset;
bReadResult = FileStream_Read(hf->pStream, &FileOffset, pbFrameData, pFrame->CompressedSize);
// Note: The raw file data size could be less than expected
// Happened in WoW build 19342 with the ROOT file. MD5 in the frame header
// is zeroed, which means it should not be checked
// Frame File: data.029
// Frame Offs: 0x013ED9F0 size 0x01325B32
// Frame End: 0x02713522
// File Size: 0x027134FC
if(bReadResult == false && GetLastError() == ERROR_HANDLE_EOF && !IsValidMD5(pFrame->md5))
{
// Get the size of the remaining file
FileStream_GetSize(hf->pStream, &StreamSize);
dwFrameSize = (DWORD)(StreamSize - FileOffset);
// If the frame offset is before EOF and frame end is beyond EOF, correct it
if(FileOffset < StreamSize && dwFrameSize < pFrame->CompressedSize)
{
memset(pbFrameData + dwFrameSize, 0, (pFrame->CompressedSize - dwFrameSize));
bReadResult = true;
}
}
// If the read result failed, we cannot finish reading it
if(bReadResult && VerifyDataBlockHash(pbFrameData, pFrame->CompressedSize, pFrame->md5))
{
// Convert the source frame to the file cache
nError = ProcessFileFrame(hf->pbFileCache,
pFrame->FrameSize,
pbFrameData,
pFrame->CompressedSize,
(DWORD)(pFrame - hf->pFrames));
if(nError == ERROR_SUCCESS)
{
// Set the start and end of the cache
hf->CacheStart = dwFrameStart;
hf->CacheEnd = dwFrameEnd;
}
}
else
{
nError = ERROR_FILE_CORRUPT;
}
// Free the raw frame data
CASC_FREE(pbFrameData);
}
// Copy the decompressed data
if(dwFrameEnd > dwEndPointer)
dwFrameEnd = dwEndPointer;
memcpy(pbBuffer, hf->pbFileCache + (dwFilePointer - dwFrameStart), (dwFrameEnd - dwFilePointer));
pbBuffer += (dwFrameEnd - dwFilePointer);
// Move pointers
dwFilePointer = dwFrameEnd;
pFrame++;
}
}
// Update the file position
if(nError == ERROR_SUCCESS)
{
if(pdwBytesRead != NULL)
*pdwBytesRead = (dwFilePointer - dwStartPointer);
hf->FilePointer = dwFilePointer;
}
if(nError != ERROR_SUCCESS)
SetLastError(nError);
return (nError == ERROR_SUCCESS);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,213 @@
/*****************************************************************************/
/* CascRootFile_Ovr.cpp Copyright (c) Ladislav Zezula 2015 */
/*---------------------------------------------------------------------------*/
/* Support for loading Overwatch ROOT file */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 28.10.15 1.00 Lad The first version of CascRootFile_Ovr.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
//-----------------------------------------------------------------------------
// Structure definitions for Overwatch root file
typedef struct _CASC_FILE_ENTRY
{
ENCODING_KEY EncodingKey; // Encoding key
ULONGLONG FileNameHash; // File name hash
DWORD dwFileName; // Offset of the file name in the name cache
} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY;
struct TRootHandler_Ovr : public TRootHandler
{
// Linear global list of file entries
DYNAMIC_ARRAY FileTable;
// Linear global list of names
DYNAMIC_ARRAY FileNames;
// Global map of FileName -> FileEntry
PCASC_MAP pRootMap;
};
//-----------------------------------------------------------------------------
// Local functions
static int InsertFileEntry(
TRootHandler_Ovr * pRootHandler,
const char * szFileName,
LPBYTE pbEncodingKey)
{
PCASC_FILE_ENTRY pFileEntry;
size_t nLength = strlen(szFileName);
// Attempt to insert the file name to the global buffer
szFileName = (char *)Array_Insert(&pRootHandler->FileNames, szFileName, nLength + 1);
if(szFileName == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Attempt to insert the entry to the array of file entries
pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1);
if(pFileEntry == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Fill the file entry
pFileEntry->EncodingKey = *(PENCODING_KEY)pbEncodingKey;
pFileEntry->FileNameHash = CalcFileNameHash(szFileName);
pFileEntry->dwFileName = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szFileName);
// Insert the file entry to the map
assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL);
Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash);
return ERROR_SUCCESS;
}
//-----------------------------------------------------------------------------
// Implementation of Overwatch root file
static int OvrHandler_Insert(
TRootHandler_Ovr * pRootHandler,
const char * szFileName,
LPBYTE pbEncodingKey)
{
return InsertFileEntry(pRootHandler, szFileName, pbEncodingKey);
}
static LPBYTE OvrHandler_Search(TRootHandler_Ovr * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD /* PtrLocaleFlags */, PDWORD /* PtrFileDataId */)
{
PCASC_FILE_ENTRY pFileEntry;
// Are we still inside the root directory range?
while(pSearch->IndexLevel1 < pRootHandler->FileTable.ItemCount)
{
// Retrieve the file item
pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, pSearch->IndexLevel1);
strcpy(pSearch->szFileName, (char *)Array_ItemAt(&pRootHandler->FileNames, pFileEntry->dwFileName));
// Prepare the pointer to the next search
pSearch->IndexLevel1++;
return pFileEntry->EncodingKey.Value;
}
// No more entries
return NULL;
}
static void OvrHandler_EndSearch(TRootHandler_Ovr * /* pRootHandler */, TCascSearch * /* pSearch */)
{
// Do nothing
}
static LPBYTE OvrHandler_GetKey(TRootHandler_Ovr * pRootHandler, const char * szFileName)
{
ULONGLONG FileNameHash = CalcFileNameHash(szFileName);
return (LPBYTE)Map_FindObject(pRootHandler->pRootMap, &FileNameHash, NULL);
}
static DWORD OvrHandler_GetFileId(TRootHandler_Ovr * /* pRootHandler */, const char * /* szFileName */)
{
// Not implemented for Overwatch
return 0;
}
static void OvrHandler_Close(TRootHandler_Ovr * pRootHandler)
{
if(pRootHandler != NULL)
{
// Free the file map
if(pRootHandler->pRootMap)
Map_Free(pRootHandler->pRootMap);
pRootHandler->pRootMap = NULL;
// Free the array of the file names and file items
Array_Free(&pRootHandler->FileTable);
Array_Free(&pRootHandler->FileNames);
// Free the root file itself
CASC_FREE(pRootHandler);
}
}
//-----------------------------------------------------------------------------
// Public functions
int RootHandler_CreateOverwatch(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)
{
TRootHandler_Ovr * pRootHandler;
ENCODING_KEY KeyBuffer;
QUERY_KEY EncodingKey = {KeyBuffer.Value, MD5_HASH_SIZE};
void * pTextFile;
size_t nLength;
char szOneLine[0x200];
char szFileName[MAX_PATH+1];
DWORD dwFileCountMax = (DWORD)hs->pEncodingMap->TableSize;
int nFileNameIndex;
int nError = ERROR_SUCCESS;
// Allocate the root handler object
hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_Ovr, 1);
if(pRootHandler == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Fill-in the handler functions
memset(pRootHandler, 0, sizeof(TRootHandler_Ovr));
pRootHandler->Insert = (ROOT_INSERT)OvrHandler_Insert;
pRootHandler->Search = (ROOT_SEARCH)OvrHandler_Search;
pRootHandler->EndSearch = (ROOT_ENDSEARCH)OvrHandler_EndSearch;
pRootHandler->GetKey = (ROOT_GETKEY)OvrHandler_GetKey;
pRootHandler->Close = (ROOT_CLOSE)OvrHandler_Close;
pRootHandler->GetFileId = (ROOT_GETFILEID)OvrHandler_GetFileId;
// Fill-in the flags
pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES;
// Allocate the linear array of file entries
nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, 0x10000);
if(nError != ERROR_SUCCESS)
return nError;
// Allocate the buffer for the file names
nError = Array_Create(&pRootHandler->FileNames, char, 0x10000);
if(nError != ERROR_SUCCESS)
return nError;
// Create map of ROOT_ENTRY -> FileEntry
pRootHandler->pRootMap = Map_Create(dwFileCountMax, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash));
if(pRootHandler->pRootMap == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Parse the ROOT file
pTextFile = ListFile_FromBuffer(pbRootFile, cbRootFile);
if(pTextFile != NULL)
{
// Get the initial line, containing variable names
nLength = ListFile_GetNextLine(pTextFile, szOneLine, _maxchars(szOneLine));
// Determine the index of the "FILENAME" variable
nError = GetRootVariableIndex(szOneLine, szOneLine + nLength, "FILENAME", &nFileNameIndex);
if(nError == ERROR_SUCCESS)
{
// Parse the next lines
while((nLength = ListFile_GetNextLine(pTextFile, szOneLine, _maxchars(szOneLine))) > 0)
{
// Parse the line
nError = ParseRootFileLine(szOneLine, szOneLine + nLength, nFileNameIndex, &EncodingKey, szFileName, _maxchars(szFileName));
if(nError == ERROR_SUCCESS)
{
InsertFileEntry(pRootHandler, szFileName, KeyBuffer.Value);
}
}
}
// Free the listfile
ListFile_Free(pTextFile);
}
// Succeeded
return nError;
}

View File

@@ -0,0 +1,214 @@
/*****************************************************************************/
/* CascRootFile_SC1.cpp Copyright (c) Ladislav Zezula 2017 */
/*---------------------------------------------------------------------------*/
/* Support for loading Starcraft 1 ROOT file */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 28.10.15 1.00 Lad The first version of CascRootFile_SC1.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
//-----------------------------------------------------------------------------
// Structure definitions for Overwatch root file
typedef struct _CASC_FILE_ENTRY
{
ENCODING_KEY EncodingKey; // Encoding key
ULONGLONG FileNameHash; // File name hash
DWORD dwFileName; // Offset of the file name in the name cache
} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY;
struct TRootHandler_SC1 : public TRootHandler
{
// Linear global list of file entries
DYNAMIC_ARRAY FileTable;
// Linear global list of names
DYNAMIC_ARRAY FileNames;
// Global map of FileName -> FileEntry
PCASC_MAP pRootMap;
};
//-----------------------------------------------------------------------------
// Local functions
static int InsertFileEntry(
TRootHandler_SC1 * pRootHandler,
const char * szFileName,
LPBYTE pbEncodingKey)
{
PCASC_FILE_ENTRY pFileEntry;
size_t nLength = strlen(szFileName);
// Attempt to insert the file name to the global buffer
szFileName = (char *)Array_Insert(&pRootHandler->FileNames, szFileName, nLength + 1);
if(szFileName == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Attempt to insert the entry to the array of file entries
pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1);
if(pFileEntry == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Fill the file entry
pFileEntry->EncodingKey = *(PENCODING_KEY)pbEncodingKey;
pFileEntry->FileNameHash = CalcFileNameHash(szFileName);
pFileEntry->dwFileName = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szFileName);
// Insert the file entry to the map
assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL);
Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash);
return ERROR_SUCCESS;
}
//-----------------------------------------------------------------------------
// Implementation of Overwatch root file
static int SC1Handler_Insert(
TRootHandler_SC1 * pRootHandler,
const char * szFileName,
LPBYTE pbEncodingKey)
{
return InsertFileEntry(pRootHandler, szFileName, pbEncodingKey);
}
static LPBYTE SC1Handler_Search(TRootHandler_SC1 * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD /* PtrLocaleFlags */, PDWORD /* PtrFileDataId */)
{
PCASC_FILE_ENTRY pFileEntry;
// Are we still inside the root directory range?
while(pSearch->IndexLevel1 < pRootHandler->FileTable.ItemCount)
{
// Retrieve the file item
pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, pSearch->IndexLevel1);
// Prepare the pointer to the next search
pSearch->IndexLevel1++;
char *filename = (char *)Array_ItemAt(&pRootHandler->FileNames, pFileEntry->dwFileName);
if (CheckWildCard(filename, pSearch->szMask)) {
strcpy(pSearch->szFileName, filename);
return pFileEntry->EncodingKey.Value;
}
}
// No more entries
return NULL;
}
static void SC1Handler_EndSearch(TRootHandler_SC1 * /* pRootHandler */, TCascSearch * /* pSearch */)
{
// Do nothing
}
static LPBYTE SC1Handler_GetKey(TRootHandler_SC1 * pRootHandler, const char * szFileName)
{
ULONGLONG FileNameHash = CalcFileNameHash(szFileName);
return (LPBYTE)Map_FindObject(pRootHandler->pRootMap, &FileNameHash, NULL);
}
static DWORD SC1Handler_GetFileId(TRootHandler_SC1 * /* pRootHandler */, const char * /* szFileName */)
{
// Not implemented for Overwatch
return 0;
}
static void SC1Handler_Close(TRootHandler_SC1 * pRootHandler)
{
if(pRootHandler != NULL)
{
// Free the file map
if(pRootHandler->pRootMap)
Map_Free(pRootHandler->pRootMap);
pRootHandler->pRootMap = NULL;
// Free the array of the file names and file items
Array_Free(&pRootHandler->FileTable);
Array_Free(&pRootHandler->FileNames);
// Free the root file itself
CASC_FREE(pRootHandler);
}
}
//-----------------------------------------------------------------------------
// Public functions
int RootHandler_CreateSC1(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)
{
TRootHandler_SC1 * pRootHandler;
ENCODING_KEY KeyBuffer;
QUERY_KEY EncodingKey = {KeyBuffer.Value, MD5_HASH_SIZE};
void * pTextFile;
size_t nLength;
char szOneLine[0x200];
DWORD dwFileCountMax = (DWORD)hs->pEncodingMap->TableSize;
int nError = ERROR_SUCCESS;
// Allocate the root handler object
hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_SC1, 1);
if(pRootHandler == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Fill-in the handler functions
memset(pRootHandler, 0, sizeof(TRootHandler_SC1));
pRootHandler->Insert = (ROOT_INSERT)SC1Handler_Insert;
pRootHandler->Search = (ROOT_SEARCH)SC1Handler_Search;
pRootHandler->EndSearch = (ROOT_ENDSEARCH)SC1Handler_EndSearch;
pRootHandler->GetKey = (ROOT_GETKEY)SC1Handler_GetKey;
pRootHandler->Close = (ROOT_CLOSE)SC1Handler_Close;
pRootHandler->GetFileId = (ROOT_GETFILEID)SC1Handler_GetFileId;
// Fill-in the flags
pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES;
// Allocate the linear array of file entries
nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, 0x10000);
if(nError != ERROR_SUCCESS)
return nError;
// Allocate the buffer for the file names
nError = Array_Create(&pRootHandler->FileNames, char, 0x10000);
if(nError != ERROR_SUCCESS)
return nError;
// Create map of ROOT_ENTRY -> FileEntry
pRootHandler->pRootMap = Map_Create(dwFileCountMax, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash));
if(pRootHandler->pRootMap == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Parse the ROOT file
pTextFile = ListFile_FromBuffer(pbRootFile, cbRootFile);
if(pTextFile != NULL)
{
// Parse the next lines
while((nLength = ListFile_GetNextLine(pTextFile, szOneLine, _maxchars(szOneLine))) > 0)
{
LPSTR szEncodingKey;
BYTE EncodingKey[MD5_HASH_SIZE];
szEncodingKey = strchr(szOneLine, _T('|'));
if(szEncodingKey != NULL)
{
// Split the name and encoding key
*szEncodingKey++ = 0;
// Insert the entry to the map
ConvertStringToBinary(szEncodingKey, MD5_STRING_SIZE, EncodingKey);
InsertFileEntry(pRootHandler, szOneLine, EncodingKey);
}
}
// Free the listfile
ListFile_Free(pTextFile);
}
// Succeeded
return nError;
}

View File

@@ -0,0 +1,595 @@
/*****************************************************************************/
/* CascOpenStorage.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* Storage functions for CASC */
/* Note: WoW6 offsets refer to WoW.exe 6.0.3.19116 (32-bit) */
/* SHA1: c10e9ffb7d040a37a356b96042657e1a0c95c0dd */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 29.04.14 1.00 Lad The first version of CascOpenStorage.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
//-----------------------------------------------------------------------------
// Local structures
#define ROOT_SEARCH_PHASE_INITIALIZING 0
#define ROOT_SEARCH_PHASE_LISTFILE 1
#define ROOT_SEARCH_PHASE_NAMELESS 2
#define ROOT_SEARCH_PHASE_FINISHED 2
// On-disk version of locale block
typedef struct _FILE_LOCALE_BLOCK
{
DWORD NumberOfFiles; // Number of entries
DWORD Flags;
DWORD Locales; // File locale mask (CASC_LOCALE_XXX)
// Followed by a block of 32-bit integers (count: NumberOfFiles)
// Followed by the MD5 and file name hash (count: NumberOfFiles)
} FILE_LOCALE_BLOCK, *PFILE_LOCALE_BLOCK;
// On-disk version of root entry
typedef struct _FILE_ROOT_ENTRY
{
ENCODING_KEY EncodingKey; // MD5 of the file
ULONGLONG FileNameHash; // Jenkins hash of the file name
} FILE_ROOT_ENTRY, *PFILE_ROOT_ENTRY;
typedef struct _CASC_ROOT_BLOCK
{
PFILE_LOCALE_BLOCK pLocaleBlockHdr; // Pointer to the locale block
PDWORD FileDataIds; // Pointer to the array of File Data IDs
PFILE_ROOT_ENTRY pRootEntries;
} CASC_ROOT_BLOCK, *PCASC_ROOT_BLOCK;
// Root file entry for CASC storages without MNDX root file (World of Warcraft 6.0+)
// Does not match to the in-file structure of the root entry
typedef struct _CASC_FILE_ENTRY
{
ENCODING_KEY EncodingKey; // File encoding key (MD5)
ULONGLONG FileNameHash; // Jenkins hash of the file name
DWORD FileDataId; // File Data Index
DWORD Locales; // Locale flags of the file
} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY;
struct TRootHandler_WoW6 : public TRootHandler
{
// Linear global list of file entries
DYNAMIC_ARRAY FileTable;
DYNAMIC_ARRAY FileDataIdLookupTable;
// Global map of FileName -> FileEntry
PCASC_MAP pRootMap;
// For counting files
DWORD dwTotalFileCount;
};
// Prototype for root file parsing routine
typedef int (*PARSE_ROOT)(TRootHandler_WoW6 * pRootHandler, PCASC_ROOT_BLOCK pBlockInfo);
//-----------------------------------------------------------------------------
// Local functions
static bool IsFileDataIdName(const char * szFileName)
{
BYTE BinaryValue[4];
// 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')
{
// Then, 8 hexadecimal digits must follow
if(ConvertStringToBinary(szFileName + 4, 8, BinaryValue) == ERROR_SUCCESS)
{
// Must be followed by an extension or end-of-string
return (szFileName[0x0C] == 0 || szFileName[0x0C] == '.');
}
}
return false;
}
static int FileDataIdCompare(const void *, const void * pvFile1, const void * pvFile2)
{
return ((PCASC_FILE_ENTRY)pvFile1)->FileDataId - ((PCASC_FILE_ENTRY)pvFile2)->FileDataId;
}
// Search by FileDataId
PCASC_FILE_ENTRY FindRootEntry(DYNAMIC_ARRAY & FileTable, DWORD FileDataId)
{
PCASC_FILE_ENTRY* pStartEntry = (PCASC_FILE_ENTRY*)FileTable.ItemArray;
PCASC_FILE_ENTRY* pMidlEntry;
PCASC_FILE_ENTRY* pEndEntry = pStartEntry + FileTable.ItemCount - 1;
int nResult;
// Perform binary search on the table
while(pStartEntry < pEndEntry)
{
// Calculate the middle of the interval
pMidlEntry = pStartEntry + ((pEndEntry - pStartEntry) / 2);
// Did we find it?
nResult = (int)FileDataId - (int)(*pMidlEntry)->FileDataId;
if(nResult == 0)
return *pMidlEntry;
// Move the interval to the left or right
(nResult < 0) ? pEndEntry = pMidlEntry : pStartEntry = pMidlEntry + 1;
}
return NULL;
}
// Search by file name hash
// Also used in CascSearchFile
PCASC_FILE_ENTRY FindRootEntry(PCASC_MAP pRootMap, const char * szFileName, DWORD * PtrTableIndex)
{
// Calculate the HASH value of the normalized file name
ULONGLONG FileNameHash = CalcFileNameHash(szFileName);
// Perform the hash search
return (PCASC_FILE_ENTRY)Map_FindObject(pRootMap, &FileNameHash, PtrTableIndex);
}
LPBYTE VerifyLocaleBlock(PCASC_ROOT_BLOCK pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd)
{
// Validate the file locale block
pBlockInfo->pLocaleBlockHdr = (PFILE_LOCALE_BLOCK)pbFilePointer;
pbFilePointer = (LPBYTE)(pBlockInfo->pLocaleBlockHdr + 1);
if(pbFilePointer > pbFileEnd)
return NULL;
// Validate the array of 32-bit integers
pBlockInfo->FileDataIds = (PDWORD)pbFilePointer;
pbFilePointer = (LPBYTE)(pBlockInfo->FileDataIds + pBlockInfo->pLocaleBlockHdr->NumberOfFiles);
if(pbFilePointer > pbFileEnd)
return NULL;
// Validate the array of root entries
pBlockInfo->pRootEntries = (PFILE_ROOT_ENTRY)pbFilePointer;
pbFilePointer = (LPBYTE)(pBlockInfo->pRootEntries + pBlockInfo->pLocaleBlockHdr->NumberOfFiles);
if(pbFilePointer > pbFileEnd)
return NULL;
// Return the position of the next block
return pbFilePointer;
}
static int ParseRoot_CountFiles(
TRootHandler_WoW6 * pRootHandler,
PCASC_ROOT_BLOCK pRootBlock)
{
// Add the file count to the total file count
pRootHandler->dwTotalFileCount += pRootBlock->pLocaleBlockHdr->NumberOfFiles;
return ERROR_SUCCESS;
}
static int ParseRoot_AddRootEntries(
TRootHandler_WoW6 * pRootHandler,
PCASC_ROOT_BLOCK pRootBlock)
{
PCASC_FILE_ENTRY pFileEntry;
DWORD dwFileDataId = 0;
// Sanity checks
assert(pRootHandler->FileTable.ItemArray != NULL);
assert(pRootHandler->FileTable.ItemCountMax != 0);
assert(pRootHandler->FileDataIdLookupTable.ItemArray != NULL);
assert(pRootHandler->FileDataIdLookupTable.ItemCountMax != 0);
// WoW.exe (build 19116): Blocks with zero files are skipped
for(DWORD i = 0; i < pRootBlock->pLocaleBlockHdr->NumberOfFiles; i++)
{
// Create new entry, with overflow check
if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax)
return ERROR_INSUFFICIENT_BUFFER;
pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1);
if (pRootHandler->FileDataIdLookupTable.ItemCount >= pRootHandler->FileDataIdLookupTable.ItemCountMax)
return ERROR_INSUFFICIENT_BUFFER;
Array_Insert(&pRootHandler->FileDataIdLookupTable, &pFileEntry, 1);
// (004147A3) Prepare the CASC_FILE_ENTRY structure
pFileEntry->FileNameHash = pRootBlock->pRootEntries[i].FileNameHash;
pFileEntry->FileDataId = dwFileDataId + pRootBlock->FileDataIds[i];
pFileEntry->Locales = pRootBlock->pLocaleBlockHdr->Locales;
pFileEntry->EncodingKey = pRootBlock->pRootEntries[i].EncodingKey;
// Also, insert the entry to the map
Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash);
// Update the local File Data Id
assert((pFileEntry->FileDataId + 1) > pFileEntry->FileDataId);
dwFileDataId = pFileEntry->FileDataId + 1;
// Move to the next root entry
pFileEntry++;
}
return ERROR_SUCCESS;
}
static int ParseWowRootFileInternal(
TRootHandler_WoW6 * pRootHandler,
PARSE_ROOT pfnParseRoot,
LPBYTE pbRootFile,
LPBYTE pbRootFileEnd,
DWORD dwLocaleMask,
BYTE bOverrideArchive,
BYTE bAudioLocale)
{
CASC_ROOT_BLOCK RootBlock;
// Now parse the root file
while(pbRootFile < pbRootFileEnd)
{
// Validate the file locale block
pbRootFile = VerifyLocaleBlock(&RootBlock, pbRootFile, pbRootFileEnd);
if(pbRootFile == NULL)
break;
// WoW.exe (build 19116): Entries with flag 0x100 set are skipped
if(RootBlock.pLocaleBlockHdr->Flags & 0x100)
continue;
// WoW.exe (build 19116): Entries with flag 0x80 set are skipped if overrideArchive CVAR is set to FALSE (which is by default in non-chinese clients)
if((RootBlock.pLocaleBlockHdr->Flags & 0x80) && bOverrideArchive == 0)
continue;
// WoW.exe (build 19116): Entries with (flags >> 0x1F) not equal to bAudioLocale are skipped
if((RootBlock.pLocaleBlockHdr->Flags >> 0x1F) != bAudioLocale)
continue;
// WoW.exe (build 19116): Locales other than defined mask are skipped too
if((RootBlock.pLocaleBlockHdr->Locales & dwLocaleMask) == 0)
continue;
// Now call the custom function
pfnParseRoot(pRootHandler, &RootBlock);
}
return ERROR_SUCCESS;
}
/*
// known dwRegion values returned from sub_661316 (7.0.3.22210 x86 win), also referred by lua GetCurrentRegion
#define WOW_REGION_US 0x01
#define WOW_REGION_KR 0x02
#define WOW_REGION_EU 0x03
#define WOW_REGION_TW 0x04
#define WOW_REGION_CN 0x05
#define WOW_LOCALE_ENUS 0x00
#define WOW_LOCALE_KOKR 0x01
#define WOW_LOCALE_FRFR 0x02
#define WOW_LOCALE_DEDE 0x03
#define WOW_LOCALE_ZHCN 0x04
#define WOW_LOCALE_ZHTW 0x05
#define WOW_LOCALE_ESES 0x06
#define WOW_LOCALE_ESMX 0x07
#define WOW_LOCALE_RURU 0x08
#define WOW_LOCALE_PTBR 0x0A
#define WOW_LOCALE_ITIT 0x0B
// dwLocale is obtained from a WOW_LOCALE_* to CASC_LOCALE_BIT_* mapping (sub_6615D0 in 7.0.3.22210 x86 win)
// because (ENUS, ENGB) and (PTBR, PTPT) pairs share the same value on WOW_LOCALE_* enum
// dwRegion is used to distinguish them
if(dwRegion == WOW_REGION_EU)
{
// Is this english version of WoW?
if(dwLocale == CASC_LOCALE_BIT_ENUS)
{
LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENGB, bOverrideArchive, bAudioLocale);
LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENUS, bOverrideArchive, bAudioLocale);
return ERROR_SUCCESS;
}
// Is this portuguese version of WoW?
if(dwLocale == CASC_LOCALE_BIT_PTBR)
{
LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTPT, bOverrideArchive, bAudioLocale);
LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTBR, bOverrideArchive, bAudioLocale);
}
}
else
LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, (1 << dwLocale), bOverrideArchive, bAudioLocale);
*/
static int ParseWowRootFile2(
TRootHandler_WoW6 * pRootHandler,
PARSE_ROOT pfnParseRoot,
LPBYTE pbRootFile,
LPBYTE pbRootFileEnd,
DWORD dwLocaleMask,
BYTE bAudioLocale)
{
// Load the locale as-is
ParseWowRootFileInternal(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, dwLocaleMask, false, bAudioLocale);
// If we wanted enGB, we also load enUS for the missing files
if(dwLocaleMask == CASC_LOCALE_ENGB)
ParseWowRootFileInternal(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, CASC_LOCALE_ENUS, false, bAudioLocale);
if(dwLocaleMask == CASC_LOCALE_PTPT)
ParseWowRootFileInternal(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, CASC_LOCALE_PTBR, false, bAudioLocale);
return ERROR_SUCCESS;
}
// WoW.exe: 004146C7 (BuildManifest::Load)
static int ParseWowRootFile(
TRootHandler_WoW6 * pRootHandler,
PARSE_ROOT pfnParseRoot,
LPBYTE pbRootFile,
LPBYTE pbRootFileEnd,
DWORD dwLocaleMask)
{
ParseWowRootFile2(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, dwLocaleMask, 0);
ParseWowRootFile2(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, dwLocaleMask, 1);
return ERROR_SUCCESS;
}
//-----------------------------------------------------------------------------
// Implementation of WoW6 root file
static int WowHandler_Insert(
TRootHandler_WoW6 * pRootHandler,
const char * szFileName,
LPBYTE pbEncodingKey)
{
PCASC_FILE_ENTRY pFileEntry;
DWORD FileDataId = 0;
// Don't let the number of items to overflow
if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax)
return ERROR_NOT_ENOUGH_MEMORY;
if (pRootHandler->FileDataIdLookupTable.ItemCount >= pRootHandler->FileDataIdLookupTable.ItemCountMax)
return ERROR_NOT_ENOUGH_MEMORY;
// Insert the item to the linear file list
pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1);
if(pFileEntry != NULL)
{
Array_Insert(&pRootHandler->FileDataIdLookupTable, &pFileEntry, 1);
// Get the file data ID of the previous item (0 if this is the first one)
if(pRootHandler->FileTable.ItemCount > 1)
FileDataId = pFileEntry[-1].FileDataId;
// Fill-in the new entry
pFileEntry->EncodingKey = *(PENCODING_KEY)pbEncodingKey;
pFileEntry->FileNameHash = CalcFileNameHash(szFileName);
pFileEntry->FileDataId = FileDataId + 1;
pFileEntry->Locales = CASC_LOCALE_ALL;
// Verify collisions (debug version only)
assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL);
// Insert the entry to the map
Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash);
}
return ERROR_SUCCESS;
}
static LPBYTE WowHandler_Search(
TRootHandler_WoW6 * pRootHandler,
TCascSearch * pSearch,
PDWORD /* PtrFileSize */,
PDWORD PtrLocaleFlags,
PDWORD PtrFileDataId)
{
PCASC_FILE_ENTRY pFileEntry;
// Only if we have a listfile
if(pSearch->pCache != NULL)
{
// Keep going through the listfile
while(ListFile_GetNext(pSearch->pCache, pSearch->szMask, pSearch->szFileName, MAX_PATH))
{
// Find the root entry
pFileEntry = FindRootEntry(pRootHandler->pRootMap, pSearch->szFileName, NULL);
if(pFileEntry != NULL)
{
// Give the caller the locale mask
if(PtrLocaleFlags != NULL)
PtrLocaleFlags[0] = pFileEntry->Locales;
if(PtrFileDataId != NULL)
PtrFileDataId[0] = pFileEntry->FileDataId;
return pFileEntry->EncodingKey.Value;
}
}
}
// No more files
return NULL;
}
static LPBYTE WowHandler_GetKey(TRootHandler_WoW6 * pRootHandler, const char * szFileName)
{
PCASC_FILE_ENTRY pFileEntry;
DWORD FileDataId;
BYTE FileDataIdLE[4];
// Open by FileDataId. The file name must be as following:
// File########.unk, where '#' are hexa-decimal numbers (case insensitive).
// Extension is ignored in that case
if(IsFileDataIdName(szFileName))
{
ConvertStringToBinary(szFileName + 4, 8, FileDataIdLE);
FileDataId = ConvertBytesToInteger_4(FileDataIdLE);
pFileEntry = FindRootEntry(pRootHandler->FileDataIdLookupTable, FileDataId);
}
else
{
// Find by the file name hash
pFileEntry = FindRootEntry(pRootHandler->pRootMap, szFileName, NULL);
}
return (pFileEntry != NULL) ? pFileEntry->EncodingKey.Value : NULL;
}
static void WowHandler_EndSearch(TRootHandler_WoW6 * /* pRootHandler */, TCascSearch * pSearch)
{
if(pSearch->pRootContext != NULL)
CASC_FREE(pSearch->pRootContext);
pSearch->pRootContext = NULL;
}
static DWORD WowHandler_GetFileId(TRootHandler_WoW6 * pRootHandler, const char * szFileName)
{
PCASC_FILE_ENTRY pFileEntry;
// Find by the file name hash
pFileEntry = FindRootEntry(pRootHandler->pRootMap, szFileName, NULL);
return (pFileEntry != NULL) ? pFileEntry->FileDataId : 0;
}
static void WowHandler_Close(TRootHandler_WoW6 * pRootHandler)
{
if(pRootHandler != NULL)
{
Array_Free(&pRootHandler->FileTable);
Array_Free(&pRootHandler->FileDataIdLookupTable);
Map_Free(pRootHandler->pRootMap);
CASC_FREE(pRootHandler);
}
}
#ifdef _DEBUG
static void TRootHandlerWoW6_Dump(
TCascStorage * hs,
TDumpContext * dc, // Pointer to an opened file
LPBYTE pbRootFile,
DWORD cbRootFile,
const TCHAR * szListFile,
int nDumpLevel)
{
PCASC_ENCODING_ENTRY pEncodingEntry;
CASC_ROOT_BLOCK BlockInfo;
PLISTFILE_MAP pListMap;
QUERY_KEY EncodingKey;
LPBYTE pbRootFileEnd = pbRootFile + cbRootFile;
LPBYTE pbFilePointer;
char szOneLine[0x100];
DWORD i;
// Create the listfile map
pListMap = ListFile_CreateMap(szListFile);
// Dump the root entries
for(pbFilePointer = pbRootFile; pbFilePointer <= pbRootFileEnd; )
{
// Validate the root block
pbFilePointer = VerifyLocaleBlock(&BlockInfo, pbFilePointer, pbRootFileEnd);
if(pbFilePointer == NULL)
break;
// Dump the locale block
dump_print(dc, "Flags: %08X Locales: %08X NumberOfFiles: %u\n"
"=========================================================\n",
BlockInfo.pLocaleBlockHdr->Flags,
BlockInfo.pLocaleBlockHdr->Locales,
BlockInfo.pLocaleBlockHdr->NumberOfFiles);
// Dump the hashes and encoding keys
for(i = 0; i < BlockInfo.pLocaleBlockHdr->NumberOfFiles; i++)
{
// Dump the entry
dump_print(dc, "%08X %08X-%08X %s %s\n",
(DWORD)(BlockInfo.FileDataIds[i]),
(DWORD)(BlockInfo.pRootEntries[i].FileNameHash >> 0x20),
(DWORD)(BlockInfo.pRootEntries[i].FileNameHash),
StringFromMD5(BlockInfo.pRootEntries[i].EncodingKey.Value, szOneLine),
ListFile_FindName(pListMap, BlockInfo.pRootEntries[i].FileNameHash));
// Find the encoding entry in the encoding table
if(nDumpLevel >= DUMP_LEVEL_ENCODING_FILE)
{
EncodingKey.pbData = BlockInfo.pRootEntries[i].EncodingKey.Value;
EncodingKey.cbData = MD5_HASH_SIZE;
pEncodingEntry = FindEncodingEntry(hs, &EncodingKey, NULL);
CascDumpEncodingEntry(hs, dc, pEncodingEntry, nDumpLevel);
}
}
// Put extra newline
dump_print(dc, "\n");
}
ListFile_FreeMap(pListMap);
}
#endif
//-----------------------------------------------------------------------------
// Public functions
int RootHandler_CreateWoW6(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile, DWORD dwLocaleMask)
{
TRootHandler_WoW6 * pRootHandler;
LPBYTE pbRootFileEnd = pbRootFile + cbRootFile;
int nError;
// Verify the size
if(pbRootFile == NULL || cbRootFile <= sizeof(PFILE_LOCALE_BLOCK))
nError = ERROR_FILE_CORRUPT;
// Allocate the root handler object
hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_WoW6, 1);
if(pRootHandler == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Fill-in the handler functions
memset(pRootHandler, 0, sizeof(TRootHandler_WoW6));
pRootHandler->Insert = (ROOT_INSERT)WowHandler_Insert;
pRootHandler->Search = (ROOT_SEARCH)WowHandler_Search;
pRootHandler->EndSearch = (ROOT_ENDSEARCH)WowHandler_EndSearch;
pRootHandler->GetKey = (ROOT_GETKEY)WowHandler_GetKey;
pRootHandler->Close = (ROOT_CLOSE)WowHandler_Close;
pRootHandler->GetFileId = (ROOT_GETFILEID)WowHandler_GetFileId;
#ifdef _DEBUG
pRootHandler->Dump = TRootHandlerWoW6_Dump; // Support for ROOT file dump
#endif // _DEBUG
// Count the files that are going to be loaded
ParseWowRootFile(pRootHandler, ParseRoot_CountFiles, pbRootFile, pbRootFileEnd, dwLocaleMask);
pRootHandler->dwTotalFileCount += CASC_EXTRA_FILES;
// Create linear table that will contain all root items
nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, pRootHandler->dwTotalFileCount);
if(nError != ERROR_SUCCESS)
return nError;
// Create sorted table that will contain all root items to lookup by FileDataId
nError = Array_Create(&pRootHandler->FileDataIdLookupTable, PCASC_FILE_ENTRY, pRootHandler->dwTotalFileCount);
if (nError != ERROR_SUCCESS)
return nError;
// Create the map of FileHash ->FileEntry
pRootHandler->pRootMap = Map_Create(pRootHandler->dwTotalFileCount, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash));
if(pRootHandler->pRootMap == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Parse the root file again and insert all files to the map
ParseWowRootFile(pRootHandler, ParseRoot_AddRootEntries, pbRootFile, pbRootFileEnd, dwLocaleMask);
// Sort entries by FileDataId for searches
qsort_pointer_array((void**)pRootHandler->FileDataIdLookupTable.ItemArray, pRootHandler->FileDataIdLookupTable.ItemCount, &FileDataIdCompare, NULL);
return ERROR_SUCCESS;
}

View File

@@ -0,0 +1,719 @@
/*****************************************************************************/
/* CascCommon.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* Common functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 29.04.14 1.00 Lad The first version of CascCommon.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "../CascLib.h"
#include "../CascCommon.h"
//-----------------------------------------------------------------------------
// Conversion to uppercase/lowercase
// Converts ASCII characters to lowercase
// Converts backslash (0x5C) to normal slash (0x2F)
unsigned char AsciiToLowerTable_Slash[256] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x2F, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
// Converts ASCII characters to uppercase
// Converts slash (0x2F) to backslash (0x5C)
unsigned char AsciiToUpperTable_BkSlash[256] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x5C,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
unsigned char IntToHexChar[] = "0123456789abcdef";
//-----------------------------------------------------------------------------
// GetLastError/SetLastError support for non-Windows platform
#ifndef PLATFORM_WINDOWS
static int nLastError = ERROR_SUCCESS;
int GetLastError()
{
return nLastError;
}
void SetLastError(int nError)
{
nLastError = nError;
}
#endif
//-----------------------------------------------------------------------------
// String manipulation
void CopyString(char * szTarget, const char * szSource, size_t cchLength)
{
memcpy(szTarget, szSource, cchLength);
szTarget[cchLength] = 0;
}
void CopyString(wchar_t * szTarget, const char * szSource, size_t cchLength)
{
mbstowcs(szTarget, szSource, cchLength);
szTarget[cchLength] = 0;
}
void CopyString(char * szTarget, const wchar_t * szSource, size_t cchLength)
{
wcstombs(szTarget, szSource, cchLength);
szTarget[cchLength] = 0;
}
char * CascNewStr(const char * szString, size_t nCharsToReserve)
{
char * szNewString = NULL;
size_t nLength;
if(szString != NULL)
{
nLength = strlen(szString);
szNewString = CASC_ALLOC(char, nLength + nCharsToReserve + 1);
if(szNewString != NULL)
{
memcpy(szNewString, szString, nLength);
szNewString[nLength] = 0;
}
}
return szNewString;
}
wchar_t * CascNewStr(const wchar_t * szString, size_t nCharsToReserve)
{
wchar_t * szNewString = NULL;
size_t nLength;
if(szString != NULL)
{
nLength = wcslen(szString);
szNewString = CASC_ALLOC(wchar_t, nLength + nCharsToReserve + 1);
if(szNewString != NULL)
{
memcpy(szNewString, szString, nLength * sizeof(wchar_t));
szNewString[nLength] = 0;
}
}
return szNewString;
}
TCHAR * CascNewStrFromAnsi(const char * szBegin, const char * szEnd)
{
TCHAR * szNewString = NULL;
// Only if the entry is valid
if(szBegin != NULL && szEnd > szBegin)
{
// Allocate and copy the string
szNewString = CASC_ALLOC(TCHAR, (szEnd - szBegin + 1));
if(szNewString != NULL)
CopyString(szNewString, szBegin, (szEnd - szBegin));
}
// Return the string
return szNewString;
}
TCHAR * CombinePath(const TCHAR * szDirectory, const TCHAR * szSubDir)
{
TCHAR * szFullPath = NULL;
TCHAR * szPathPtr;
size_t nLength1 = 0;
size_t nLength2 = 0;
// Calculate lengths of each part
if(szDirectory != NULL)
{
// Get the length of the directory
nLength1 = _tcslen(szDirectory);
// Cut all ending backslashes
while(nLength1 > 0 && (szDirectory[nLength1 - 1] == _T('\\') || szDirectory[nLength1 - 1] == _T('/')))
nLength1--;
}
if(szSubDir != NULL)
{
// 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)
{
memcpy(szPathPtr, szDirectory, (nLength1 * sizeof(TCHAR)));
szPathPtr += nLength1;
}
// Copy the sub-directory
if(szSubDir != NULL && nLength2 != 0)
{
// Append backslash to the previous one
if(szPathPtr > szFullPath)
*szPathPtr++ = _T(PATH_SEPARATOR);
// Copy the string
memcpy(szPathPtr, szSubDir, (nLength2 * sizeof(TCHAR)));
szPathPtr += nLength2;
}
// Terminate the string
szPathPtr[0] = 0;
}
return szFullPath;
}
TCHAR * CombinePathAndString(const TCHAR * szPath, const char * szString, size_t nLength)
{
TCHAR * szFullPath = NULL;
TCHAR * szSubDir;
// Create the subdir string
szSubDir = CASC_ALLOC(TCHAR, nLength + 1);
if(szSubDir != NULL)
{
CopyString(szSubDir, szString, nLength);
szFullPath = CombinePath(szPath, szSubDir);
CASC_FREE(szSubDir);
}
return szFullPath;
}
size_t NormalizeFileName(const unsigned char * NormTable, char * szNormName, const char * szFileName, size_t cchMaxChars)
{
char * szNormNameEnd = szNormName + cchMaxChars;
size_t i;
// Normalize the file name: ToLower + BackSlashToSlash
for(i = 0; szFileName[0] != 0 && szNormName < szNormNameEnd; i++)
*szNormName++ = NormTable[*szFileName++];
// Terminate the string
szNormName[0] = 0;
return i;
}
size_t NormalizeFileName_UpperBkSlash(char * szNormName, const char * szFileName, size_t cchMaxChars)
{
return NormalizeFileName(AsciiToUpperTable_BkSlash, szNormName, szFileName, cchMaxChars);
}
size_t NormalizeFileName_LowerSlash(char * szNormName, const char * szFileName, size_t cchMaxChars)
{
return NormalizeFileName(AsciiToLowerTable_Slash, szNormName, szFileName, cchMaxChars);
}
ULONGLONG CalcFileNameHash(const char * szFileName)
{
char szNormName[MAX_PATH+1];
uint32_t dwHashHigh = 0;
uint32_t dwHashLow = 0;
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;
}
int ConvertDigitToInt32(const TCHAR * szString, PDWORD PtrValue)
{
BYTE Digit;
Digit = (BYTE)(AsciiToUpperTable_BkSlash[szString[0]] - _T('0'));
if(Digit > 9)
Digit -= 'A' - '9' - 1;
PtrValue[0] = Digit;
return (Digit > 0x0F) ? ERROR_BAD_FORMAT : ERROR_SUCCESS;
}
int ConvertStringToInt08(const char * szString, PDWORD PtrValue)
{
BYTE DigitOne = AsciiToUpperTable_BkSlash[szString[0]] - '0';
BYTE DigitTwo = AsciiToUpperTable_BkSlash[szString[1]] - '0';
// Fix the digits
if(DigitOne > 9)
DigitOne -= 'A' - '9' - 1;
if(DigitTwo > 9)
DigitTwo -= 'A' - '9' - 1;
// Combine them into a value
PtrValue[0] = (DigitOne << 0x04) | DigitTwo;
return (DigitOne <= 0x0F && DigitTwo <= 0x0F) ? ERROR_SUCCESS : ERROR_BAD_FORMAT;
}
int ConvertStringToInt32(const TCHAR * szString, size_t nMaxDigits, PDWORD PtrValue)
{
// The number of digits must be even
assert((nMaxDigits & 0x01) == 0);
assert(nMaxDigits <= 8);
// Prepare the variables
PtrValue[0] = 0;
nMaxDigits >>= 1;
// Convert the string up to the number of digits
for(size_t i = 0; i < nMaxDigits; i++)
{
BYTE DigitOne;
BYTE DigitTwo;
DigitOne = (BYTE)(AsciiToUpperTable_BkSlash[szString[0]] - _T('0'));
if(DigitOne > 9)
DigitOne -= 'A' - '9' - 1;
DigitTwo = (BYTE)(AsciiToUpperTable_BkSlash[szString[1]] - _T('0'));
if(DigitTwo > 9)
DigitTwo -= 'A' - '9' - 1;
if(DigitOne > 0x0F || DigitTwo > 0x0F)
return ERROR_BAD_FORMAT;
PtrValue[0] = (PtrValue[0] << 0x08) | (DigitOne << 0x04) | DigitTwo;
szString += 2;
}
return ERROR_SUCCESS;
}
// Converts string blob to binary blob.
int ConvertStringToBinary(
const char * szString,
size_t nMaxDigits,
LPBYTE pbBinary)
{
const char * szStringEnd = szString + nMaxDigits;
DWORD dwCounter = 0;
BYTE DigitValue;
BYTE ByteValue = 0;
// Convert the string
while(szString < szStringEnd)
{
// Retrieve the digit converted to hexa
DigitValue = (BYTE)(AsciiToUpperTable_BkSlash[szString[0]] - '0');
if(DigitValue > 9)
DigitValue -= 'A' - '9' - 1;
if(DigitValue > 0x0F)
return ERROR_BAD_FORMAT;
// Insert the digit to the binary buffer
ByteValue = (ByteValue << 0x04) | DigitValue;
dwCounter++;
// If we reached the second digit, it means that we need
// to flush the byte value and move on
if((dwCounter & 0x01) == 0)
*pbBinary++ = ByteValue;
szString++;
}
return ERROR_SUCCESS;
}
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++)
{
*szBuffer++ = IntToHexChar[pbBinary[0] >> 0x04];
*szBuffer++ = IntToHexChar[pbBinary[0] & 0x0F];
pbBinary++;
}
// Terminate the string
*szBuffer = 0;
return szSaveBuffer;
}
char * StringFromMD5(LPBYTE md5, char * szBuffer)
{
return StringFromBinary(md5, MD5_HASH_SIZE, szBuffer);
}
//-----------------------------------------------------------------------------
// File name utilities
const wchar_t * GetPlainFileName(const wchar_t * szFileName)
{
const wchar_t * szPlainName = szFileName;
while(*szFileName != 0)
{
if(*szFileName == '\\' || *szFileName == '/')
szPlainName = szFileName + 1;
szFileName++;
}
return szPlainName;
}
const char * GetPlainFileName(const char * szFileName)
{
const char * szPlainName = szFileName;
while(*szFileName != 0)
{
if(*szFileName == '\\' || *szFileName == '/')
szPlainName = szFileName + 1;
szFileName++;
}
return szPlainName;
}
bool CheckWildCard(const char * szString, const char * szWildCard)
{
const char * szWildCardPtr;
for(;;)
{
// If there is '?' in the wildcard, we skip one char
while(szWildCard[0] == '?')
{
if(szString[0] == 0)
return false;
szWildCard++;
szString++;
}
// Handle '*'
szWildCardPtr = szWildCard;
if(szWildCardPtr[0] != 0)
{
if(szWildCardPtr[0] == '*')
{
szWildCardPtr++;
if(szWildCardPtr[0] == '*')
continue;
if(szWildCardPtr[0] == 0)
return true;
if(AsciiToUpperTable_BkSlash[szWildCardPtr[0]] == AsciiToUpperTable_BkSlash[szString[0]])
{
if(CheckWildCard(szString, szWildCardPtr))
return true;
}
}
else
{
if(AsciiToUpperTable_BkSlash[szWildCardPtr[0]] != AsciiToUpperTable_BkSlash[szString[0]])
return false;
szWildCard = szWildCardPtr + 1;
}
if(szString[0] == 0)
return false;
szString++;
}
else
{
return (szString[0] == 0) ? true : false;
}
}
}
//-----------------------------------------------------------------------------
// Hashing functions
bool IsValidMD5(LPBYTE pbMd5)
{
BYTE BitSummary = 0;
// 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);
}
bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5)
{
hash_state md5_state;
BYTE md5_digest[MD5_HASH_SIZE];
// Don't verify the block if the MD5 is not valid.
if(!IsValidMD5(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);
// 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)
{
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 */
}
/* 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 */
}

View File

@@ -0,0 +1,89 @@
/*****************************************************************************/
/* CascCommon.h Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* Common functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 29.04.14 1.00 Lad The first version of CascCommon.h */
/*****************************************************************************/
#ifndef __COMMON_H__
#define __COMMON_H__
//-----------------------------------------------------------------------------
// Common macros
// Macro for building 64-bit file offset from two 32-bit
#define MAKE_OFFSET64(hi, lo) (((ULONGLONG)hi << 32) | (ULONGLONG)lo)
#ifndef ALIGN_TO_SIZE
#define ALIGN_TO_SIZE(x, a) (((x) + (a)-1) & ~((a)-1))
#endif
//-----------------------------------------------------------------------------
// Conversion tables
extern unsigned char AsciiToLowerTable_Slash[256];
extern unsigned char AsciiToUpperTable_BkSlash[256];
extern unsigned char IntToHexChar[];
//-----------------------------------------------------------------------------
// String manipulation
void CopyString(char * szTarget, const char * szSource, size_t cchLength);
void CopyString(wchar_t * szTarget, const char * szSource, size_t cchLength);
void CopyString(char * szTarget, const wchar_t * szSource, size_t cchLength);
char * CascNewStr(const char * szString, size_t nCharsToReserve);
wchar_t * CascNewStr(const wchar_t * szString, size_t nCharsToReserve);
TCHAR * CascNewStrFromAnsi(const char * szBegin, const char * szEnd);
TCHAR * CombinePath(const TCHAR * szPath, const TCHAR * szSubDir);
TCHAR * CombinePathAndString(const TCHAR * szPath, const char * szString, size_t nLength);
size_t NormalizeFileName_UpperBkSlash(char * szNormName, const char * szFileName, size_t cchMaxChars);
size_t NormalizeFileName_LowerSlash(char * szNormName, const char * szFileName, size_t cchMaxChars);
ULONGLONG CalcFileNameHash(const char * szFileName);
int ConvertDigitToInt32(const TCHAR * szString, PDWORD PtrValue);
int ConvertStringToInt08(const char * szString, PDWORD PtrValue);
int ConvertStringToInt32(const TCHAR * szString, size_t nMaxDigits, PDWORD PtrValue);
int ConvertStringToBinary(const char * szString, size_t nMaxDigits, LPBYTE pbBinary);
char * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, char * szBuffer);
char * StringFromMD5(LPBYTE md5, char * szBuffer);
//-----------------------------------------------------------------------------
// File name utilities
bool CheckWildCard(const char * szString, const char * szWildCard);
const wchar_t * GetPlainFileName(const wchar_t * szFileName);
const char * GetPlainFileName(const char * szFileName);
//-----------------------------------------------------------------------------
// Hashing functions
ULONGLONG HashStringJenkins(const char * szFileName);
bool IsValidMD5(LPBYTE pbMd5);
void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash);
bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5);
//-----------------------------------------------------------------------------
// Scanning a directory
typedef bool (*INDEX_FILE_FOUND)(const TCHAR * szFileName, PDWORD IndexArray, PDWORD OldIndexArray, void * pvContext);
bool DirectoryExists(const TCHAR * szDirectory);
int ScanIndexDirectory(
const TCHAR * szIndexPath,
INDEX_FILE_FOUND pfnOnFileFound,
PDWORD IndexArray,
PDWORD OldIndexArray,
void * pvContext
);
#endif // __COMMON_H__

View File

@@ -0,0 +1,102 @@
/*****************************************************************************/
/* Directory.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* System-dependent directory functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 29.04.14 1.00 Lad The first version of Directory.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "../CascLib.h"
#include "../CascCommon.h"
//-----------------------------------------------------------------------------
// Public functions
bool DirectoryExists(const TCHAR * szDirectory)
{
#ifdef PLATFORM_WINDOWS
DWORD dwAttributes = GetFileAttributes(szDirectory);
if((dwAttributes != INVALID_FILE_ATTRIBUTES) && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY))
return true;
#else // PLATFORM_WINDOWS
DIR * dir = opendir(szDirectory);
if(dir != NULL)
{
closedir(dir);
return true;
}
#endif
return false;
}
int ScanIndexDirectory(
const TCHAR * szIndexPath,
INDEX_FILE_FOUND pfnOnFileFound,
PDWORD MainIndexes,
PDWORD OldIndexArray,
void * pvContext)
{
#ifdef PLATFORM_WINDOWS
WIN32_FIND_DATA wf;
TCHAR * szSearchMask;
HANDLE hFind;
// Prepare the search mask
szSearchMask = CombinePath(szIndexPath, _T("*"));
if(szSearchMask == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Prepare directory search
hFind = FindFirstFile(szSearchMask, &wf);
if(hFind != INVALID_HANDLE_VALUE)
{
// Skip the first file as it's always just "." or ".."
while(FindNextFile(hFind, &wf))
{
// If the found object is a file, pass it to the handler
if(!(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
// Let the callback scan the file name
pfnOnFileFound(wf.cFileName, MainIndexes, OldIndexArray, pvContext);
}
}
// Close the search handle
FindClose(hFind);
}
CASC_FREE(szSearchMask);
#else // PLATFORM_WINDOWS
struct dirent * dir_entry;
DIR * dir;
dir = opendir(szIndexPath);
if(dir != NULL)
{
while((dir_entry = readdir(dir)) != NULL)
{
if(dir_entry->d_type != DT_DIR)
{
pfnOnFileFound(dir_entry->d_name, MainIndexes, OldIndexArray, pvContext);
}
}
closedir(dir);
}
#endif
return ERROR_SUCCESS;
}

View File

@@ -0,0 +1,29 @@
/*****************************************************************************/
/* Directory.h Copyright (c) Ladislav Zezula 2015 */
/*---------------------------------------------------------------------------*/
/* Directory functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 30.10.15 1.00 Lad The first version of Directory.h */
/*****************************************************************************/
#ifndef __DIRECTORY_H__
#define __DIRECTORY_H__
//-----------------------------------------------------------------------------
// Scanning a directory
typedef bool (*INDEX_FILE_FOUND)(const TCHAR * szFileName, PDWORD IndexArray, PDWORD OldIndexArray, void * pvContext);
bool DirectoryExists(const TCHAR * szDirectory);
int ScanIndexDirectory(
const TCHAR * szIndexPath,
INDEX_FILE_FOUND pfnOnFileFound,
PDWORD IndexArray,
PDWORD OldIndexArray,
void * pvContext
);
#endif // __DIRECTORY_H__

View File

@@ -0,0 +1,153 @@
/*****************************************************************************/
/* DumpContext.cpp Copyright (c) Ladislav Zezula 2015 */
/*---------------------------------------------------------------------------*/
/* Implementation of dump context */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 16.03.15 1.00 Lad Created */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "../CascLib.h"
#include "../CascCommon.h"
//-----------------------------------------------------------------------------
// Local functions
static TCHAR * FormatFileName(TCascStorage * hs, const TCHAR * szNameFormat)
{
TCHAR * szFileName;
TCHAR * szSrc;
TCHAR * szTrg;
// Create copy of the file name
szFileName = szSrc = szTrg = CascNewStr(szNameFormat, 0);
if(szFileName != NULL)
{
// Format the file name
while(szSrc[0] != 0)
{
if(szSrc[0] == _T('%'))
{
// Replace "%build%" with a build number
if(!_tcsncmp(szSrc, _T("%build%"), 7))
{
szTrg += _stprintf(szTrg, _T("%u"), hs->dwBuildNumber);
szSrc += 7;
continue;
}
}
// Just copy the character
*szTrg++ = *szSrc++;
}
// Terminate the target file name
szTrg[0] = 0;
}
return szFileName;
}
//-----------------------------------------------------------------------------
// Public functions
TDumpContext * CreateDumpContext(TCascStorage * hs, const TCHAR * szNameFormat)
{
TDumpContext * dc;
TCHAR * szFileName;
// Validate the storage handle
if(hs != NULL)
{
// Calculate the number of bytes needed for dump context
dc = CASC_ALLOC(TDumpContext, 1);
if(dc != NULL)
{
// Initialize the dump context
memset(dc, 0, sizeof(TDumpContext));
// Format the real file name
szFileName = FormatFileName(hs, szNameFormat);
if(szFileName != NULL)
{
// Create the file
dc->pStream = FileStream_CreateFile(szFileName, 0);
if(dc->pStream != NULL)
{
// Initialize buffers
dc->pbBufferBegin =
dc->pbBufferPtr = dc->DumpBuffer;
dc->pbBufferEnd = dc->DumpBuffer + CASC_DUMP_BUFFER_SIZE;
// Success
CASC_FREE(szFileName);
return dc;
}
// File create failed --> delete the file name
CASC_FREE(szFileName);
}
// Free the dump context
CASC_FREE(dc);
}
}
return NULL;
}
int dump_print(TDumpContext * dc, const char * szFormat, ...)
{
va_list argList;
char szBuffer[0x200];
int nLength = 0;
// Only if the dump context is valid
if(dc != NULL)
{
// Print the buffer using sprintf
va_start(argList, szFormat);
nLength = vsprintf(szBuffer, szFormat, argList);
assert(nLength < 0x200);
va_end(argList);
// Copy the string. Replace "\n" with "\n\r"
for(int i = 0; i < nLength; i++)
{
// Flush the buffer, if needed
if((dc->pbBufferPtr + 2) >= dc->pbBufferEnd)
{
FileStream_Write(dc->pStream, NULL, dc->pbBufferBegin, (DWORD)(dc->pbBufferPtr - dc->pbBufferBegin));
dc->pbBufferPtr = dc->pbBufferBegin;
}
// Copy the char
if(szBuffer[i] == 0x0A)
*dc->pbBufferPtr++ = 0x0D;
*dc->pbBufferPtr++ = szBuffer[i];
}
}
return nLength;
}
int dump_close(TDumpContext * dc)
{
// Only if the dump context is valid
if(dc != NULL)
{
// Flush the dump context if there are some data
if(dc->pbBufferPtr > dc->pbBufferBegin)
FileStream_Write(dc->pStream, NULL, dc->pbBufferBegin, (DWORD)(dc->pbBufferPtr - dc->pbBufferBegin));
dc->pbBufferPtr = dc->pbBufferBegin;
// Free the file stream and the entire context
if(dc->pStream != NULL)
FileStream_Close(dc->pStream);
CASC_FREE(dc);
}
return 0;
}

View File

@@ -0,0 +1,38 @@
/*****************************************************************************/
/* DumpContext.h Copyright (c) Ladislav Zezula 2015 */
/*---------------------------------------------------------------------------*/
/* Interface for TDumpContext */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 16.03.15 1.00 Lad Created */
/*****************************************************************************/
#ifndef __DUMP_CONTEXT_H__
#define __DUMP_CONTEXT_H__
//-----------------------------------------------------------------------------
// Defines
// Size of the buffer for the dump context
#define CASC_DUMP_BUFFER_SIZE 0x10000
// Structure for dump context
struct TDumpContext
{
TFileStream * pStream; // Pointer to the open stream
LPBYTE pbBufferBegin; // Begin of the dump buffer
LPBYTE pbBufferPtr; // Current dump buffer pointer
LPBYTE pbBufferEnd; // End of the dump buffer
BYTE DumpBuffer[CASC_DUMP_BUFFER_SIZE]; // Dump buffer
};
//-----------------------------------------------------------------------------
// Dump context functions
TDumpContext * CreateDumpContext(struct _TCascStorage * hs, const TCHAR * szNameFormat);
int dump_print(TDumpContext * dc, const char * szFormat, ...);
int dump_close(TDumpContext * dc);
#endif // __DUMP_CONTEXT_H__

View File

@@ -0,0 +1,101 @@
/*****************************************************************************/
/* DynamicArray.cpp Copyright (c) Ladislav Zezula 2015 */
/*---------------------------------------------------------------------------*/
/* Description: */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 30.10.15 1.00 Lad The first version of DynamicArray.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "../CascLib.h"
#include "../CascCommon.h"
//-----------------------------------------------------------------------------
// Local functions
static bool EnlargeArray(PDYNAMIC_ARRAY pArray, size_t NewItemCount)
{
char * NewItemArray;
size_t ItemCountMax;
// We expect the array to be already allocated
assert(pArray->ItemArray != NULL);
assert(pArray->ItemCountMax != 0);
// Shall we enlarge the table?
if(NewItemCount > pArray->ItemCountMax)
{
// Calculate new table size
ItemCountMax = pArray->ItemCountMax;
while(ItemCountMax < NewItemCount)
ItemCountMax = ItemCountMax << 1;
// Allocate new table
NewItemArray = CASC_REALLOC(char, pArray->ItemArray, pArray->ItemSize * ItemCountMax);
if(NewItemArray == NULL)
return false;
// Set the new table size
pArray->ItemCountMax = ItemCountMax;
pArray->ItemArray = NewItemArray;
}
return true;
}
//-----------------------------------------------------------------------------
// Public functions
int Array_Create_(PDYNAMIC_ARRAY pArray, size_t ItemSize, size_t ItemCountMax)
{
pArray->ItemArray = CASC_ALLOC(char, (ItemSize * ItemCountMax));
if(pArray->ItemArray == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
pArray->ItemCountMax = ItemCountMax;
pArray->ItemCount = 0;
pArray->ItemSize = ItemSize;
return ERROR_SUCCESS;
}
void * Array_Insert(PDYNAMIC_ARRAY pArray, const void * NewItems, size_t NewItemCount)
{
char * NewItemPtr;
// Try to enlarge the buffer, if needed
if(!EnlargeArray(pArray, pArray->ItemCount + NewItemCount))
return NULL;
NewItemPtr = pArray->ItemArray + (pArray->ItemCount * pArray->ItemSize);
// Copy the old item(s), if any
if(NewItems != NULL)
memcpy(NewItemPtr, NewItems, (NewItemCount * pArray->ItemSize));
// Increment the size of the array
pArray->ItemCount += NewItemCount;
return NewItemPtr;
}
void * Array_ItemAt(PDYNAMIC_ARRAY pArray, size_t ItemIndex)
{
assert(ItemIndex < pArray->ItemCount);
return pArray->ItemArray + (ItemIndex * pArray->ItemSize);
}
size_t Array_IndexOf(PDYNAMIC_ARRAY pArray, const void * ArrayPtr)
{
char * ArrayItem = (char *)ArrayPtr;
assert(pArray->ItemArray <= ArrayItem && ArrayItem <= pArray->ItemArray + (pArray->ItemCount * pArray->ItemSize));
return ((ArrayItem - pArray->ItemArray) / pArray->ItemSize);
}
void Array_Free(PDYNAMIC_ARRAY pArray)
{
if(pArray != NULL && pArray->ItemArray != NULL)
{
CASC_FREE(pArray->ItemArray);
}
}

View File

@@ -0,0 +1,37 @@
/*****************************************************************************/
/* DynamicArray.h Copyright (c) Ladislav Zezula 2015 */
/*---------------------------------------------------------------------------*/
/* Common array implementation */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 30.10.15 1.00 Lad The first version of DynamicArray.h */
/*****************************************************************************/
#ifndef __DYNAMIC_ARRAY_H__
#define __DYNAMIC_ARRAY_H__
//-----------------------------------------------------------------------------
// Structures
typedef struct _DYNAMIC_ARRAY
{
char * ItemArray; // Pointer to items
size_t ItemCountMax; // Current number of items
size_t ItemCount; // Total size of the buffer
size_t ItemSize; // Size of the single item
} DYNAMIC_ARRAY, *PDYNAMIC_ARRAY;
//-----------------------------------------------------------------------------
// Functions for managing the array
int Array_Create_(PDYNAMIC_ARRAY pArray, size_t ItemSize, size_t ItemCountMax);
void * Array_Insert(PDYNAMIC_ARRAY pArray, const void * NewItems, size_t NewItemCount);
void * Array_ItemAt(PDYNAMIC_ARRAY pArray, size_t ItemIndex);
size_t Array_IndexOf(PDYNAMIC_ARRAY pArray, const void * ArrayPtr);
void Array_Free(PDYNAMIC_ARRAY pArray);
#define Array_Create(pArray, type, ItemCountMax) Array_Create_(pArray, sizeof(type), ItemCountMax)
#endif // __DYNAMIC_ARRAY__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,260 @@
/*****************************************************************************/
/* FileStream.h Copyright (c) Ladislav Zezula 2012 */
/*---------------------------------------------------------------------------*/
/* Description: Definitions for FileStream object */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 14.04.12 1.00 Lad The first version of FileStream.h */
/*****************************************************************************/
#ifndef __FILESTREAM_H__
#define __FILESTREAM_H__
//-----------------------------------------------------------------------------
// Flags for file stream
#define BASE_PROVIDER_FILE 0x00000000 // Base data source is a file
#define BASE_PROVIDER_MAP 0x00000001 // Base data source is memory-mapped file
#define BASE_PROVIDER_HTTP 0x00000002 // Base data source is a file on web server
#define BASE_PROVIDER_MASK 0x0000000F // Mask for base provider value
#define STREAM_PROVIDER_FLAT 0x00000000 // Stream is linear with no offset mapping
#define STREAM_PROVIDER_PARTIAL 0x00000010 // Stream is partial file (.part)
#define STREAM_PROVIDER_ENCRYPTED 0x00000020 // Stream is an encrypted archive
#define STREAM_PROVIDER_BLOCK4 0x00000030 // 0x4000 per block, text MD5 after each block, max 0x2000 blocks per file
#define STREAM_PROVIDER_MASK 0x000000F0 // Mask for stream provider value
#define STREAM_FLAG_READ_ONLY 0x00000100 // Stream is read only
#define STREAM_FLAG_WRITE_SHARE 0x00000200 // Allow write sharing when open for write
#define STREAM_FLAG_USE_BITMAP 0x00000400 // If the file has a file bitmap, load it and use it
#define STREAM_OPTIONS_MASK 0x0000FF00 // Mask for stream options
#define STREAM_PROVIDERS_MASK 0x000000FF // Mask to get stream providers
#define STREAM_FLAGS_MASK 0x0000FFFF // Mask for all stream flags (providers+options)
//-----------------------------------------------------------------------------
// Function prototypes
typedef void (*STREAM_INIT)(
struct TFileStream * pStream // Pointer to an unopened stream
);
typedef bool (*STREAM_CREATE)(
struct TFileStream * pStream // Pointer to an unopened stream
);
typedef bool (*STREAM_OPEN)(
struct TFileStream * pStream, // Pointer to an unopened stream
const TCHAR * szFileName, // Pointer to file name to be open
DWORD dwStreamFlags // Stream flags
);
typedef bool (*STREAM_READ)(
struct TFileStream * pStream, // Pointer to an open stream
ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
void * pvBuffer, // Pointer to data to be read
DWORD dwBytesToRead // Number of bytes to read from the file
);
typedef bool (*STREAM_WRITE)(
struct TFileStream * pStream, // Pointer to an open stream
ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it writes to the current position
const void * pvBuffer, // Pointer to data to be written
DWORD dwBytesToWrite // Number of bytes to read from the file
);
typedef bool (*STREAM_RESIZE)(
struct TFileStream * pStream, // Pointer to an open stream
ULONGLONG FileSize // New size for the file, in bytes
);
typedef bool (*STREAM_GETSIZE)(
struct TFileStream * pStream, // Pointer to an open stream
ULONGLONG * pFileSize // Receives the file size, in bytes
);
typedef bool (*STREAM_GETPOS)(
struct TFileStream * pStream, // Pointer to an open stream
ULONGLONG * pByteOffset // Pointer to store current file position
);
typedef void (*STREAM_CLOSE)(
struct TFileStream * pStream // Pointer to an open stream
);
typedef bool (*BLOCK_READ)(
struct TFileStream * pStream, // Pointer to a block-oriented stream
ULONGLONG StartOffset, // Byte offset of start of the block array
ULONGLONG EndOffset, // End offset (either end of the block or end of the file)
LPBYTE BlockBuffer, // Pointer to block-aligned buffer
DWORD BytesNeeded, // Number of bytes that are really needed
bool bAvailable // true if the block is available
);
typedef bool (*BLOCK_CHECK)(
struct TFileStream * pStream, // Pointer to a block-oriented stream
ULONGLONG BlockOffset // Offset of the file to check
);
typedef void (*BLOCK_SAVEMAP)(
struct TFileStream * pStream // Pointer to a block-oriented stream
);
//-----------------------------------------------------------------------------
// Local structures - partial file structure and bitmap footer
#define ID_FILE_BITMAP_FOOTER 0x33767470 // Signature of the file bitmap footer ('ptv3')
#define DEFAULT_BLOCK_SIZE 0x00004000 // Default size of the stream block
#define DEFAULT_BUILD_NUMBER 10958 // Build number for newly created partial MPQs
typedef struct _PART_FILE_HEADER
{
DWORD PartialVersion; // Always set to 2
char GameBuildNumber[0x20]; // Minimum build number of the game that can use this MPQ
DWORD Flags; // Flags (details unknown)
DWORD FileSizeLo; // Low 32 bits of the contained file size
DWORD FileSizeHi; // High 32 bits of the contained file size
DWORD BlockSize; // Size of one file block, in bytes
} PART_FILE_HEADER, *PPART_FILE_HEADER;
// Structure describing the block-to-file map entry
typedef struct _PART_FILE_MAP_ENTRY
{
DWORD Flags; // 3 = the block is present in the file
DWORD BlockOffsLo; // Low 32 bits of the block position in the file
DWORD BlockOffsHi; // High 32 bits of the block position in the file
DWORD LargeValueLo; // 64-bit value, meaning is unknown
DWORD LargeValueHi;
} PART_FILE_MAP_ENTRY, *PPART_FILE_MAP_ENTRY;
typedef struct _FILE_BITMAP_FOOTER
{
DWORD Signature; // 'ptv3' (ID_FILE_BITMAP_FOOTER)
DWORD Version; // Unknown, seems to always have value of 3 (version?)
DWORD BuildNumber; // Game build number for that MPQ
DWORD MapOffsetLo; // Low 32-bits of the offset of the bit map
DWORD MapOffsetHi; // High 32-bits of the offset of the bit map
DWORD BlockSize; // Size of one block (usually 0x4000 bytes)
} FILE_BITMAP_FOOTER, *PFILE_BITMAP_FOOTER;
//-----------------------------------------------------------------------------
// Structure for file stream
union TBaseProviderData
{
struct
{
ULONGLONG FileSize; // Size of the file
ULONGLONG FilePos; // Current file position
ULONGLONG FileTime; // Last write time
HANDLE hFile; // File handle
} File;
struct
{
ULONGLONG FileSize; // Size of the file
ULONGLONG FilePos; // Current file position
ULONGLONG FileTime; // Last write time
LPBYTE pbFile; // Pointer to mapped view
} Map;
struct
{
ULONGLONG FileSize; // Size of the file
ULONGLONG FilePos; // Current file position
ULONGLONG FileTime; // Last write time
HANDLE hInternet; // Internet handle
HANDLE hConnect; // Connection to the internet server
} Http;
};
struct TFileStream
{
// Stream provider functions
STREAM_READ StreamRead; // Pointer to stream read function for this archive. Do not use directly.
STREAM_WRITE StreamWrite; // Pointer to stream write function for this archive. Do not use directly.
STREAM_RESIZE StreamResize; // Pointer to function changing file size
STREAM_GETSIZE StreamGetSize; // Pointer to function returning file size
STREAM_GETPOS StreamGetPos; // Pointer to function that returns current file position
STREAM_CLOSE StreamClose; // Pointer to function closing the stream
// Block-oriented functions
BLOCK_READ BlockRead; // Pointer to function reading one or more blocks
BLOCK_CHECK BlockCheck; // Pointer to function checking whether the block is present
// Base provider functions
STREAM_CREATE BaseCreate; // Pointer to base create function
STREAM_OPEN BaseOpen; // Pointer to base open function
STREAM_READ BaseRead; // Read from the stream
STREAM_WRITE BaseWrite; // Write to the stream
STREAM_RESIZE BaseResize; // Pointer to function changing file size
STREAM_GETSIZE BaseGetSize; // Pointer to function returning file size
STREAM_GETPOS BaseGetPos; // Pointer to function that returns current file position
STREAM_CLOSE BaseClose; // Pointer to function closing the stream
// Base provider data (file size, file position)
TBaseProviderData Base;
// Stream provider data
TFileStream * pMaster; // Master stream (e.g. MPQ on a web server)
TCHAR * szFileName; // File name (self-relative pointer)
ULONGLONG StreamSize; // Stream size (can be less than file size)
ULONGLONG StreamPos; // Stream position
DWORD BuildNumber; // Game build number
DWORD dwFlags; // Stream flags
// Followed by stream provider data, with variable length
};
//-----------------------------------------------------------------------------
// Structures for block-oriented stream
struct TBlockStream : public TFileStream
{
STREAM_DOWNLOAD_CALLBACK pfnCallback; // Callback for downloading
void * FileBitmap; // Array of bits for file blocks
void * UserData; // User data to be passed to the download callback
DWORD BitmapSize; // Size of the file bitmap (in bytes)
DWORD BlockSize; // Size of one block, in bytes
DWORD BlockCount; // Number of data blocks in the file
DWORD IsComplete; // If nonzero, no blocks are missing
DWORD IsModified; // nonzero if the bitmap has been modified
};
//-----------------------------------------------------------------------------
// Structure for encrypted stream
#define ENCRYPTED_CHUNK_SIZE 0x40 // Size of one chunk to be decrypted
struct TEncryptedStream : public TBlockStream
{
BYTE Key[ENCRYPTED_CHUNK_SIZE]; // File key
};
//-----------------------------------------------------------------------------
// Public functions for file stream
TFileStream * FileStream_CreateFile(const TCHAR * szFileName, DWORD dwStreamFlags);
TFileStream * FileStream_OpenFile(const TCHAR * szFileName, DWORD dwStreamFlags);
const TCHAR * FileStream_GetFileName(TFileStream * pStream);
size_t FileStream_Prefix(const TCHAR * szFileName, DWORD * pdwProvider);
bool FileStream_SetCallback(TFileStream * pStream, STREAM_DOWNLOAD_CALLBACK pfnCallback, void * pvUserData);
bool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead);
bool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite);
bool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize);
bool FileStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize);
bool FileStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset);
bool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFT);
bool FileStream_GetFlags(TFileStream * pStream, PDWORD pdwStreamFlags);
bool FileStream_Replace(TFileStream * pStream, TFileStream * pNewStream);
void FileStream_Close(TFileStream * pStream);
#endif // __FILESTREAM_H__

View File

@@ -0,0 +1,360 @@
/*****************************************************************************/
/* ListFile.cpp Copyright (c) Ladislav Zezula 2004 */
/*---------------------------------------------------------------------------*/
/* Description: */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 12.06.04 1.00 Lad The first version of ListFile.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "../CascLib.h"
#include "../CascCommon.h"
//-----------------------------------------------------------------------------
// Listfile cache structure
typedef struct _LISTFILE_CACHE
{
char * pBegin; // The begin of the listfile cache
char * pPos; // Current position in the cache
char * pEnd; // The last character in the file cache
// Followed by the cache (variable length)
} LISTFILE_CACHE, *PLISTFILE_CACHE;
//-----------------------------------------------------------------------------
// Creating the listfile cache for the given amount of data
static PLISTFILE_CACHE CreateListFileCache(DWORD dwFileSize)
{
PLISTFILE_CACHE pCache;
// Allocate cache for one file block
pCache = (PLISTFILE_CACHE)CASC_ALLOC(BYTE, sizeof(LISTFILE_CACHE) + dwFileSize);
if(pCache != NULL)
{
// Set the initial pointers
pCache->pBegin =
pCache->pPos = (char *)(pCache + 1);
pCache->pEnd = pCache->pBegin + dwFileSize;
}
// Return the cache
return pCache;
}
//-----------------------------------------------------------------------------
// Functions for parsing an external listfile
void * ListFile_OpenExternal(const TCHAR * szListFile)
{
PLISTFILE_CACHE pCache = NULL;
TFileStream * pStream;
ULONGLONG FileSize = 0;
// Open the external listfile
pStream = FileStream_OpenFile(szListFile, STREAM_FLAG_READ_ONLY);
if(pStream != NULL)
{
// Retrieve the size of the external listfile
FileStream_GetSize(pStream, &FileSize);
if(0 < FileSize && FileSize <= 0x30000000)
{
// Create the in-memory cache for the entire listfile
// The listfile does not have any data loaded yet
pCache = CreateListFileCache((DWORD)FileSize);
if(pCache != NULL)
{
if(!FileStream_Read(pStream, NULL, pCache->pBegin, (DWORD)FileSize))
{
ListFile_Free(pCache);
pCache = NULL;
}
}
}
// Close the file stream
FileStream_Close(pStream);
}
return pCache;
}
void * ListFile_FromBuffer(LPBYTE pbBuffer, DWORD cbBuffer)
{
PLISTFILE_CACHE pCache = NULL;
// Create the in-memory cache for the entire listfile
// The listfile does not have any data loaded yet
pCache = CreateListFileCache(cbBuffer);
if(pCache != NULL)
memcpy(pCache->pBegin, pbBuffer, cbBuffer);
return pCache;
}
// Performs the MD5-based check on the listfile
bool ListFile_VerifyMD5(void * pvListFile, LPBYTE pbHashMD5)
{
PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile;
// Must be at the beginning
assert(pCache->pPos == pCache->pBegin);
// Verify the MD5 hash for the entire block
return VerifyDataBlockHash(pCache->pBegin, (DWORD)(pCache->pEnd - pCache->pBegin), pbHashMD5);
}
size_t ListFile_GetNextLine(void * pvListFile, const char ** pszLineBegin, const char ** pszLineEnd)
{
PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile;
char * szExtraString = NULL;
char * szLineBegin;
char * szLineEnd;
// Skip newlines, spaces, tabs and another non-printable stuff
while(pCache->pPos < pCache->pEnd && pCache->pPos[0] <= 0x20)
pCache->pPos++;
// Remember the begin of the line
szLineBegin = pCache->pPos;
// Copy the remaining characters
while(pCache->pPos < pCache->pEnd)
{
// If we have found a newline, stop loading
if(pCache->pPos[0] == 0x0D || pCache->pPos[0] == 0x0A)
break;
// Blizzard listfiles can also contain information about patch:
// Pass1\Files\MacOS\unconditional\user\Background Downloader.app\Contents\Info.plist~Patch(Data#frFR#base-frFR,1326)
if(pCache->pPos[0] == '~')
szExtraString = pCache->pPos;
// Move the position by one character forward
pCache->pPos++;
}
// Remember the end of the line
szLineEnd = (szExtraString != NULL && szExtraString[0] == '~' && szExtraString[1] == 'P') ? szExtraString : pCache->pPos;
// Give the caller the positions of the begin and end of the line
pszLineBegin[0] = szLineBegin;
pszLineEnd[0] = szLineEnd;
return (size_t)(szLineEnd - szLineBegin);
}
size_t ListFile_GetNextLine(void * pvListFile, char * szBuffer, size_t nMaxChars)
{
const char * szLineBegin = NULL;
const char * szLineEnd = NULL;
size_t nLength;
// Retrieve the next line
nLength = ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd);
// Check the length
if(nLength > nMaxChars)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
// Copy the line to the user buffer
memcpy(szBuffer, szLineBegin, nLength);
szBuffer[nLength] = 0;
return nLength;
}
size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, size_t nMaxChars)
{
size_t nLength = 0;
int nError = ERROR_SUCCESS;
// Check for parameters
for(;;)
{
// Read the (next) line
nLength = ListFile_GetNextLine(pvListFile, szBuffer, nMaxChars);
if(nLength == 0)
{
nError = ERROR_NO_MORE_FILES;
break;
}
// If some mask entered, check it
if(CheckWildCard(szBuffer, szMask))
{
nError = ERROR_SUCCESS;
break;
}
}
if(nError != ERROR_SUCCESS)
SetLastError(nError);
return nLength;
}
void ListFile_Free(void * pvListFile)
{
if(pvListFile != NULL)
{
CASC_FREE(pvListFile);
}
}
//-----------------------------------------------------------------------------
// Functions for creating a listfile map
#define LISTMAP_INITIAL 0x100000
static PLISTFILE_MAP ListMap_Create()
{
PLISTFILE_MAP pListMap;
size_t cbToAllocate;
// Create buffer for the listfile
// Note that because the listfile is quite big and CASC_REALLOC
// is a costly operation, we want to have as few reallocs as possible.
cbToAllocate = sizeof(LISTFILE_MAP) + LISTMAP_INITIAL;
pListMap = (PLISTFILE_MAP)CASC_ALLOC(BYTE, cbToAllocate);
if(pListMap != NULL)
{
// Fill the listfile buffer
memset(pListMap, 0, sizeof(LISTFILE_MAP));
pListMap->cbBufferMax = LISTMAP_INITIAL;
}
return pListMap;
}
static PLISTFILE_MAP ListMap_InsertName(PLISTFILE_MAP pListMap, const char * szFileName, size_t nLength)
{
PLISTFILE_ENTRY pListEntry;
size_t cbToAllocate;
size_t cbEntrySize;
// Make sure there is enough space in the list map
cbEntrySize = sizeof(LISTFILE_ENTRY) + nLength;
cbEntrySize = ALIGN_TO_SIZE(cbEntrySize, 8);
if((pListMap->cbBuffer + cbEntrySize) > pListMap->cbBufferMax)
{
cbToAllocate = sizeof(LISTFILE_MAP) + (pListMap->cbBufferMax * 3) / 2;
pListMap = (PLISTFILE_MAP)CASC_REALLOC(BYTE, pListMap, cbToAllocate);
if(pListMap == NULL)
return NULL;
pListMap->cbBufferMax = (pListMap->cbBufferMax * 3) / 2;
}
// Get the pointer to the first entry
pListEntry = (PLISTFILE_ENTRY)((LPBYTE)(pListMap + 1) + pListMap->cbBuffer);
pListEntry->FileNameHash = CalcFileNameHash(szFileName);
pListEntry->cbEntrySize = (DWORD)cbEntrySize;
// Copy the file name to the entry
memcpy(pListEntry->szFileName, szFileName, nLength);
pListEntry->szFileName[nLength] = 0;
// Move the next entry
pListMap->cbBuffer += cbEntrySize;
pListMap->nEntries++;
return pListMap;
}
static PLISTFILE_MAP ListMap_Finish(PLISTFILE_MAP pListMap)
{
PLISTFILE_ENTRY pListEntry;
PCASC_MAP pMap;
LPBYTE pbEntry;
// Sanity check
assert(pListMap->pNameMap == NULL);
// Create the map
pListMap->pNameMap = pMap = Map_Create((DWORD)pListMap->nEntries, sizeof(ULONGLONG), 0);
if(pListMap->pNameMap == NULL)
{
ListFile_FreeMap(pListMap);
return NULL;
}
// Fill the map
pbEntry = (LPBYTE)(pListMap + 1);
for(size_t i = 0; i < pListMap->nEntries; i++)
{
// Get the listfile entry
pListEntry = (PLISTFILE_ENTRY)pbEntry;
pbEntry += pListEntry->cbEntrySize;
// Insert the entry to the map
Map_InsertObject(pMap, pListEntry, &pListEntry->FileNameHash);
}
return pListMap;
}
PLISTFILE_MAP ListFile_CreateMap(const TCHAR * szListFile)
{
PLISTFILE_MAP pListMap = NULL;
void * pvListFile;
char szFileName[MAX_PATH+1];
size_t nLength;
// Only if the listfile name has been given
if(szListFile != NULL)
{
// Create map for the listfile
pListMap = ListMap_Create();
if(pListMap != NULL)
{
// Open the external listfile
pvListFile = ListFile_OpenExternal(szListFile);
if(pvListFile != NULL)
{
// Go through the entire listfile and insert each name to the map
while((nLength = ListFile_GetNext(pvListFile, "*", szFileName, MAX_PATH)) != 0)
{
// Insert the file name to the map
pListMap = ListMap_InsertName(pListMap, szFileName, nLength);
if(pListMap == NULL)
break;
}
if(pListMap == NULL)
{
// Finish the listfile map
pListMap = ListMap_Finish(pListMap);
}
// Free the listfile
ListFile_Free(pvListFile);
}
}
}
// Return the created map
return pListMap;
}
const char * ListFile_FindName(PLISTFILE_MAP pListMap, ULONGLONG FileNameHash)
{
PLISTFILE_ENTRY pListEntry = NULL;
if(pListMap != NULL)
pListEntry = (PLISTFILE_ENTRY)Map_FindObject(pListMap->pNameMap, &FileNameHash, NULL);
return (pListEntry != NULL) ? pListEntry->szFileName : "";
}
void ListFile_FreeMap(PLISTFILE_MAP pListMap)
{
if(pListMap != NULL)
{
if(pListMap->pNameMap != NULL)
Map_Free(pListMap->pNameMap);
CASC_FREE(pListMap);
}
}

View File

@@ -0,0 +1,54 @@
/*****************************************************************************/
/* ListFile.h Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* Common functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 10.05.14 1.00 Lad The first version of ListFile.h */
/*****************************************************************************/
#ifndef __LISTFILE_H__
#define __LISTFILE_H__
//-----------------------------------------------------------------------------
// Structures
typedef struct _LISTFILE_ENTRY
{
ULONGLONG FileNameHash; // Hash of the file name
DWORD cbEntrySize; // Length of this entry, in bytes
char szFileName[1]; // File name, aligned to 8-byte boundary
} LISTFILE_ENTRY, *PLISTFILE_ENTRY;
typedef struct _LISTFILE_MAP
{
PCASC_MAP pNameMap; // Map of hash-to-name
size_t cbBufferMax; // Total size of the buffer, in bytes
size_t cbBuffer; // Current size of the buffer, in bytes
size_t nEntries; // Number of entries
// First LISTFILE_ENTRY starts here
} LISTFILE_MAP, *PLISTFILE_MAP;
//-----------------------------------------------------------------------------
// Functions for parsing an external listfile
void * ListFile_OpenExternal(const TCHAR * szListFile);
void * ListFile_FromBuffer(LPBYTE pbBuffer, DWORD cbBuffer);
bool ListFile_VerifyMD5(void * pvListFile, LPBYTE pbHashMD5);
size_t ListFile_GetNextLine(void * pvListFile, const char ** pszLineBegin, const char ** pszLineEnd);
size_t ListFile_GetNextLine(void * pvListFile, char * szBuffer, size_t nMaxChars);
size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, size_t nMaxChars);
void ListFile_Free(void * pvListFile);
//-----------------------------------------------------------------------------
// Functions for creating a listfile map
PLISTFILE_MAP ListFile_CreateMap(const TCHAR * szListFile);
const char * ListFile_FindName(PLISTFILE_MAP pListMap, ULONGLONG FileNameHash);
void ListFile_FreeMap(PLISTFILE_MAP pListMap);
#endif // __LISTFILE_H__

View File

@@ -0,0 +1,287 @@
/*****************************************************************************/
/* Map.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* Implementation of map for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 10.06.14 1.00 Lad The first version of Map.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "../CascLib.h"
#include "../CascCommon.h"
//-----------------------------------------------------------------------------
// Local functions
// Returns the extension, right after "."
static const char * String_GetExtension(const char * szString)
{
const char * szExtension = strrchr(szString, '.');
return (szExtension != NULL) ? szExtension + 1 : NULL;
}
static DWORD CalcHashIndex_Key(PCASC_MAP pMap, void * pvKey)
{
LPBYTE pbKey = (LPBYTE)pvKey;
DWORD dwHash = 0x7EEE7EEE;
// Construct the hash from the first 8 digits
dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[0];
dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[1];
dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[2];
dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[3];
dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[4];
dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[5];
dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[6];
dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[7];
// Return the hash limited by the table size
return (dwHash % pMap->TableSize);
}
static DWORD CalcHashIndex_String(PCASC_MAP pMap, const char * szString, const char * szStringEnd)
{
LPBYTE pbKeyEnd = (LPBYTE)szStringEnd;
LPBYTE pbKey = (LPBYTE)szString;
DWORD dwHash = 0x7EEE7EEE;
// Hash the string itself
while(pbKey < pbKeyEnd)
{
dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ AsciiToUpperTable_BkSlash[pbKey[0]];
pbKey++;
}
// Return the hash limited by the table size
return (dwHash % pMap->TableSize);
}
static bool CompareObject_Key(PCASC_MAP pMap, void * pvObject, void * pvKey)
{
LPBYTE pbObjectKey = (LPBYTE)pvObject + pMap->KeyOffset;
return (memcmp(pbObjectKey, pvKey, pMap->KeyLength) == 0);
}
static bool CompareObject_String(
PCASC_MAP pMap,
const char * szExistingString,
const char * szString,
const char * szStringEnd)
{
// Keep compiler happy
CASCLIB_UNUSED(pMap);
// Compare the whole part, case insensitive
while(szString < szStringEnd)
{
if(AsciiToUpperTable_BkSlash[*szExistingString] != AsciiToUpperTable_BkSlash[*szString])
return false;
szExistingString++;
szString++;
}
return true;
}
//-----------------------------------------------------------------------------
// Public functions
PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwKeyOffset)
{
PCASC_MAP pMap;
size_t cbToAllocate;
size_t dwTableSize;
// Calculate the size of the table
dwTableSize = (dwMaxItems * 3 / 2) | 0x01;
// Allocate new map for the objects
cbToAllocate = sizeof(CASC_MAP) + (dwTableSize * sizeof(void *));
pMap = (PCASC_MAP)CASC_ALLOC(LPBYTE, cbToAllocate);
if(pMap != NULL)
{
memset(pMap, 0, cbToAllocate);
pMap->KeyLength = dwKeyLength;
pMap->TableSize = dwTableSize;
pMap->KeyOffset = dwKeyOffset;
}
// Return the allocated map
return pMap;
}
size_t Map_EnumObjects(PCASC_MAP pMap, void **ppvArray)
{
size_t nIndex = 0;
// Verify pointer to the map
if(pMap != NULL && ppvArray != NULL)
{
// Enumerate all items in main table
for(size_t i = 0; i < pMap->TableSize; i++)
{
// Is that cell valid?
if(pMap->HashTable[i] != NULL)
{
ppvArray[nIndex++] = pMap->HashTable[i];
}
}
return pMap->ItemCount;
}
return 0;
}
void * Map_FindObject(PCASC_MAP pMap, void * pvKey, PDWORD PtrIndex)
{
void * pvObject;
DWORD dwHashIndex;
// Verify pointer to the map
if(pMap != NULL)
{
// Construct the main index
dwHashIndex = CalcHashIndex_Key(pMap, pvKey);
while(pMap->HashTable[dwHashIndex] != NULL)
{
// Get the pointer at that position
pvObject = pMap->HashTable[dwHashIndex];
// Compare the hash
if(CompareObject_Key(pMap, pvObject, pvKey))
{
if(PtrIndex != NULL)
PtrIndex[0] = dwHashIndex;
return pvObject;
}
// Move to the next entry
dwHashIndex = (dwHashIndex + 1) % pMap->TableSize;
}
}
// Not found, sorry
return NULL;
}
bool Map_InsertObject(PCASC_MAP pMap, void * pvNewObject, void * pvKey)
{
void * pvExistingObject;
DWORD dwHashIndex;
// Verify pointer to the map
if(pMap != NULL)
{
// Limit check
if((pMap->ItemCount + 1) >= pMap->TableSize)
return false;
// Construct the hash index
dwHashIndex = CalcHashIndex_Key(pMap, pvKey);
while(pMap->HashTable[dwHashIndex] != NULL)
{
// Get the pointer at that position
pvExistingObject = pMap->HashTable[dwHashIndex];
// Check if hash being inserted conflicts with an existing hash
if(CompareObject_Key(pMap, pvExistingObject, pvKey))
return false;
// Move to the next entry
dwHashIndex = (dwHashIndex + 1) % pMap->TableSize;
}
// Insert at that position
pMap->HashTable[dwHashIndex] = pvNewObject;
pMap->ItemCount++;
return true;
}
// Failed
return false;
}
bool Map_InsertString(PCASC_MAP pMap, const char * szString, bool bCutExtension)
{
const char * szExistingString;
const char * szStringEnd = NULL;
DWORD dwHashIndex;
// Verify pointer to the map
if(pMap != NULL)
{
// Limit check
if((pMap->ItemCount + 1) >= pMap->TableSize)
return false;
// Retrieve the length of the string without extension
if(bCutExtension)
szStringEnd = String_GetExtension(szString);
if(szStringEnd == NULL)
szStringEnd = szString + strlen(szString);
// Construct the hash index
dwHashIndex = CalcHashIndex_String(pMap, szString, szStringEnd);
while(pMap->HashTable[dwHashIndex] != NULL)
{
// Get the pointer at that position
szExistingString = (const char *)pMap->HashTable[dwHashIndex];
// Check if hash being inserted conflicts with an existing hash
if(CompareObject_String(pMap, szExistingString, szString, szStringEnd))
return false;
// Move to the next entry
dwHashIndex = (dwHashIndex + 1) % pMap->TableSize;
}
// Insert at that position
pMap->HashTable[dwHashIndex] = (void *)szString;
pMap->ItemCount++;
return true;
}
// Failed
return false;
}
const char * Map_FindString(PCASC_MAP pMap, const char * szString, const char * szStringEnd)
{
const char * szExistingString;
DWORD dwHashIndex;
// Verify pointer to the map
if(pMap != NULL)
{
// Construct the main index
dwHashIndex = CalcHashIndex_String(pMap, szString, szStringEnd);
while(pMap->HashTable[dwHashIndex] != NULL)
{
// Get the pointer at that position
szExistingString = (const char *)pMap->HashTable[dwHashIndex];
// Compare the hash
if(CompareObject_String(pMap, szExistingString, szString, szStringEnd))
return szExistingString;
// Move to the next entry
dwHashIndex = (dwHashIndex + 1) % pMap->TableSize;
}
}
// Not found, sorry
return NULL;
}
void Map_Free(PCASC_MAP pMap)
{
if(pMap != NULL)
{
CASC_FREE(pMap);
}
}

View File

@@ -0,0 +1,42 @@
/*****************************************************************************/
/* Map.h Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* Interface of hash-to-ptr map for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 10.06.14 1.00 Lad The first version of Map.h */
/*****************************************************************************/
#ifndef __HASHTOPTR_H__
#define __HASHTOPTR_H__
//-----------------------------------------------------------------------------
// Structures
#define KEY_LENGTH_STRING 0xFFFFFFFF // Pass this to Map_Create as dwKeyLength when you want map of string->object
typedef struct _CASC_MAP
{
size_t TableSize;
size_t ItemCount; // Number of items in the map
size_t KeyOffset; // How far is the hash from the begin of the structure (in bytes)
size_t KeyLength; // Length of the hash key
void * HashTable[1]; // Pointer table
} CASC_MAP, *PCASC_MAP;
typedef bool (*MAP_COMPARE)(PCASC_MAP pMap, void * pvObject, void * pvKey);
//-----------------------------------------------------------------------------
// Functions
PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwKeyOffset);
size_t Map_EnumObjects(PCASC_MAP pMap, void **ppvArray);
void * Map_FindObject(PCASC_MAP pMap, void * pvKey, PDWORD PtrIndex);
bool Map_InsertObject(PCASC_MAP pMap, void * pvNewObject, void * pvKey);
const char * Map_FindString(PCASC_MAP pMap, const char * szString, const char * szStringEnd);
bool Map_InsertString(PCASC_MAP pMap, const char * szString, bool bCutExtension);
void Map_Free(PCASC_MAP pMap);
#endif // __HASHTOPTR_H__

View File

@@ -0,0 +1,88 @@
/*****************************************************************************/
/* RootHandler.cpp Copyright (c) Ladislav Zezula 2015 */
/*---------------------------------------------------------------------------*/
/* Implementation of root handler */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 09.03.15 1.00 Lad Created */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "../CascLib.h"
#include "../CascCommon.h"
//-----------------------------------------------------------------------------
// Common support
int RootHandler_Insert(TRootHandler * pRootHandler, const char * szFileName, LPBYTE pbEncodingKey)
{
if(pRootHandler == NULL || pRootHandler->Insert == NULL || pbEncodingKey == NULL)
return ERROR_NOT_SUPPORTED;
return pRootHandler->Insert(pRootHandler, szFileName, pbEncodingKey);
}
LPBYTE RootHandler_Search(TRootHandler * pRootHandler, struct _TCascSearch * pSearch, PDWORD PtrFileSize, PDWORD PtrLocaleFlags, PDWORD PtrFileDataId)
{
// Check if the root structure is valid at all
if(pRootHandler == NULL)
return NULL;
return pRootHandler->Search(pRootHandler, pSearch, PtrFileSize, PtrLocaleFlags, PtrFileDataId);
}
void RootHandler_EndSearch(TRootHandler * pRootHandler, struct _TCascSearch * pSearch)
{
// Check if the root structure is valid at all
if(pRootHandler != NULL)
{
pRootHandler->EndSearch(pRootHandler, pSearch);
}
}
LPBYTE RootHandler_GetKey(TRootHandler * pRootHandler, const char * szFileName)
{
// Check if the root structure is valid at all
if(pRootHandler == NULL)
return NULL;
return pRootHandler->GetKey(pRootHandler, szFileName);
}
void RootHandler_Dump(TCascStorage * hs, LPBYTE pbRootHandler, DWORD cbRootHandler, const TCHAR * szNameFormat, const TCHAR * szListFile, int nDumpLevel)
{
TDumpContext * dc;
// Only if the ROOT provider suports the dump option
if(hs->pRootHandler != NULL && hs->pRootHandler->Dump != NULL)
{
// Create the dump file
dc = CreateDumpContext(hs, szNameFormat);
if(dc != NULL)
{
// Dump the content and close the file
hs->pRootHandler->Dump(hs, dc, pbRootHandler, cbRootHandler, szListFile, nDumpLevel);
dump_close(dc);
}
}
}
void RootHandler_Close(TRootHandler * pRootHandler)
{
// Check if the root structure is allocated at all
if(pRootHandler != NULL)
{
pRootHandler->Close(pRootHandler);
}
}
DWORD RootHandler_GetFileId(TRootHandler * pRootHandler, const char * szFileName)
{
// Check if the root structure is valid at all
if(pRootHandler == NULL)
return 0;
return pRootHandler->GetFileId(pRootHandler, szFileName);
}

View File

@@ -0,0 +1,96 @@
/*****************************************************************************/
/* RootHandler.h Copyright (c) Ladislav Zezula 2015 */
/*---------------------------------------------------------------------------*/
/* Interface for root handlers */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 09.03.15 1.00 Lad Created */
/*****************************************************************************/
#ifndef __ROOT_HANDLER_H__
#define __ROOT_HANDLER_H__
//-----------------------------------------------------------------------------
// Defines
#define CASC_MNDX_ROOT_SIGNATURE 0x58444E4D // 'MNDX'
#define CASC_DIABLO3_ROOT_SIGNATURE 0x8007D0C4
#define CASC_OVERWATCH_ROOT_SIGNATURE 0x35444D23 // '#MD5'
#define ROOT_FLAG_HAS_NAMES 0x00000001 // The root file contains file names
#define DUMP_LEVEL_ROOT_FILE 1 // Dump root file
#define DUMP_LEVEL_ENCODING_FILE 2 // Dump root file + encoding file
#define DUMP_LEVEL_INDEX_ENTRIES 3 // Dump root file + encoding file + index entries
//-----------------------------------------------------------------------------
// Root file function prototypes
typedef int (*ROOT_INSERT)(
struct TRootHandler * pRootHandler, // Pointer to an initialized root handler
const char * szFileName, // Pointer to the file name
LPBYTE pbEncodingKey // Pointer to the encoding key of the file name
);
typedef LPBYTE (*ROOT_SEARCH)(
struct TRootHandler * pRootHandler, // Pointer to an initialized root handler
struct _TCascSearch * pSearch, // Pointer to the initialized search structure
PDWORD PtrFileSize, // Pointer to receive file size (optional)
PDWORD PtrLocaleFlags, // Pointer to receive locale flags (optional)
PDWORD PtrFileDataId // Pointer to FileDataID (optional)
);
typedef void (*ROOT_ENDSEARCH)(
struct TRootHandler * pRootHandler, // Pointer to an initialized root handler
struct _TCascSearch * pSearch // Pointer to the initialized search structure
);
typedef LPBYTE (*ROOT_GETKEY)(
struct TRootHandler * pRootHandler, // Pointer to an initialized root handler
const char * szFileName // Pointer to the name of a file
);
typedef void (*ROOT_DUMP)(
struct _TCascStorage * hs, // Pointer to the open storage
TDumpContext * dc, // Opened dump context
LPBYTE pbRootHandler, // Pointer to the loaded ROOT file
DWORD cbRootHandler, // Length of the loaded ROOT file
const TCHAR * szListFile,
int nDumpLevel
);
typedef void (*ROOT_CLOSE)(
struct TRootHandler * pRootHandler // Pointer to an initialized root handler
);
typedef DWORD(*ROOT_GETFILEID)(
struct TRootHandler * pRootHandler, // Pointer to an initialized root handler
const char * szFileName // Pointer to the name of a file
);
struct TRootHandler
{
ROOT_INSERT Insert; // Inserts an existing file name
ROOT_SEARCH Search; // Performs the root file search
ROOT_ENDSEARCH EndSearch; // Performs cleanup after searching
ROOT_GETKEY GetKey; // Retrieves encoding key for a file name
ROOT_DUMP Dump;
ROOT_CLOSE Close; // Closing the root file
ROOT_GETFILEID GetFileId; // Returns File Id for a given Filename
DWORD dwRootFlags; // Root flags - see the ROOT_FLAG_XXX
};
//-----------------------------------------------------------------------------
// Public functions
int RootHandler_Insert(TRootHandler * pRootHandler, const char * szFileName, LPBYTE pbEncodingKey);
LPBYTE RootHandler_Search(TRootHandler * pRootHandler, struct _TCascSearch * pSearch, PDWORD PtrFileSize, PDWORD PtrLocaleFlags, PDWORD PtrFileDataId);
void RootHandler_EndSearch(TRootHandler * pRootHandler, struct _TCascSearch * pSearch);
LPBYTE RootHandler_GetKey(TRootHandler * pRootHandler, const char * szFileName);
void RootHandler_Dump(struct _TCascStorage * hs, LPBYTE pbRootHandler, DWORD cbRootHandler, const TCHAR * szNameFormat, const TCHAR * szListFile, int nDumpLevel);
void RootHandler_Close(TRootHandler * pRootHandler);
DWORD RootHandler_GetFileId(TRootHandler * pRootHandler, const char * szFileName);
#endif // __ROOT_HANDLER_H__

View File

@@ -0,0 +1,24 @@
#ifndef __LOOKUP3_H__
#define __LOOKUP3_H__
#ifdef WIN32
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#else
#include <stdint.h> /* defines uint32_t etc */
#endif
#ifdef __cplusplus
extern "C"
{
#endif
uint32_t hashlittle(const void *key, size_t length, uint32_t initval);
void hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb);
#ifdef __cplusplus
}
#endif
#endif // __LOOKUP3_H__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
*/
#include "../headers/tomcrypt.h"
/**
@file hash_memory.c
Hash memory helper, Tom St Denis
*/
/**
Hash a block of memory and store the digest.
@param hash The index of the hash you wish to use
@param in The data you wish to hash
@param inlen The length of the data to hash (octets)
@param out [out] Where to store the digest
@param outlen [in/out] Max size and resulting size of the digest
@return CRYPT_OK if successful
*/
int hash_memory(int hash, const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen)
{
hash_state *md;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
if ((err = hash_is_valid(hash)) != CRYPT_OK) {
return err;
}
if (*outlen < hash_descriptor[hash].hashsize) {
*outlen = hash_descriptor[hash].hashsize;
return CRYPT_BUFFER_OVERFLOW;
}
md = XMALLOC(sizeof(hash_state));
if (md == NULL) {
return CRYPT_MEM;
}
if ((err = hash_descriptor[hash].init(md)) != CRYPT_OK) {
goto LBL_ERR;
}
if ((err = hash_descriptor[hash].process(md, in, inlen)) != CRYPT_OK) {
goto LBL_ERR;
}
err = hash_descriptor[hash].done(md, out);
*outlen = hash_descriptor[hash].hashsize;
LBL_ERR:
#ifdef LTC_CLEAN_STACK
zeromem(md, sizeof(hash_state));
#endif
XFREE(md);
return err;
}
/* $Source: /cvs/libtom/libtomcrypt/src/hashes/helper/hash_memory.c,v $ */
/* $Revision: 1.6 $ */
/* $Date: 2006/12/28 01:27:23 $ */

View File

@@ -0,0 +1,368 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
*/
#include "../headers/tomcrypt.h"
/**
@file md5.c
LTC_MD5 hash function by Tom St Denis
*/
#ifdef LTC_MD5
const struct ltc_hash_descriptor md5_desc =
{
"md5",
3,
16,
64,
/* OID */
{ 1, 2, 840, 113549, 2, 5, },
6,
&md5_init,
&md5_process,
&md5_done,
&md5_test,
NULL
};
#define F(x,y,z) (z ^ (x & (y ^ z)))
#define G(x,y,z) (y ^ (z & (y ^ x)))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y^(x|(~z)))
#ifdef LTC_SMALL_CODE
#define FF(a,b,c,d,M,s,t) \
a = (a + F(b,c,d) + M + t); a = ROL(a, s) + b;
#define GG(a,b,c,d,M,s,t) \
a = (a + G(b,c,d) + M + t); a = ROL(a, s) + b;
#define HH(a,b,c,d,M,s,t) \
a = (a + H(b,c,d) + M + t); a = ROL(a, s) + b;
#define II(a,b,c,d,M,s,t) \
a = (a + I(b,c,d) + M + t); a = ROL(a, s) + b;
static const unsigned char Worder[64] = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12,
5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2,
0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9
};
static const unsigned char Rorder[64] = {
7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
};
static const ulong32 Korder[64] = {
0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL, 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL, 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL, 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL, 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL, 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL
};
#else
#define FF(a,b,c,d,M,s,t) \
a = (a + F(b,c,d) + M + t); a = ROLc(a, s) + b;
#define GG(a,b,c,d,M,s,t) \
a = (a + G(b,c,d) + M + t); a = ROLc(a, s) + b;
#define HH(a,b,c,d,M,s,t) \
a = (a + H(b,c,d) + M + t); a = ROLc(a, s) + b;
#define II(a,b,c,d,M,s,t) \
a = (a + I(b,c,d) + M + t); a = ROLc(a, s) + b;
#endif
#ifdef LTC_CLEAN_STACK
static int _md5_compress(hash_state *md, unsigned char *buf)
#else
static int md5_compress(hash_state *md, unsigned char *buf)
#endif
{
ulong32 i, W[16], a, b, c, d;
#ifdef LTC_SMALL_CODE
ulong32 t;
#endif
/* copy the state into 512-bits into W[0..15] */
for (i = 0; i < 16; i++) {
LOAD32L(W[i], buf + (4*i));
}
/* copy state */
a = md->md5.state[0];
b = md->md5.state[1];
c = md->md5.state[2];
d = md->md5.state[3];
#ifdef LTC_SMALL_CODE
for (i = 0; i < 16; ++i) {
FF(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
t = d; d = c; c = b; b = a; a = t;
}
for (; i < 32; ++i) {
GG(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
t = d; d = c; c = b; b = a; a = t;
}
for (; i < 48; ++i) {
HH(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
t = d; d = c; c = b; b = a; a = t;
}
for (; i < 64; ++i) {
II(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
t = d; d = c; c = b; b = a; a = t;
}
#else
FF(a,b,c,d,W[0],7,0xd76aa478UL)
FF(d,a,b,c,W[1],12,0xe8c7b756UL)
FF(c,d,a,b,W[2],17,0x242070dbUL)
FF(b,c,d,a,W[3],22,0xc1bdceeeUL)
FF(a,b,c,d,W[4],7,0xf57c0fafUL)
FF(d,a,b,c,W[5],12,0x4787c62aUL)
FF(c,d,a,b,W[6],17,0xa8304613UL)
FF(b,c,d,a,W[7],22,0xfd469501UL)
FF(a,b,c,d,W[8],7,0x698098d8UL)
FF(d,a,b,c,W[9],12,0x8b44f7afUL)
FF(c,d,a,b,W[10],17,0xffff5bb1UL)
FF(b,c,d,a,W[11],22,0x895cd7beUL)
FF(a,b,c,d,W[12],7,0x6b901122UL)
FF(d,a,b,c,W[13],12,0xfd987193UL)
FF(c,d,a,b,W[14],17,0xa679438eUL)
FF(b,c,d,a,W[15],22,0x49b40821UL)
GG(a,b,c,d,W[1],5,0xf61e2562UL)
GG(d,a,b,c,W[6],9,0xc040b340UL)
GG(c,d,a,b,W[11],14,0x265e5a51UL)
GG(b,c,d,a,W[0],20,0xe9b6c7aaUL)
GG(a,b,c,d,W[5],5,0xd62f105dUL)
GG(d,a,b,c,W[10],9,0x02441453UL)
GG(c,d,a,b,W[15],14,0xd8a1e681UL)
GG(b,c,d,a,W[4],20,0xe7d3fbc8UL)
GG(a,b,c,d,W[9],5,0x21e1cde6UL)
GG(d,a,b,c,W[14],9,0xc33707d6UL)
GG(c,d,a,b,W[3],14,0xf4d50d87UL)
GG(b,c,d,a,W[8],20,0x455a14edUL)
GG(a,b,c,d,W[13],5,0xa9e3e905UL)
GG(d,a,b,c,W[2],9,0xfcefa3f8UL)
GG(c,d,a,b,W[7],14,0x676f02d9UL)
GG(b,c,d,a,W[12],20,0x8d2a4c8aUL)
HH(a,b,c,d,W[5],4,0xfffa3942UL)
HH(d,a,b,c,W[8],11,0x8771f681UL)
HH(c,d,a,b,W[11],16,0x6d9d6122UL)
HH(b,c,d,a,W[14],23,0xfde5380cUL)
HH(a,b,c,d,W[1],4,0xa4beea44UL)
HH(d,a,b,c,W[4],11,0x4bdecfa9UL)
HH(c,d,a,b,W[7],16,0xf6bb4b60UL)
HH(b,c,d,a,W[10],23,0xbebfbc70UL)
HH(a,b,c,d,W[13],4,0x289b7ec6UL)
HH(d,a,b,c,W[0],11,0xeaa127faUL)
HH(c,d,a,b,W[3],16,0xd4ef3085UL)
HH(b,c,d,a,W[6],23,0x04881d05UL)
HH(a,b,c,d,W[9],4,0xd9d4d039UL)
HH(d,a,b,c,W[12],11,0xe6db99e5UL)
HH(c,d,a,b,W[15],16,0x1fa27cf8UL)
HH(b,c,d,a,W[2],23,0xc4ac5665UL)
II(a,b,c,d,W[0],6,0xf4292244UL)
II(d,a,b,c,W[7],10,0x432aff97UL)
II(c,d,a,b,W[14],15,0xab9423a7UL)
II(b,c,d,a,W[5],21,0xfc93a039UL)
II(a,b,c,d,W[12],6,0x655b59c3UL)
II(d,a,b,c,W[3],10,0x8f0ccc92UL)
II(c,d,a,b,W[10],15,0xffeff47dUL)
II(b,c,d,a,W[1],21,0x85845dd1UL)
II(a,b,c,d,W[8],6,0x6fa87e4fUL)
II(d,a,b,c,W[15],10,0xfe2ce6e0UL)
II(c,d,a,b,W[6],15,0xa3014314UL)
II(b,c,d,a,W[13],21,0x4e0811a1UL)
II(a,b,c,d,W[4],6,0xf7537e82UL)
II(d,a,b,c,W[11],10,0xbd3af235UL)
II(c,d,a,b,W[2],15,0x2ad7d2bbUL)
II(b,c,d,a,W[9],21,0xeb86d391UL)
#endif
md->md5.state[0] = md->md5.state[0] + a;
md->md5.state[1] = md->md5.state[1] + b;
md->md5.state[2] = md->md5.state[2] + c;
md->md5.state[3] = md->md5.state[3] + d;
return CRYPT_OK;
}
#ifdef LTC_CLEAN_STACK
static int md5_compress(hash_state *md, unsigned char *buf)
{
int err;
err = _md5_compress(md, buf);
burn_stack(sizeof(ulong32) * 21);
return err;
}
#endif
/**
Initialize the hash state
@param md The hash state you wish to initialize
@return CRYPT_OK if successful
*/
int md5_init(hash_state * md)
{
LTC_ARGCHK(md != NULL);
md->md5.state[0] = 0x67452301UL;
md->md5.state[1] = 0xefcdab89UL;
md->md5.state[2] = 0x98badcfeUL;
md->md5.state[3] = 0x10325476UL;
md->md5.curlen = 0;
md->md5.length = 0;
return CRYPT_OK;
}
/**
Process a block of memory though the hash
@param md The hash state
@param in The data to hash
@param inlen The length of the data (octets)
@return CRYPT_OK if successful
*/
HASH_PROCESS(md5_process, md5_compress, md5, 64)
/**
Terminate the hash to get the digest
@param md The hash state
@param out [out] The destination of the hash (16 bytes)
@return CRYPT_OK if successful
*/
int md5_done(hash_state * md, unsigned char *out)
{
int i;
LTC_ARGCHK(md != NULL);
LTC_ARGCHK(out != NULL);
if (md->md5.curlen >= sizeof(md->md5.buf)) {
return CRYPT_INVALID_ARG;
}
/* increase the length of the message */
md->md5.length += md->md5.curlen * 8;
/* append the '1' bit */
md->md5.buf[md->md5.curlen++] = (unsigned char)0x80;
/* if the length is currently above 56 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if (md->md5.curlen > 56) {
while (md->md5.curlen < 64) {
md->md5.buf[md->md5.curlen++] = (unsigned char)0;
}
md5_compress(md, md->md5.buf);
md->md5.curlen = 0;
}
/* pad upto 56 bytes of zeroes */
while (md->md5.curlen < 56) {
md->md5.buf[md->md5.curlen++] = (unsigned char)0;
}
/* store length */
STORE64L(md->md5.length, md->md5.buf+56);
md5_compress(md, md->md5.buf);
/* copy output */
for (i = 0; i < 4; i++) {
STORE32L(md->md5.state[i], out+(4*i));
}
#ifdef LTC_CLEAN_STACK
zeromem(md, sizeof(hash_state));
#endif
return CRYPT_OK;
}
/**
Self-test the hash
@return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
*/
int md5_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
static const struct {
char *msg;
unsigned char hash[16];
} tests[] = {
{ "",
{ 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
{ "a",
{0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8,
0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } },
{ "abc",
{ 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
{ "message digest",
{ 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d,
0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } },
{ "abcdefghijklmnopqrstuvwxyz",
{ 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00,
0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } },
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
{ 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5,
0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } },
{ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
{ 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55,
0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } },
{ NULL, { 0 } }
};
int i;
unsigned char tmp[16];
hash_state md;
for (i = 0; tests[i].msg != NULL; i++) {
md5_init(&md);
md5_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
md5_done(&md, tmp);
if (XMEMCMP(tmp, tests[i].hash, 16) != 0) {
return CRYPT_FAIL_TESTVECTOR;
}
}
return CRYPT_OK;
#endif
}
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/hashes/md5.c,v $ */
/* $Revision: 1.10 $ */
/* $Date: 2007/05/12 14:25:28 $ */

View File

@@ -0,0 +1,87 @@
#ifndef TOMCRYPT_H_
#define TOMCRYPT_H_
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <limits.h>
/* use configuration data */
#include "tomcrypt_custom.h"
#ifdef __cplusplus
extern "C" {
#endif
/* version */
#define CRYPT 0x0117
#define SCRYPT "1.17"
/* max size of either a cipher/hash block or symmetric key [largest of the two] */
#define MAXBLOCKSIZE 128
/* descriptor table size */
#define TAB_SIZE 32
/* error codes [will be expanded in future releases] */
enum {
CRYPT_OK=0, /* Result OK */
CRYPT_ERROR, /* Generic Error */
CRYPT_NOP, /* Not a failure but no operation was performed */
CRYPT_INVALID_KEYSIZE, /* Invalid key size given */
CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */
CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */
CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */
CRYPT_INVALID_PACKET, /* Invalid input packet given */
CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */
CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */
CRYPT_INVALID_CIPHER, /* Invalid cipher specified */
CRYPT_INVALID_HASH, /* Invalid hash specified */
CRYPT_INVALID_PRNG, /* Invalid PRNG specified */
CRYPT_MEM, /* Out of memory */
CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */
CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */
CRYPT_INVALID_ARG, /* Generic invalid argument */
CRYPT_FILE_NOTFOUND, /* File Not Found */
CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */
CRYPT_PK_INVALID_SYSTEM,/* Invalid PK system specified */
CRYPT_PK_DUP, /* Duplicate key already in key ring */
CRYPT_PK_NOT_FOUND, /* Key not found in keyring */
CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */
CRYPT_INVALID_PRIME_SIZE,/* Invalid size of prime requested */
CRYPT_PK_INVALID_PADDING /* Invalid padding on input */
};
#include "tomcrypt_cfg.h"
#include "tomcrypt_macros.h"
#include "tomcrypt_cipher.h"
#include "tomcrypt_hash.h"
#include "tomcrypt_mac.h"
#include "tomcrypt_prng.h"
#include "tomcrypt_pk.h"
#include "tomcrypt_math.h"
#include "tomcrypt_misc.h"
#include "tomcrypt_argchk.h"
#include "tomcrypt_pkcs.h"
#ifdef __cplusplus
}
#endif
#endif /* TOMCRYPT_H_ */
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt.h,v $ */
/* $Revision: 1.21 $ */
/* $Date: 2006/12/16 19:34:05 $ */

View File

@@ -0,0 +1,38 @@
/* Defines the LTC_ARGCHK macro used within the library */
/* ARGTYPE is defined in mycrypt_cfg.h */
#if ARGTYPE == 0
#include <signal.h>
/* this is the default LibTomCrypt macro */
void crypt_argchk(char *v, char *s, int d);
#define LTC_ARGCHK(x) if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); }
#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
#elif ARGTYPE == 1
/* fatal type of error */
#define LTC_ARGCHK(x) assert((x))
#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
#elif ARGTYPE == 2
#define LTC_ARGCHK(x) if (!(x)) { fprintf(stderr, "\nwarning: ARGCHK failed at %s:%d\n", __FILE__, __LINE__); }
#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
#elif ARGTYPE == 3
#define LTC_ARGCHK(x)
#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
#elif ARGTYPE == 4
#define LTC_ARGCHK(x) if (!(x)) return CRYPT_INVALID_ARG;
#define LTC_ARGCHKVD(x) if (!(x)) return;
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_argchk.h,v $ */
/* $Revision: 1.5 $ */
/* $Date: 2006/08/27 20:50:21 $ */

View File

@@ -0,0 +1,136 @@
/* This is the build config file.
*
* With this you can setup what to inlcude/exclude automatically during any build. Just comment
* out the line that #define's the word for the thing you want to remove. phew!
*/
#ifndef TOMCRYPT_CFG_H
#define TOMCRYPT_CFG_H
#if defined(_WIN32) || defined(_MSC_VER)
#define LTC_CALL __cdecl
#else
#ifndef LTC_CALL
#define LTC_CALL
#endif
#endif
#ifndef LTC_EXPORT
#define LTC_EXPORT
#endif
/* certain platforms use macros for these, making the prototypes broken */
#ifndef LTC_NO_PROTOTYPES
/* you can change how memory allocation works ... */
LTC_EXPORT void * LTC_CALL XMALLOC(size_t n);
LTC_EXPORT void * LTC_CALL XREALLOC(void *p, size_t n);
LTC_EXPORT void * LTC_CALL XCALLOC(size_t n, size_t s);
LTC_EXPORT void LTC_CALL XFREE(void *p);
LTC_EXPORT void LTC_CALL XQSORT(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
/* change the clock function too */
LTC_EXPORT clock_t LTC_CALL XCLOCK(void);
/* various other functions */
LTC_EXPORT void * LTC_CALL XMEMCPY(void *dest, const void *src, size_t n);
LTC_EXPORT int LTC_CALL XMEMCMP(const void *s1, const void *s2, size_t n);
LTC_EXPORT void * LTC_CALL XMEMSET(void *s, int c, size_t n);
LTC_EXPORT int LTC_CALL XSTRCMP(const char *s1, const char *s2);
#endif
/* type of argument checking, 0=default, 1=fatal and 2=error+continue, 3=nothing */
#ifndef ARGTYPE
#define ARGTYPE 0
#endif
/* Controls endianess and size of registers. Leave uncommented to get platform neutral [slower] code
*
* Note: in order to use the optimized macros your platform must support unaligned 32 and 64 bit read/writes.
* The x86 platforms allow this but some others [ARM for instance] do not. On those platforms you **MUST**
* use the portable [slower] macros.
*/
/* detect x86-32 machines somewhat */
#if !defined(__STRICT_ANSI__) && (defined(INTEL_CC) || (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__))))
#define ENDIAN_LITTLE
#define ENDIAN_32BITWORD
#define LTC_FAST
#define LTC_FAST_TYPE unsigned long
#endif
/* detects MIPS R5900 processors (PS2) */
#if (defined(__R5900) || defined(R5900) || defined(__R5900__)) && (defined(_mips) || defined(__mips__) || defined(mips))
#define ENDIAN_LITTLE
#define ENDIAN_64BITWORD
#endif
/* detect amd64 */
#if !defined(__STRICT_ANSI__) && defined(__x86_64__)
#define ENDIAN_LITTLE
#define ENDIAN_64BITWORD
#define LTC_FAST
#define LTC_FAST_TYPE unsigned long
#endif
/* detect PPC32 */
#if !defined(__STRICT_ANSI__) && defined(LTC_PPC32)
#define ENDIAN_BIG
#define ENDIAN_32BITWORD
#define LTC_FAST
#define LTC_FAST_TYPE unsigned long
#endif
/* detect sparc and sparc64 */
#if defined(__sparc__)
#define ENDIAN_BIG
#if defined(__arch64__)
#define ENDIAN_64BITWORD
#else
#define ENDIAN_32BITWORD
#endif
#endif
#ifdef LTC_NO_FAST
#ifdef LTC_FAST
#undef LTC_FAST
#endif
#endif
/* No asm is a quick way to disable anything "not portable" */
#ifdef LTC_NO_ASM
#undef ENDIAN_LITTLE
#undef ENDIAN_BIG
#undef ENDIAN_32BITWORD
#undef ENDIAN_64BITWORD
#undef LTC_FAST
#undef LTC_FAST_TYPE
#define LTC_NO_ROLC
#define LTC_NO_BSWAP
#endif
/* #define ENDIAN_LITTLE */
/* #define ENDIAN_BIG */
/* #define ENDIAN_32BITWORD */
/* #define ENDIAN_64BITWORD */
#if (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD))
#error You must specify a word size as well as endianess in tomcrypt_cfg.h
#endif
#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE))
#define ENDIAN_NEUTRAL
#endif
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_cfg.h,v $ */
/* $Revision: 1.19 $ */
/* $Date: 2006/12/04 02:19:48 $ */

View File

@@ -0,0 +1,891 @@
/* ---- SYMMETRIC KEY STUFF -----
*
* We put each of the ciphers scheduled keys in their own structs then we put all of
* the key formats in one union. This makes the function prototypes easier to use.
*/
#ifdef LTC_BLOWFISH
struct blowfish_key {
ulong32 S[4][256];
ulong32 K[18];
};
#endif
#ifdef LTC_RC5
struct rc5_key {
int rounds;
ulong32 K[50];
};
#endif
#ifdef LTC_RC6
struct rc6_key {
ulong32 K[44];
};
#endif
#ifdef LTC_SAFERP
struct saferp_key {
unsigned char K[33][16];
long rounds;
};
#endif
#ifdef LTC_RIJNDAEL
struct rijndael_key {
ulong32 eK[60], dK[60];
int Nr;
};
#endif
#ifdef LTC_KSEED
struct kseed_key {
ulong32 K[32], dK[32];
};
#endif
#ifdef LTC_KASUMI
struct kasumi_key {
ulong32 KLi1[8], KLi2[8],
KOi1[8], KOi2[8], KOi3[8],
KIi1[8], KIi2[8], KIi3[8];
};
#endif
#ifdef LTC_XTEA
struct xtea_key {
unsigned long A[32], B[32];
};
#endif
#ifdef LTC_TWOFISH
#ifndef LTC_TWOFISH_SMALL
struct twofish_key {
ulong32 S[4][256], K[40];
};
#else
struct twofish_key {
ulong32 K[40];
unsigned char S[32], start;
};
#endif
#endif
#ifdef LTC_SAFER
#define LTC_SAFER_K64_DEFAULT_NOF_ROUNDS 6
#define LTC_SAFER_K128_DEFAULT_NOF_ROUNDS 10
#define LTC_SAFER_SK64_DEFAULT_NOF_ROUNDS 8
#define LTC_SAFER_SK128_DEFAULT_NOF_ROUNDS 10
#define LTC_SAFER_MAX_NOF_ROUNDS 13
#define LTC_SAFER_BLOCK_LEN 8
#define LTC_SAFER_KEY_LEN (1 + LTC_SAFER_BLOCK_LEN * (1 + 2 * LTC_SAFER_MAX_NOF_ROUNDS))
typedef unsigned char safer_block_t[LTC_SAFER_BLOCK_LEN];
typedef unsigned char safer_key_t[LTC_SAFER_KEY_LEN];
struct safer_key { safer_key_t key; };
#endif
#ifdef LTC_RC2
struct rc2_key { unsigned xkey[64]; };
#endif
#ifdef LTC_DES
struct des_key {
ulong32 ek[32], dk[32];
};
struct des3_key {
ulong32 ek[3][32], dk[3][32];
};
#endif
#ifdef LTC_CAST5
struct cast5_key {
ulong32 K[32], keylen;
};
#endif
#ifdef LTC_NOEKEON
struct noekeon_key {
ulong32 K[4], dK[4];
};
#endif
#ifdef LTC_SKIPJACK
struct skipjack_key {
unsigned char key[10];
};
#endif
#ifdef LTC_KHAZAD
struct khazad_key {
ulong64 roundKeyEnc[8 + 1];
ulong64 roundKeyDec[8 + 1];
};
#endif
#ifdef LTC_ANUBIS
struct anubis_key {
int keyBits;
int R;
ulong32 roundKeyEnc[18 + 1][4];
ulong32 roundKeyDec[18 + 1][4];
};
#endif
#ifdef LTC_MULTI2
struct multi2_key {
int N;
ulong32 uk[8];
};
#endif
typedef union Symmetric_key {
#ifdef LTC_DES
struct des_key des;
struct des3_key des3;
#endif
#ifdef LTC_RC2
struct rc2_key rc2;
#endif
#ifdef LTC_SAFER
struct safer_key safer;
#endif
#ifdef LTC_TWOFISH
struct twofish_key twofish;
#endif
#ifdef LTC_BLOWFISH
struct blowfish_key blowfish;
#endif
#ifdef LTC_RC5
struct rc5_key rc5;
#endif
#ifdef LTC_RC6
struct rc6_key rc6;
#endif
#ifdef LTC_SAFERP
struct saferp_key saferp;
#endif
#ifdef LTC_RIJNDAEL
struct rijndael_key rijndael;
#endif
#ifdef LTC_XTEA
struct xtea_key xtea;
#endif
#ifdef LTC_CAST5
struct cast5_key cast5;
#endif
#ifdef LTC_NOEKEON
struct noekeon_key noekeon;
#endif
#ifdef LTC_SKIPJACK
struct skipjack_key skipjack;
#endif
#ifdef LTC_KHAZAD
struct khazad_key khazad;
#endif
#ifdef LTC_ANUBIS
struct anubis_key anubis;
#endif
#ifdef LTC_KSEED
struct kseed_key kseed;
#endif
#ifdef LTC_KASUMI
struct kasumi_key kasumi;
#endif
#ifdef LTC_MULTI2
struct multi2_key multi2;
#endif
void *data;
} symmetric_key;
#ifdef LTC_ECB_MODE
/** A block cipher ECB structure */
typedef struct {
/** The index of the cipher chosen */
int cipher,
/** The block size of the given cipher */
blocklen;
/** The scheduled key */
symmetric_key key;
} symmetric_ECB;
#endif
#ifdef LTC_CFB_MODE
/** A block cipher CFB structure */
typedef struct {
/** The index of the cipher chosen */
int cipher,
/** The block size of the given cipher */
blocklen,
/** The padding offset */
padlen;
/** The current IV */
unsigned char IV[MAXBLOCKSIZE],
/** The pad used to encrypt/decrypt */
pad[MAXBLOCKSIZE];
/** The scheduled key */
symmetric_key key;
} symmetric_CFB;
#endif
#ifdef LTC_OFB_MODE
/** A block cipher OFB structure */
typedef struct {
/** The index of the cipher chosen */
int cipher,
/** The block size of the given cipher */
blocklen,
/** The padding offset */
padlen;
/** The current IV */
unsigned char IV[MAXBLOCKSIZE];
/** The scheduled key */
symmetric_key key;
} symmetric_OFB;
#endif
#ifdef LTC_CBC_MODE
/** A block cipher CBC structure */
typedef struct {
/** The index of the cipher chosen */
int cipher,
/** The block size of the given cipher */
blocklen;
/** The current IV */
unsigned char IV[MAXBLOCKSIZE];
/** The scheduled key */
symmetric_key key;
} symmetric_CBC;
#endif
#ifdef LTC_CTR_MODE
/** A block cipher CTR structure */
typedef struct {
/** The index of the cipher chosen */
int cipher,
/** The block size of the given cipher */
blocklen,
/** The padding offset */
padlen,
/** The mode (endianess) of the CTR, 0==little, 1==big */
mode,
/** counter width */
ctrlen;
/** The counter */
unsigned char ctr[MAXBLOCKSIZE],
/** The pad used to encrypt/decrypt */
pad[MAXBLOCKSIZE];
/** The scheduled key */
symmetric_key key;
} symmetric_CTR;
#endif
#ifdef LTC_LRW_MODE
/** A LRW structure */
typedef struct {
/** The index of the cipher chosen (must be a 128-bit block cipher) */
int cipher;
/** The current IV */
unsigned char IV[16],
/** the tweak key */
tweak[16],
/** The current pad, it's the product of the first 15 bytes against the tweak key */
pad[16];
/** The scheduled symmetric key */
symmetric_key key;
#ifdef LRW_TABLES
/** The pre-computed multiplication table */
unsigned char PC[16][256][16];
#endif
} symmetric_LRW;
#endif
#ifdef LTC_F8_MODE
/** A block cipher F8 structure */
typedef struct {
/** The index of the cipher chosen */
int cipher,
/** The block size of the given cipher */
blocklen,
/** The padding offset */
padlen;
/** The current IV */
unsigned char IV[MAXBLOCKSIZE],
MIV[MAXBLOCKSIZE];
/** Current block count */
ulong32 blockcnt;
/** The scheduled key */
symmetric_key key;
} symmetric_F8;
#endif
/** cipher descriptor table, last entry has "name == NULL" to mark the end of table */
extern struct ltc_cipher_descriptor {
/** name of cipher */
char *name;
/** internal ID */
unsigned char ID;
/** min keysize (octets) */
int min_key_length,
/** max keysize (octets) */
max_key_length,
/** block size (octets) */
block_length,
/** default number of rounds */
default_rounds;
/** Setup the cipher
@param key The input symmetric key
@param keylen The length of the input key (octets)
@param num_rounds The requested number of rounds (0==default)
@param skey [out] The destination of the scheduled key
@return CRYPT_OK if successful
*/
int (*setup)(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
/** Encrypt a block
@param pt The plaintext
@param ct [out] The ciphertext
@param skey The scheduled key
@return CRYPT_OK if successful
*/
int (*ecb_encrypt)(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
/** Decrypt a block
@param ct The ciphertext
@param pt [out] The plaintext
@param skey The scheduled key
@return CRYPT_OK if successful
*/
int (*ecb_decrypt)(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
/** Test the block cipher
@return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
*/
int (*test)(void);
/** Terminate the context
@param skey The scheduled key
*/
void (*done)(symmetric_key *skey);
/** Determine a key size
@param keysize [in/out] The size of the key desired and the suggested size
@return CRYPT_OK if successful
*/
int (*keysize)(int *keysize);
/** Accelerators **/
/** Accelerated ECB encryption
@param pt Plaintext
@param ct Ciphertext
@param blocks The number of complete blocks to process
@param skey The scheduled key context
@return CRYPT_OK if successful
*/
int (*accel_ecb_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, symmetric_key *skey);
/** Accelerated ECB decryption
@param pt Plaintext
@param ct Ciphertext
@param blocks The number of complete blocks to process
@param skey The scheduled key context
@return CRYPT_OK if successful
*/
int (*accel_ecb_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, symmetric_key *skey);
/** Accelerated CBC encryption
@param pt Plaintext
@param ct Ciphertext
@param blocks The number of complete blocks to process
@param IV The initial value (input/output)
@param skey The scheduled key context
@return CRYPT_OK if successful
*/
int (*accel_cbc_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, symmetric_key *skey);
/** Accelerated CBC decryption
@param pt Plaintext
@param ct Ciphertext
@param blocks The number of complete blocks to process
@param IV The initial value (input/output)
@param skey The scheduled key context
@return CRYPT_OK if successful
*/
int (*accel_cbc_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, unsigned char *IV, symmetric_key *skey);
/** Accelerated CTR encryption
@param pt Plaintext
@param ct Ciphertext
@param blocks The number of complete blocks to process
@param IV The initial value (input/output)
@param mode little or big endian counter (mode=0 or mode=1)
@param skey The scheduled key context
@return CRYPT_OK if successful
*/
int (*accel_ctr_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, int mode, symmetric_key *skey);
/** Accelerated LRW
@param pt Plaintext
@param ct Ciphertext
@param blocks The number of complete blocks to process
@param IV The initial value (input/output)
@param tweak The LRW tweak
@param skey The scheduled key context
@return CRYPT_OK if successful
*/
int (*accel_lrw_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, const unsigned char *tweak, symmetric_key *skey);
/** Accelerated LRW
@param ct Ciphertext
@param pt Plaintext
@param blocks The number of complete blocks to process
@param IV The initial value (input/output)
@param tweak The LRW tweak
@param skey The scheduled key context
@return CRYPT_OK if successful
*/
int (*accel_lrw_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, unsigned char *IV, const unsigned char *tweak, symmetric_key *skey);
/** Accelerated CCM packet (one-shot)
@param key The secret key to use
@param keylen The length of the secret key (octets)
@param uskey A previously scheduled key [optional can be NULL]
@param nonce The session nonce [use once]
@param noncelen The length of the nonce
@param header The header for the session
@param headerlen The length of the header (octets)
@param pt [out] The plaintext
@param ptlen The length of the plaintext (octets)
@param ct [out] The ciphertext
@param tag [out] The destination tag
@param taglen [in/out] The max size and resulting size of the authentication tag
@param direction Encrypt or Decrypt direction (0 or 1)
@return CRYPT_OK if successful
*/
int (*accel_ccm_memory)(
const unsigned char *key, unsigned long keylen,
symmetric_key *uskey,
const unsigned char *nonce, unsigned long noncelen,
const unsigned char *header, unsigned long headerlen,
unsigned char *pt, unsigned long ptlen,
unsigned char *ct,
unsigned char *tag, unsigned long *taglen,
int direction);
/** Accelerated GCM packet (one shot)
@param key The secret key
@param keylen The length of the secret key
@param IV The initial vector
@param IVlen The length of the initial vector
@param adata The additional authentication data (header)
@param adatalen The length of the adata
@param pt The plaintext
@param ptlen The length of the plaintext (ciphertext length is the same)
@param ct The ciphertext
@param tag [out] The MAC tag
@param taglen [in/out] The MAC tag length
@param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
@return CRYPT_OK on success
*/
int (*accel_gcm_memory)(
const unsigned char *key, unsigned long keylen,
const unsigned char *IV, unsigned long IVlen,
const unsigned char *adata, unsigned long adatalen,
unsigned char *pt, unsigned long ptlen,
unsigned char *ct,
unsigned char *tag, unsigned long *taglen,
int direction);
/** Accelerated one shot LTC_OMAC
@param key The secret key
@param keylen The key length (octets)
@param in The message
@param inlen Length of message (octets)
@param out [out] Destination for tag
@param outlen [in/out] Initial and final size of out
@return CRYPT_OK on success
*/
int (*omac_memory)(
const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
/** Accelerated one shot XCBC
@param key The secret key
@param keylen The key length (octets)
@param in The message
@param inlen Length of message (octets)
@param out [out] Destination for tag
@param outlen [in/out] Initial and final size of out
@return CRYPT_OK on success
*/
int (*xcbc_memory)(
const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
/** Accelerated one shot F9
@param key The secret key
@param keylen The key length (octets)
@param in The message
@param inlen Length of message (octets)
@param out [out] Destination for tag
@param outlen [in/out] Initial and final size of out
@return CRYPT_OK on success
@remark Requires manual padding
*/
int (*f9_memory)(
const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
} cipher_descriptor[];
#ifdef LTC_BLOWFISH
int blowfish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int blowfish_test(void);
void blowfish_done(symmetric_key *skey);
int blowfish_keysize(int *keysize);
extern const struct ltc_cipher_descriptor blowfish_desc;
#endif
#ifdef LTC_RC5
int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int rc5_test(void);
void rc5_done(symmetric_key *skey);
int rc5_keysize(int *keysize);
extern const struct ltc_cipher_descriptor rc5_desc;
#endif
#ifdef LTC_RC6
int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int rc6_test(void);
void rc6_done(symmetric_key *skey);
int rc6_keysize(int *keysize);
extern const struct ltc_cipher_descriptor rc6_desc;
#endif
#ifdef LTC_RC2
int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int rc2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int rc2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int rc2_test(void);
void rc2_done(symmetric_key *skey);
int rc2_keysize(int *keysize);
extern const struct ltc_cipher_descriptor rc2_desc;
#endif
#ifdef LTC_SAFERP
int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int saferp_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int saferp_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int saferp_test(void);
void saferp_done(symmetric_key *skey);
int saferp_keysize(int *keysize);
extern const struct ltc_cipher_descriptor saferp_desc;
#endif
#ifdef LTC_SAFER
int safer_k64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int safer_sk64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int safer_k128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int safer_sk128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int safer_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
int safer_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
int safer_k64_test(void);
int safer_sk64_test(void);
int safer_sk128_test(void);
void safer_done(symmetric_key *skey);
int safer_64_keysize(int *keysize);
int safer_128_keysize(int *keysize);
extern const struct ltc_cipher_descriptor safer_k64_desc, safer_k128_desc, safer_sk64_desc, safer_sk128_desc;
#endif
#ifdef LTC_RIJNDAEL
/* make aes an alias */
#define aes_setup rijndael_setup
#define aes_ecb_encrypt rijndael_ecb_encrypt
#define aes_ecb_decrypt rijndael_ecb_decrypt
#define aes_test rijndael_test
#define aes_done rijndael_done
#define aes_keysize rijndael_keysize
#define aes_enc_setup rijndael_enc_setup
#define aes_enc_ecb_encrypt rijndael_enc_ecb_encrypt
#define aes_enc_keysize rijndael_enc_keysize
int rijndael_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int rijndael_test(void);
void rijndael_done(symmetric_key *skey);
int rijndael_keysize(int *keysize);
int rijndael_enc_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int rijndael_enc_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
void rijndael_enc_done(symmetric_key *skey);
int rijndael_enc_keysize(int *keysize);
extern const struct ltc_cipher_descriptor rijndael_desc, aes_desc;
extern const struct ltc_cipher_descriptor rijndael_enc_desc, aes_enc_desc;
#endif
#ifdef LTC_XTEA
int xtea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int xtea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int xtea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int xtea_test(void);
void xtea_done(symmetric_key *skey);
int xtea_keysize(int *keysize);
extern const struct ltc_cipher_descriptor xtea_desc;
#endif
#ifdef LTC_TWOFISH
int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int twofish_test(void);
void twofish_done(symmetric_key *skey);
int twofish_keysize(int *keysize);
extern const struct ltc_cipher_descriptor twofish_desc;
#endif
#ifdef LTC_DES
int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int des_test(void);
void des_done(symmetric_key *skey);
int des_keysize(int *keysize);
int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int des3_test(void);
void des3_done(symmetric_key *skey);
int des3_keysize(int *keysize);
extern const struct ltc_cipher_descriptor des_desc, des3_desc;
#endif
#ifdef LTC_CAST5
int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int cast5_test(void);
void cast5_done(symmetric_key *skey);
int cast5_keysize(int *keysize);
extern const struct ltc_cipher_descriptor cast5_desc;
#endif
#ifdef LTC_NOEKEON
int noekeon_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int noekeon_test(void);
void noekeon_done(symmetric_key *skey);
int noekeon_keysize(int *keysize);
extern const struct ltc_cipher_descriptor noekeon_desc;
#endif
#ifdef LTC_SKIPJACK
int skipjack_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int skipjack_test(void);
void skipjack_done(symmetric_key *skey);
int skipjack_keysize(int *keysize);
extern const struct ltc_cipher_descriptor skipjack_desc;
#endif
#ifdef LTC_KHAZAD
int khazad_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int khazad_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int khazad_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int khazad_test(void);
void khazad_done(symmetric_key *skey);
int khazad_keysize(int *keysize);
extern const struct ltc_cipher_descriptor khazad_desc;
#endif
#ifdef LTC_ANUBIS
int anubis_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int anubis_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int anubis_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int anubis_test(void);
void anubis_done(symmetric_key *skey);
int anubis_keysize(int *keysize);
extern const struct ltc_cipher_descriptor anubis_desc;
#endif
#ifdef LTC_KSEED
int kseed_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int kseed_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int kseed_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int kseed_test(void);
void kseed_done(symmetric_key *skey);
int kseed_keysize(int *keysize);
extern const struct ltc_cipher_descriptor kseed_desc;
#endif
#ifdef LTC_KASUMI
int kasumi_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int kasumi_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int kasumi_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int kasumi_test(void);
void kasumi_done(symmetric_key *skey);
int kasumi_keysize(int *keysize);
extern const struct ltc_cipher_descriptor kasumi_desc;
#endif
#ifdef LTC_MULTI2
int multi2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
int multi2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
int multi2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
int multi2_test(void);
void multi2_done(symmetric_key *skey);
int multi2_keysize(int *keysize);
extern const struct ltc_cipher_descriptor multi2_desc;
#endif
#ifdef LTC_ECB_MODE
int ecb_start(int cipher, const unsigned char *key,
int keylen, int num_rounds, symmetric_ECB *ecb);
int ecb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_ECB *ecb);
int ecb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_ECB *ecb);
int ecb_done(symmetric_ECB *ecb);
#endif
#ifdef LTC_CFB_MODE
int cfb_start(int cipher, const unsigned char *IV, const unsigned char *key,
int keylen, int num_rounds, symmetric_CFB *cfb);
int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb);
int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb);
int cfb_getiv(unsigned char *IV, unsigned long *len, symmetric_CFB *cfb);
int cfb_setiv(const unsigned char *IV, unsigned long len, symmetric_CFB *cfb);
int cfb_done(symmetric_CFB *cfb);
#endif
#ifdef LTC_OFB_MODE
int ofb_start(int cipher, const unsigned char *IV, const unsigned char *key,
int keylen, int num_rounds, symmetric_OFB *ofb);
int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_OFB *ofb);
int ofb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_OFB *ofb);
int ofb_getiv(unsigned char *IV, unsigned long *len, symmetric_OFB *ofb);
int ofb_setiv(const unsigned char *IV, unsigned long len, symmetric_OFB *ofb);
int ofb_done(symmetric_OFB *ofb);
#endif
#ifdef LTC_CBC_MODE
int cbc_start(int cipher, const unsigned char *IV, const unsigned char *key,
int keylen, int num_rounds, symmetric_CBC *cbc);
int cbc_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CBC *cbc);
int cbc_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CBC *cbc);
int cbc_getiv(unsigned char *IV, unsigned long *len, symmetric_CBC *cbc);
int cbc_setiv(const unsigned char *IV, unsigned long len, symmetric_CBC *cbc);
int cbc_done(symmetric_CBC *cbc);
#endif
#ifdef LTC_CTR_MODE
#define CTR_COUNTER_LITTLE_ENDIAN 0x0000
#define CTR_COUNTER_BIG_ENDIAN 0x1000
#define LTC_CTR_RFC3686 0x2000
int ctr_start( int cipher,
const unsigned char *IV,
const unsigned char *key, int keylen,
int num_rounds, int ctr_mode,
symmetric_CTR *ctr);
int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr);
int ctr_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CTR *ctr);
int ctr_getiv(unsigned char *IV, unsigned long *len, symmetric_CTR *ctr);
int ctr_setiv(const unsigned char *IV, unsigned long len, symmetric_CTR *ctr);
int ctr_done(symmetric_CTR *ctr);
int ctr_test(void);
#endif
#ifdef LTC_LRW_MODE
#define LRW_ENCRYPT 0
#define LRW_DECRYPT 1
int lrw_start( int cipher,
const unsigned char *IV,
const unsigned char *key, int keylen,
const unsigned char *tweak,
int num_rounds,
symmetric_LRW *lrw);
int lrw_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_LRW *lrw);
int lrw_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_LRW *lrw);
int lrw_getiv(unsigned char *IV, unsigned long *len, symmetric_LRW *lrw);
int lrw_setiv(const unsigned char *IV, unsigned long len, symmetric_LRW *lrw);
int lrw_done(symmetric_LRW *lrw);
int lrw_test(void);
/* don't call */
int lrw_process(const unsigned char *pt, unsigned char *ct, unsigned long len, int mode, symmetric_LRW *lrw);
#endif
#ifdef LTC_F8_MODE
int f8_start( int cipher, const unsigned char *IV,
const unsigned char *key, int keylen,
const unsigned char *salt_key, int skeylen,
int num_rounds, symmetric_F8 *f8);
int f8_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_F8 *f8);
int f8_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_F8 *f8);
int f8_getiv(unsigned char *IV, unsigned long *len, symmetric_F8 *f8);
int f8_setiv(const unsigned char *IV, unsigned long len, symmetric_F8 *f8);
int f8_done(symmetric_F8 *f8);
int f8_test_mode(void);
#endif
#ifdef LTC_XTS_MODE
typedef struct {
symmetric_key key1, key2;
int cipher;
} symmetric_xts;
int xts_start( int cipher,
const unsigned char *key1,
const unsigned char *key2,
unsigned long keylen,
int num_rounds,
symmetric_xts *xts);
int xts_encrypt(
const unsigned char *pt, unsigned long ptlen,
unsigned char *ct,
const unsigned char *tweak,
symmetric_xts *xts);
int xts_decrypt(
const unsigned char *ct, unsigned long ptlen,
unsigned char *pt,
const unsigned char *tweak,
symmetric_xts *xts);
void xts_done(symmetric_xts *xts);
int xts_test(void);
void xts_mult_x(unsigned char *I);
#endif
int find_cipher(const char *name);
int find_cipher_any(const char *name, int blocklen, int keylen);
int find_cipher_id(unsigned char ID);
int register_cipher(const struct ltc_cipher_descriptor *cipher);
int unregister_cipher(const struct ltc_cipher_descriptor *cipher);
int cipher_is_valid(int idx);
LTC_MUTEX_PROTO(ltc_cipher_mutex)
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_cipher.h,v $ */
/* $Revision: 1.54 $ */
/* $Date: 2007/05/12 14:37:41 $ */

View File

@@ -0,0 +1,424 @@
#ifndef TOMCRYPT_CUSTOM_H_
#define TOMCRYPT_CUSTOM_H_
#define LTC_NO_CIPHERS
#define LTC_NO_HASHES
#define LTC_NO_MACS
#define LTC_NO_PRNGS
#define LTC_NO_CURVES
#define LTC_NO_MODES
#define LTC_NO_PKCS
#define LTC_NO_ROLC
#define LTC_SOURCE
#define LTC_SHA1
#define LTC_MD5
#define LTC_DER
#define LTC_RC4
#define USE_LTM
#define LTM_DESC
/* macros for various libc functions you can change for embedded targets */
#ifndef XMALLOC
#ifdef malloc
#define LTC_NO_PROTOTYPES
#endif
#define XMALLOC LibTomMalloc
#endif
#ifndef XREALLOC
#ifdef realloc
#define LTC_NO_PROTOTYPES
#endif
#define XREALLOC LibTomRealloc
#endif
#ifndef XCALLOC
#ifdef calloc
#define LTC_NO_PROTOTYPES
#endif
#define XCALLOC LibTomCalloc
#endif
#ifndef XFREE
#ifdef free
#define LTC_NO_PROTOTYPES
#endif
#define XFREE LibTomFree
#endif
#ifndef XMEMSET
#ifdef memset
#define LTC_NO_PROTOTYPES
#endif
#define XMEMSET memset
#endif
#ifndef XMEMCPY
#ifdef memcpy
#define LTC_NO_PROTOTYPES
#endif
#define XMEMCPY memcpy
#endif
#ifndef XMEMCMP
#ifdef memcmp
#define LTC_NO_PROTOTYPES
#endif
#define XMEMCMP memcmp
#endif
#ifndef XSTRCMP
#ifdef strcmp
#define LTC_NO_PROTOTYPES
#endif
#define XSTRCMP strcmp
#endif
#ifndef XCLOCK
#define XCLOCK LibTomClock
#endif
#ifndef XCLOCKS_PER_SEC
#define XCLOCKS_PER_SEC CLOCKS_PER_SEC
#endif
#ifndef XQSORT
#ifdef qsort
#define LTC_NO_PROTOTYPES
#endif
#define XQSORT LibTomQsort
#endif
/* Easy button? */
#ifdef LTC_EASY
#define LTC_NO_CIPHERS
#define LTC_RIJNDAEL
#define LTC_BLOWFISH
#define LTC_DES
#define LTC_CAST5
#define LTC_NO_MODES
#define LTC_ECB_MODE
#define LTC_CBC_MODE
#define LTC_CTR_MODE
#define LTC_NO_HASHES
#define LTC_SHA1
#define LTC_SHA512
#define LTC_SHA384
#define LTC_SHA256
#define LTC_SHA224
#define LTC_NO_MACS
#define LTC_HMAC
#define LTC_OMAC
#define LTC_CCM_MODE
#define LTC_NO_PRNGS
#define LTC_SPRNG
#define LTC_YARROW
#define LTC_DEVRANDOM
#define TRY_URANDOM_FIRST
#define LTC_NO_PK
#define LTC_MRSA
#define LTC_MECC
#endif
/* Use small code where possible */
/* #define LTC_SMALL_CODE */
/* Enable self-test test vector checking */
#ifndef LTC_NO_TEST
#define LTC_TEST
#endif
/* clean the stack of functions which put private information on stack */
/* #define LTC_CLEAN_STACK */
/* disable all file related functions */
/* #define LTC_NO_FILE */
/* disable all forms of ASM */
/* #define LTC_NO_ASM */
/* disable FAST mode */
/* #define LTC_NO_FAST */
/* disable BSWAP on x86 */
/* #define LTC_NO_BSWAP */
/* ---> Symmetric Block Ciphers <--- */
#ifndef LTC_NO_CIPHERS
#define LTC_BLOWFISH
#define LTC_RC2
#define LTC_RC5
#define LTC_RC6
#define LTC_SAFERP
#define LTC_RIJNDAEL
#define LTC_XTEA
/* _TABLES tells it to use tables during setup, _SMALL means to use the smaller scheduled key format
* (saves 4KB of ram), _ALL_TABLES enables all tables during setup */
#define LTC_TWOFISH
#ifndef LTC_NO_TABLES
#define LTC_TWOFISH_TABLES
/* #define LTC_TWOFISH_ALL_TABLES */
#else
#define LTC_TWOFISH_SMALL
#endif
/* #define LTC_TWOFISH_SMALL */
/* LTC_DES includes EDE triple-LTC_DES */
#define LTC_DES
#define LTC_CAST5
#define LTC_NOEKEON
#define LTC_SKIPJACK
#define LTC_SAFER
#define LTC_KHAZAD
#define LTC_ANUBIS
#define LTC_ANUBIS_TWEAK
#define LTC_KSEED
#define LTC_KASUMI
#endif /* LTC_NO_CIPHERS */
/* ---> Block Cipher Modes of Operation <--- */
#ifndef LTC_NO_MODES
#define LTC_CFB_MODE
#define LTC_OFB_MODE
#define LTC_ECB_MODE
#define LTC_CBC_MODE
#define LTC_CTR_MODE
/* F8 chaining mode */
#define LTC_F8_MODE
/* LRW mode */
#define LTC_LRW_MODE
#ifndef LTC_NO_TABLES
/* like GCM mode this will enable 16 8x128 tables [64KB] that make
* seeking very fast.
*/
#define LRW_TABLES
#endif
/* XTS mode */
#define LTC_XTS_MODE
#endif /* LTC_NO_MODES */
/* ---> One-Way Hash Functions <--- */
#ifndef LTC_NO_HASHES
#define LTC_CHC_HASH
#define LTC_WHIRLPOOL
#define LTC_SHA512
#define LTC_SHA384
#define LTC_SHA256
#define LTC_SHA224
#define LTC_TIGER
#define LTC_SHA1
#define LTC_MD5
#define LTC_MD4
#define LTC_MD2
#define LTC_RIPEMD128
#define LTC_RIPEMD160
#define LTC_RIPEMD256
#define LTC_RIPEMD320
#endif /* LTC_NO_HASHES */
/* ---> MAC functions <--- */
#ifndef LTC_NO_MACS
#define LTC_HMAC
#define LTC_OMAC
#define LTC_PMAC
#define LTC_XCBC
#define LTC_F9_MODE
#define LTC_PELICAN
#if defined(LTC_PELICAN) && !defined(LTC_RIJNDAEL)
#error Pelican-MAC requires LTC_RIJNDAEL
#endif
/* ---> Encrypt + Authenticate Modes <--- */
#define LTC_EAX_MODE
#if defined(LTC_EAX_MODE) && !(defined(LTC_CTR_MODE) && defined(LTC_OMAC))
#error LTC_EAX_MODE requires CTR and LTC_OMAC mode
#endif
#define LTC_OCB_MODE
#define LTC_CCM_MODE
#define LTC_GCM_MODE
/* Use 64KiB tables */
#ifndef LTC_NO_TABLES
#define LTC_GCM_TABLES
#endif
/* USE SSE2? requires GCC works on x86_32 and x86_64*/
#ifdef LTC_GCM_TABLES
/* #define LTC_GCM_TABLES_SSE2 */
#endif
#endif /* LTC_NO_MACS */
/* Various tidbits of modern neatoness */
#define LTC_BASE64
/* --> Pseudo Random Number Generators <--- */
#ifndef LTC_NO_PRNGS
/* Yarrow */
#define LTC_YARROW
/* which descriptor of AES to use? */
/* 0 = rijndael_enc 1 = aes_enc, 2 = rijndael [full], 3 = aes [full] */
#define LTC_YARROW_AES 0
#if defined(LTC_YARROW) && !defined(LTC_CTR_MODE)
#error LTC_YARROW requires LTC_CTR_MODE chaining mode to be defined!
#endif
/* a PRNG that simply reads from an available system source */
#define LTC_SPRNG
/* The LTC_RC4 stream cipher */
#define LTC_RC4
/* Fortuna PRNG */
#define LTC_FORTUNA
/* reseed every N calls to the read function */
#define LTC_FORTUNA_WD 10
/* number of pools (4..32) can save a bit of ram by lowering the count */
#define LTC_FORTUNA_POOLS 32
/* Greg's LTC_SOBER128 PRNG ;-0 */
#define LTC_SOBER128
/* the *nix style /dev/random device */
#define LTC_DEVRANDOM
/* try /dev/urandom before trying /dev/random */
#define TRY_URANDOM_FIRST
#endif /* LTC_NO_PRNGS */
/* ---> math provider? <--- */
#ifndef LTC_NO_MATH
/* LibTomMath */
#define LTM_LTC_DESC
/* TomsFastMath */
//#define TFM_LTC_DESC
#endif /* LTC_NO_MATH */
/* ---> Public Key Crypto <--- */
#ifndef LTC_NO_PK
/* Include RSA support */
#define LTC_MRSA
/* Include Katja (a Rabin variant like RSA) */
/* #define MKAT */
/* Digital Signature Algorithm */
#define LTC_MDSA
/* ECC */
#define LTC_MECC
/* use Shamir's trick for point mul (speeds up signature verification) */
#define LTC_ECC_SHAMIR
#if defined(TFM_LTC_DESC) && defined(LTC_MECC)
#define LTC_MECC_ACCEL
#endif
/* do we want fixed point ECC */
/* #define LTC_MECC_FP */
/* Timing Resistant? */
/* #define LTC_ECC_TIMING_RESISTANT */
#endif /* LTC_NO_PK */
/* LTC_PKCS #1 (RSA) and #5 (Password Handling) stuff */
#ifndef LTC_NO_PKCS
#define LTC_PKCS_1
#define LTC_PKCS_5
/* Include ASN.1 DER (required by DSA/RSA) */
#define LTC_DER
#endif /* LTC_NO_PKCS */
/* cleanup */
#ifdef LTC_MECC
/* Supported ECC Key Sizes */
#ifndef LTC_NO_CURVES
#define ECC112
#define ECC128
#define ECC160
#define ECC192
#define ECC224
#define ECC256
#define ECC384
#define ECC521
#endif
#endif
#if defined(LTC_MECC) || defined(LTC_MRSA) || defined(LTC_MDSA) || defined(MKATJA)
/* Include the MPI functionality? (required by the PK algorithms) */
#define MPI
#endif
#ifdef LTC_MRSA
#define LTC_PKCS_1
#endif
#if defined(LTC_DER) && !defined(MPI)
#error ASN.1 DER requires MPI functionality
#endif
#if (defined(LTC_MDSA) || defined(LTC_MRSA) || defined(LTC_MECC) || defined(MKATJA)) && !defined(LTC_DER)
#error PK requires ASN.1 DER functionality, make sure LTC_DER is enabled
#endif
/* THREAD management */
#ifdef LTC_PTHREAD
#include <pthread.h>
#define LTC_MUTEX_GLOBAL(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER;
#define LTC_MUTEX_PROTO(x) extern pthread_mutex_t x;
#define LTC_MUTEX_TYPE(x) pthread_mutex_t x;
#define LTC_MUTEX_INIT(x) pthread_mutex_init(x, NULL);
#define LTC_MUTEX_LOCK(x) pthread_mutex_lock(x);
#define LTC_MUTEX_UNLOCK(x) pthread_mutex_unlock(x);
#else
/* default no functions */
#define LTC_MUTEX_GLOBAL(x)
#define LTC_MUTEX_PROTO(x)
#define LTC_MUTEX_TYPE(x)
#define LTC_MUTEX_INIT(x)
#define LTC_MUTEX_LOCK(x)
#define LTC_MUTEX_UNLOCK(x)
#endif
/* Debuggers */
/* define this if you use Valgrind, note: it CHANGES the way SOBER-128 and LTC_RC4 work (see the code) */
/* #define LTC_VALGRIND */
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_custom.h,v $ */
/* $Revision: 1.73 $ */
/* $Date: 2007/05/12 14:37:41 $ */

View File

@@ -0,0 +1,378 @@
/* ---- HASH FUNCTIONS ---- */
#ifdef LTC_SHA512
struct sha512_state {
ulong64 length, state[8];
unsigned long curlen;
unsigned char buf[128];
};
#endif
#ifdef LTC_SHA256
struct sha256_state {
ulong64 length;
ulong32 state[8], curlen;
unsigned char buf[64];
};
#endif
#ifdef LTC_SHA1
struct sha1_state {
ulong64 length;
ulong32 state[5], curlen;
unsigned char buf[64];
};
#endif
#ifdef LTC_MD5
struct md5_state {
ulong64 length;
ulong32 state[4], curlen;
unsigned char buf[64];
};
#endif
#ifdef LTC_MD4
struct md4_state {
ulong64 length;
ulong32 state[4], curlen;
unsigned char buf[64];
};
#endif
#ifdef LTC_TIGER
struct tiger_state {
ulong64 state[3], length;
unsigned long curlen;
unsigned char buf[64];
};
#endif
#ifdef LTC_MD2
struct md2_state {
unsigned char chksum[16], X[48], buf[16];
unsigned long curlen;
};
#endif
#ifdef LTC_RIPEMD128
struct rmd128_state {
ulong64 length;
unsigned char buf[64];
ulong32 curlen, state[4];
};
#endif
#ifdef LTC_RIPEMD160
struct rmd160_state {
ulong64 length;
unsigned char buf[64];
ulong32 curlen, state[5];
};
#endif
#ifdef LTC_RIPEMD256
struct rmd256_state {
ulong64 length;
unsigned char buf[64];
ulong32 curlen, state[8];
};
#endif
#ifdef LTC_RIPEMD320
struct rmd320_state {
ulong64 length;
unsigned char buf[64];
ulong32 curlen, state[10];
};
#endif
#ifdef LTC_WHIRLPOOL
struct whirlpool_state {
ulong64 length, state[8];
unsigned char buf[64];
ulong32 curlen;
};
#endif
#ifdef LTC_CHC_HASH
struct chc_state {
ulong64 length;
unsigned char state[MAXBLOCKSIZE], buf[MAXBLOCKSIZE];
ulong32 curlen;
};
#endif
typedef union Hash_state {
#ifdef LTC_CHC_HASH
struct chc_state chc;
#endif
#ifdef LTC_WHIRLPOOL
struct whirlpool_state whirlpool;
#endif
#ifdef LTC_SHA512
struct sha512_state sha512;
#endif
#ifdef LTC_SHA256
struct sha256_state sha256;
#endif
#ifdef LTC_SHA1
struct sha1_state sha1;
#endif
#ifdef LTC_MD5
struct md5_state md5;
#endif
#ifdef LTC_MD4
struct md4_state md4;
#endif
#ifdef LTC_MD2
struct md2_state md2;
#endif
#ifdef LTC_TIGER
struct tiger_state tiger;
#endif
#ifdef LTC_RIPEMD128
struct rmd128_state rmd128;
#endif
#ifdef LTC_RIPEMD160
struct rmd160_state rmd160;
#endif
#ifdef LTC_RIPEMD256
struct rmd256_state rmd256;
#endif
#ifdef LTC_RIPEMD320
struct rmd320_state rmd320;
#endif
void *data;
} hash_state;
/** hash descriptor */
extern struct ltc_hash_descriptor {
/** name of hash */
char *name;
/** internal ID */
unsigned char ID;
/** Size of digest in octets */
unsigned long hashsize;
/** Input block size in octets */
unsigned long blocksize;
/** ASN.1 OID */
unsigned long OID[16];
/** Length of DER encoding */
unsigned long OIDlen;
/** Init a hash state
@param hash The hash to initialize
@return CRYPT_OK if successful
*/
int (*init)(hash_state *hash);
/** Process a block of data
@param hash The hash state
@param in The data to hash
@param inlen The length of the data (octets)
@return CRYPT_OK if successful
*/
int (*process)(hash_state *hash, const unsigned char *in, unsigned long inlen);
/** Produce the digest and store it
@param hash The hash state
@param out [out] The destination of the digest
@return CRYPT_OK if successful
*/
int (*done)(hash_state *hash, unsigned char *out);
/** Self-test
@return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
*/
int (*test)(void);
/* accelerated hmac callback: if you need to-do multiple packets just use the generic hmac_memory and provide a hash callback */
int (*hmac_block)(const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
} hash_descriptor[];
#ifdef LTC_CHC_HASH
int chc_register(int cipher);
int chc_init(hash_state * md);
int chc_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int chc_done(hash_state * md, unsigned char *hash);
int chc_test(void);
extern const struct ltc_hash_descriptor chc_desc;
#endif
#ifdef LTC_WHIRLPOOL
int whirlpool_init(hash_state * md);
int whirlpool_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int whirlpool_done(hash_state * md, unsigned char *hash);
int whirlpool_test(void);
extern const struct ltc_hash_descriptor whirlpool_desc;
#endif
#ifdef LTC_SHA512
int sha512_init(hash_state * md);
int sha512_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int sha512_done(hash_state * md, unsigned char *hash);
int sha512_test(void);
extern const struct ltc_hash_descriptor sha512_desc;
#endif
#ifdef LTC_SHA384
#ifndef LTC_SHA512
#error LTC_SHA512 is required for LTC_SHA384
#endif
int sha384_init(hash_state * md);
#define sha384_process sha512_process
int sha384_done(hash_state * md, unsigned char *hash);
int sha384_test(void);
extern const struct ltc_hash_descriptor sha384_desc;
#endif
#ifdef LTC_SHA256
int sha256_init(hash_state * md);
int sha256_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int sha256_done(hash_state * md, unsigned char *hash);
int sha256_test(void);
extern const struct ltc_hash_descriptor sha256_desc;
#ifdef LTC_SHA224
#ifndef LTC_SHA256
#error LTC_SHA256 is required for LTC_SHA224
#endif
int sha224_init(hash_state * md);
#define sha224_process sha256_process
int sha224_done(hash_state * md, unsigned char *hash);
int sha224_test(void);
extern const struct ltc_hash_descriptor sha224_desc;
#endif
#endif
#ifdef LTC_SHA1
int sha1_init(hash_state * md);
int sha1_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int sha1_done(hash_state * md, unsigned char *hash);
int sha1_test(void);
extern const struct ltc_hash_descriptor sha1_desc;
#endif
#ifdef LTC_MD5
int md5_init(hash_state * md);
int md5_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int md5_done(hash_state * md, unsigned char *hash);
int md5_test(void);
extern const struct ltc_hash_descriptor md5_desc;
#endif
#ifdef LTC_MD4
int md4_init(hash_state * md);
int md4_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int md4_done(hash_state * md, unsigned char *hash);
int md4_test(void);
extern const struct ltc_hash_descriptor md4_desc;
#endif
#ifdef LTC_MD2
int md2_init(hash_state * md);
int md2_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int md2_done(hash_state * md, unsigned char *hash);
int md2_test(void);
extern const struct ltc_hash_descriptor md2_desc;
#endif
#ifdef LTC_TIGER
int tiger_init(hash_state * md);
int tiger_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int tiger_done(hash_state * md, unsigned char *hash);
int tiger_test(void);
extern const struct ltc_hash_descriptor tiger_desc;
#endif
#ifdef LTC_RIPEMD128
int rmd128_init(hash_state * md);
int rmd128_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int rmd128_done(hash_state * md, unsigned char *hash);
int rmd128_test(void);
extern const struct ltc_hash_descriptor rmd128_desc;
#endif
#ifdef LTC_RIPEMD160
int rmd160_init(hash_state * md);
int rmd160_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int rmd160_done(hash_state * md, unsigned char *hash);
int rmd160_test(void);
extern const struct ltc_hash_descriptor rmd160_desc;
#endif
#ifdef LTC_RIPEMD256
int rmd256_init(hash_state * md);
int rmd256_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int rmd256_done(hash_state * md, unsigned char *hash);
int rmd256_test(void);
extern const struct ltc_hash_descriptor rmd256_desc;
#endif
#ifdef LTC_RIPEMD320
int rmd320_init(hash_state * md);
int rmd320_process(hash_state * md, const unsigned char *in, unsigned long inlen);
int rmd320_done(hash_state * md, unsigned char *hash);
int rmd320_test(void);
extern const struct ltc_hash_descriptor rmd320_desc;
#endif
int find_hash(const char *name);
int find_hash_id(unsigned char ID);
int find_hash_oid(const unsigned long *ID, unsigned long IDlen);
int find_hash_any(const char *name, int digestlen);
int register_hash(const struct ltc_hash_descriptor *hash);
int unregister_hash(const struct ltc_hash_descriptor *hash);
int hash_is_valid(int idx);
LTC_MUTEX_PROTO(ltc_hash_mutex)
int hash_memory(int hash,
const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int hash_memory_multi(int hash, unsigned char *out, unsigned long *outlen,
const unsigned char *in, unsigned long inlen, ...);
int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen);
int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen);
/* a simple macro for making hash "process" functions */
#define HASH_PROCESS(func_name, compress_name, state_var, block_size) \
int func_name (hash_state * md, const unsigned char *in, unsigned long inlen) \
{ \
unsigned long n; \
int err; \
LTC_ARGCHK(md != NULL); \
LTC_ARGCHK(in != NULL); \
if (md-> state_var .curlen > sizeof(md-> state_var .buf)) { \
return CRYPT_INVALID_ARG; \
} \
while (inlen > 0) { \
if (md-> state_var .curlen == 0 && inlen >= block_size) { \
if ((err = compress_name (md, (unsigned char *)in)) != CRYPT_OK) { \
return err; \
} \
md-> state_var .length += block_size * 8; \
in += block_size; \
inlen -= block_size; \
} else { \
n = MIN(inlen, (block_size - md-> state_var .curlen)); \
memcpy(md-> state_var .buf + md-> state_var.curlen, in, (size_t)n); \
md-> state_var .curlen += n; \
in += n; \
inlen -= n; \
if (md-> state_var .curlen == block_size) { \
if ((err = compress_name (md, md-> state_var .buf)) != CRYPT_OK) { \
return err; \
} \
md-> state_var .length += 8*block_size; \
md-> state_var .curlen = 0; \
} \
} \
} \
return CRYPT_OK; \
}
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_hash.h,v $ */
/* $Revision: 1.22 $ */
/* $Date: 2007/05/12 14:32:35 $ */

View File

@@ -0,0 +1,384 @@
#ifdef LTC_HMAC
typedef struct Hmac_state {
hash_state md;
int hash;
hash_state hashstate;
unsigned char *key;
} hmac_state;
int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen);
int hmac_process(hmac_state *hmac, const unsigned char *in, unsigned long inlen);
int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen);
int hmac_test(void);
int hmac_memory(int hash,
const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int hmac_memory_multi(int hash,
const unsigned char *key, unsigned long keylen,
unsigned char *out, unsigned long *outlen,
const unsigned char *in, unsigned long inlen, ...);
int hmac_file(int hash, const char *fname, const unsigned char *key,
unsigned long keylen,
unsigned char *dst, unsigned long *dstlen);
#endif
#ifdef LTC_OMAC
typedef struct {
int cipher_idx,
buflen,
blklen;
unsigned char block[MAXBLOCKSIZE],
prev[MAXBLOCKSIZE],
Lu[2][MAXBLOCKSIZE];
symmetric_key key;
} omac_state;
int omac_init(omac_state *omac, int cipher, const unsigned char *key, unsigned long keylen);
int omac_process(omac_state *omac, const unsigned char *in, unsigned long inlen);
int omac_done(omac_state *omac, unsigned char *out, unsigned long *outlen);
int omac_memory(int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int omac_memory_multi(int cipher,
const unsigned char *key, unsigned long keylen,
unsigned char *out, unsigned long *outlen,
const unsigned char *in, unsigned long inlen, ...);
int omac_file(int cipher,
const unsigned char *key, unsigned long keylen,
const char *filename,
unsigned char *out, unsigned long *outlen);
int omac_test(void);
#endif /* LTC_OMAC */
#ifdef LTC_PMAC
typedef struct {
unsigned char Ls[32][MAXBLOCKSIZE], /* L shifted by i bits to the left */
Li[MAXBLOCKSIZE], /* value of Li [current value, we calc from previous recall] */
Lr[MAXBLOCKSIZE], /* L * x^-1 */
block[MAXBLOCKSIZE], /* currently accumulated block */
checksum[MAXBLOCKSIZE]; /* current checksum */
symmetric_key key; /* scheduled key for cipher */
unsigned long block_index; /* index # for current block */
int cipher_idx, /* cipher idx */
block_len, /* length of block */
buflen; /* number of bytes in the buffer */
} pmac_state;
int pmac_init(pmac_state *pmac, int cipher, const unsigned char *key, unsigned long keylen);
int pmac_process(pmac_state *pmac, const unsigned char *in, unsigned long inlen);
int pmac_done(pmac_state *pmac, unsigned char *out, unsigned long *outlen);
int pmac_memory(int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *msg, unsigned long msglen,
unsigned char *out, unsigned long *outlen);
int pmac_memory_multi(int cipher,
const unsigned char *key, unsigned long keylen,
unsigned char *out, unsigned long *outlen,
const unsigned char *in, unsigned long inlen, ...);
int pmac_file(int cipher,
const unsigned char *key, unsigned long keylen,
const char *filename,
unsigned char *out, unsigned long *outlen);
int pmac_test(void);
/* internal functions */
int pmac_ntz(unsigned long x);
void pmac_shift_xor(pmac_state *pmac);
#endif /* PMAC */
#ifdef LTC_EAX_MODE
#if !(defined(LTC_OMAC) && defined(LTC_CTR_MODE))
#error LTC_EAX_MODE requires LTC_OMAC and CTR
#endif
typedef struct {
unsigned char N[MAXBLOCKSIZE];
symmetric_CTR ctr;
omac_state headeromac, ctomac;
} eax_state;
int eax_init(eax_state *eax, int cipher, const unsigned char *key, unsigned long keylen,
const unsigned char *nonce, unsigned long noncelen,
const unsigned char *header, unsigned long headerlen);
int eax_encrypt(eax_state *eax, const unsigned char *pt, unsigned char *ct, unsigned long length);
int eax_decrypt(eax_state *eax, const unsigned char *ct, unsigned char *pt, unsigned long length);
int eax_addheader(eax_state *eax, const unsigned char *header, unsigned long length);
int eax_done(eax_state *eax, unsigned char *tag, unsigned long *taglen);
int eax_encrypt_authenticate_memory(int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *nonce, unsigned long noncelen,
const unsigned char *header, unsigned long headerlen,
const unsigned char *pt, unsigned long ptlen,
unsigned char *ct,
unsigned char *tag, unsigned long *taglen);
int eax_decrypt_verify_memory(int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *nonce, unsigned long noncelen,
const unsigned char *header, unsigned long headerlen,
const unsigned char *ct, unsigned long ctlen,
unsigned char *pt,
unsigned char *tag, unsigned long taglen,
int *stat);
int eax_test(void);
#endif /* EAX MODE */
#ifdef LTC_OCB_MODE
typedef struct {
unsigned char L[MAXBLOCKSIZE], /* L value */
Ls[32][MAXBLOCKSIZE], /* L shifted by i bits to the left */
Li[MAXBLOCKSIZE], /* value of Li [current value, we calc from previous recall] */
Lr[MAXBLOCKSIZE], /* L * x^-1 */
R[MAXBLOCKSIZE], /* R value */
checksum[MAXBLOCKSIZE]; /* current checksum */
symmetric_key key; /* scheduled key for cipher */
unsigned long block_index; /* index # for current block */
int cipher, /* cipher idx */
block_len; /* length of block */
} ocb_state;
int ocb_init(ocb_state *ocb, int cipher,
const unsigned char *key, unsigned long keylen, const unsigned char *nonce);
int ocb_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned char *ct);
int ocb_decrypt(ocb_state *ocb, const unsigned char *ct, unsigned char *pt);
int ocb_done_encrypt(ocb_state *ocb,
const unsigned char *pt, unsigned long ptlen,
unsigned char *ct,
unsigned char *tag, unsigned long *taglen);
int ocb_done_decrypt(ocb_state *ocb,
const unsigned char *ct, unsigned long ctlen,
unsigned char *pt,
const unsigned char *tag, unsigned long taglen, int *stat);
int ocb_encrypt_authenticate_memory(int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *nonce,
const unsigned char *pt, unsigned long ptlen,
unsigned char *ct,
unsigned char *tag, unsigned long *taglen);
int ocb_decrypt_verify_memory(int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *nonce,
const unsigned char *ct, unsigned long ctlen,
unsigned char *pt,
const unsigned char *tag, unsigned long taglen,
int *stat);
int ocb_test(void);
/* internal functions */
void ocb_shift_xor(ocb_state *ocb, unsigned char *Z);
int ocb_ntz(unsigned long x);
int s_ocb_done(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen,
unsigned char *ct, unsigned char *tag, unsigned long *taglen, int mode);
#endif /* LTC_OCB_MODE */
#ifdef LTC_CCM_MODE
#define CCM_ENCRYPT 0
#define CCM_DECRYPT 1
int ccm_memory(int cipher,
const unsigned char *key, unsigned long keylen,
symmetric_key *uskey,
const unsigned char *nonce, unsigned long noncelen,
const unsigned char *header, unsigned long headerlen,
unsigned char *pt, unsigned long ptlen,
unsigned char *ct,
unsigned char *tag, unsigned long *taglen,
int direction);
int ccm_test(void);
#endif /* LTC_CCM_MODE */
#if defined(LRW_MODE) || defined(LTC_GCM_MODE)
void gcm_gf_mult(const unsigned char *a, const unsigned char *b, unsigned char *c);
#endif
/* table shared between GCM and LRW */
#if defined(LTC_GCM_TABLES) || defined(LRW_TABLES) || ((defined(LTC_GCM_MODE) || defined(LTC_GCM_MODE)) && defined(LTC_FAST))
extern const unsigned char gcm_shift_table[];
#endif
#ifdef LTC_GCM_MODE
#define GCM_ENCRYPT 0
#define GCM_DECRYPT 1
#define LTC_GCM_MODE_IV 0
#define LTC_GCM_MODE_AAD 1
#define LTC_GCM_MODE_TEXT 2
typedef struct {
symmetric_key K;
unsigned char H[16], /* multiplier */
X[16], /* accumulator */
Y[16], /* counter */
Y_0[16], /* initial counter */
buf[16]; /* buffer for stuff */
int cipher, /* which cipher */
ivmode, /* Which mode is the IV in? */
mode, /* mode the GCM code is in */
buflen; /* length of data in buf */
ulong64 totlen, /* 64-bit counter used for IV and AAD */
pttotlen; /* 64-bit counter for the PT */
#ifdef LTC_GCM_TABLES
unsigned char PC[16][256][16] /* 16 tables of 8x128 */
#ifdef LTC_GCM_TABLES_SSE2
__attribute__ ((aligned (16)))
#endif
;
#endif
} gcm_state;
void gcm_mult_h(gcm_state *gcm, unsigned char *I);
int gcm_init(gcm_state *gcm, int cipher,
const unsigned char *key, int keylen);
int gcm_reset(gcm_state *gcm);
int gcm_add_iv(gcm_state *gcm,
const unsigned char *IV, unsigned long IVlen);
int gcm_add_aad(gcm_state *gcm,
const unsigned char *adata, unsigned long adatalen);
int gcm_process(gcm_state *gcm,
unsigned char *pt, unsigned long ptlen,
unsigned char *ct,
int direction);
int gcm_done(gcm_state *gcm,
unsigned char *tag, unsigned long *taglen);
int gcm_memory( int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *IV, unsigned long IVlen,
const unsigned char *adata, unsigned long adatalen,
unsigned char *pt, unsigned long ptlen,
unsigned char *ct,
unsigned char *tag, unsigned long *taglen,
int direction);
int gcm_test(void);
#endif /* LTC_GCM_MODE */
#ifdef LTC_PELICAN
typedef struct pelican_state
{
symmetric_key K;
unsigned char state[16];
int buflen;
} pelican_state;
int pelican_init(pelican_state *pelmac, const unsigned char *key, unsigned long keylen);
int pelican_process(pelican_state *pelmac, const unsigned char *in, unsigned long inlen);
int pelican_done(pelican_state *pelmac, unsigned char *out);
int pelican_test(void);
int pelican_memory(const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
unsigned char *out);
#endif
#ifdef LTC_XCBC
/* add this to "keylen" to xcbc_init to use a pure three-key XCBC MAC */
#define LTC_XCBC_PURE 0x8000UL
typedef struct {
unsigned char K[3][MAXBLOCKSIZE],
IV[MAXBLOCKSIZE];
symmetric_key key;
int cipher,
buflen,
blocksize;
} xcbc_state;
int xcbc_init(xcbc_state *xcbc, int cipher, const unsigned char *key, unsigned long keylen);
int xcbc_process(xcbc_state *xcbc, const unsigned char *in, unsigned long inlen);
int xcbc_done(xcbc_state *xcbc, unsigned char *out, unsigned long *outlen);
int xcbc_memory(int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int xcbc_memory_multi(int cipher,
const unsigned char *key, unsigned long keylen,
unsigned char *out, unsigned long *outlen,
const unsigned char *in, unsigned long inlen, ...);
int xcbc_file(int cipher,
const unsigned char *key, unsigned long keylen,
const char *filename,
unsigned char *out, unsigned long *outlen);
int xcbc_test(void);
#endif
#ifdef LTC_F9_MODE
typedef struct {
unsigned char akey[MAXBLOCKSIZE],
ACC[MAXBLOCKSIZE],
IV[MAXBLOCKSIZE];
symmetric_key key;
int cipher,
buflen,
keylen,
blocksize;
} f9_state;
int f9_init(f9_state *f9, int cipher, const unsigned char *key, unsigned long keylen);
int f9_process(f9_state *f9, const unsigned char *in, unsigned long inlen);
int f9_done(f9_state *f9, unsigned char *out, unsigned long *outlen);
int f9_memory(int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int f9_memory_multi(int cipher,
const unsigned char *key, unsigned long keylen,
unsigned char *out, unsigned long *outlen,
const unsigned char *in, unsigned long inlen, ...);
int f9_file(int cipher,
const unsigned char *key, unsigned long keylen,
const char *filename,
unsigned char *out, unsigned long *outlen);
int f9_test(void);
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_mac.h,v $ */
/* $Revision: 1.23 $ */
/* $Date: 2007/05/12 14:37:41 $ */

View File

@@ -0,0 +1,424 @@
/* fix for MSVC ...evil! */
#ifdef _MSC_VER
#define CONST64(n) n ## ui64
typedef unsigned __int64 ulong64;
#else
#define CONST64(n) n ## ULL
typedef unsigned long long ulong64;
#endif
/* this is the "32-bit at least" data type
* Re-define it to suit your platform but it must be at least 32-bits
*/
#if defined(__x86_64__) || (defined(__sparc__) && defined(__arch64__))
typedef unsigned ulong32;
#else
typedef unsigned long ulong32;
#endif
/* ---- HELPER MACROS ---- */
#ifdef ENDIAN_NEUTRAL
#define STORE32L(x, y) \
{ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
(y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
#define LOAD32L(x, y) \
{ x = ((unsigned long)((y)[3] & 255)<<24) | \
((unsigned long)((y)[2] & 255)<<16) | \
((unsigned long)((y)[1] & 255)<<8) | \
((unsigned long)((y)[0] & 255)); }
#define STORE64L(x, y) \
{ (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
(y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
(y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
(y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
#define LOAD64L(x, y) \
{ x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
(((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
(((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
(((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
#define STORE32H(x, y) \
{ (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
(y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
#define LOAD32H(x, y) \
{ x = ((unsigned long)((y)[0] & 255)<<24) | \
((unsigned long)((y)[1] & 255)<<16) | \
((unsigned long)((y)[2] & 255)<<8) | \
((unsigned long)((y)[3] & 255)); }
#define STORE64H(x, y) \
{ (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
#define LOAD64H(x, y) \
{ x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
(((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
(((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
(((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
#endif /* ENDIAN_NEUTRAL */
#ifdef ENDIAN_LITTLE
#if !defined(LTC_NO_BSWAP) && (defined(INTEL_CC) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__) || defined(__x86_64__))))
#define STORE32H(x, y) \
asm __volatile__ ( \
"bswapl %0 \n\t" \
"movl %0,(%1)\n\t" \
"bswapl %0 \n\t" \
::"r"(x), "r"(y));
#define LOAD32H(x, y) \
asm __volatile__ ( \
"movl (%1),%0\n\t" \
"bswapl %0\n\t" \
:"=r"(x): "r"(y));
#else
#define STORE32H(x, y) \
{ (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
(y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
#define LOAD32H(x, y) \
{ x = ((unsigned long)((y)[0] & 255)<<24) | \
((unsigned long)((y)[1] & 255)<<16) | \
((unsigned long)((y)[2] & 255)<<8) | \
((unsigned long)((y)[3] & 255)); }
#endif
/* x86_64 processor */
#if !defined(LTC_NO_BSWAP) && (defined(__GNUC__) && defined(__x86_64__))
#define STORE64H(x, y) \
asm __volatile__ ( \
"bswapq %0 \n\t" \
"movq %0,(%1)\n\t" \
"bswapq %0 \n\t" \
::"r"(x), "r"(y));
#define LOAD64H(x, y) \
asm __volatile__ ( \
"movq (%1),%0\n\t" \
"bswapq %0\n\t" \
:"=r"(x): "r"(y));
#else
#define STORE64H(x, y) \
{ (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
#define LOAD64H(x, y) \
{ x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
(((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
(((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
(((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
#endif
#ifdef ENDIAN_32BITWORD
#define STORE32L(x, y) \
{ ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
#define LOAD32L(x, y) \
XMEMCPY(&(x), y, 4);
#define STORE64L(x, y) \
{ (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
(y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
(y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
(y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
#define LOAD64L(x, y) \
{ x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
(((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
(((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
(((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
#else /* 64-bit words then */
#define STORE32L(x, y) \
{ ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
#define LOAD32L(x, y) \
{ XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; }
#define STORE64L(x, y) \
{ ulong64 __t = (x); XMEMCPY(y, &__t, 8); }
#define LOAD64L(x, y) \
{ XMEMCPY(&(x), y, 8); }
#endif /* ENDIAN_64BITWORD */
#endif /* ENDIAN_LITTLE */
#ifdef ENDIAN_BIG
#define STORE32L(x, y) \
{ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
(y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
#define LOAD32L(x, y) \
{ x = ((unsigned long)((y)[3] & 255)<<24) | \
((unsigned long)((y)[2] & 255)<<16) | \
((unsigned long)((y)[1] & 255)<<8) | \
((unsigned long)((y)[0] & 255)); }
#define STORE64L(x, y) \
{ (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
(y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
(y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
(y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
#define LOAD64L(x, y) \
{ x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \
(((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \
(((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \
(((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
#ifdef ENDIAN_32BITWORD
#define STORE32H(x, y) \
{ ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
#define LOAD32H(x, y) \
XMEMCPY(&(x), y, 4);
#define STORE64H(x, y) \
{ (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
#define LOAD64H(x, y) \
{ x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \
(((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \
(((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \
(((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); }
#else /* 64-bit words then */
#define STORE32H(x, y) \
{ ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
#define LOAD32H(x, y) \
{ XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; }
#define STORE64H(x, y) \
{ ulong64 __t = (x); XMEMCPY(y, &__t, 8); }
#define LOAD64H(x, y) \
{ XMEMCPY(&(x), y, 8); }
#endif /* ENDIAN_64BITWORD */
#endif /* ENDIAN_BIG */
#define BSWAP(x) ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL) | \
((x>>8)&0x0000FF00UL) | ((x<<8)&0x00FF0000UL) )
/* 32-bit Rotates */
#if defined(_MSC_VER)
/* instrinsic rotate */
#include <stdlib.h>
#pragma intrinsic(_lrotr,_lrotl)
#define ROR(x,n) _lrotr(x,n)
#define ROL(x,n) _lrotl(x,n)
#define RORc(x,n) _lrotr(x,n)
#define ROLc(x,n) _lrotl(x,n)
#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(LTC_NO_ASM)
static inline unsigned ROL(unsigned word, int i)
{
asm ("roll %%cl,%0"
:"=r" (word)
:"0" (word),"c" (i));
return word;
}
static inline unsigned ROR(unsigned word, int i)
{
asm ("rorl %%cl,%0"
:"=r" (word)
:"0" (word),"c" (i));
return word;
}
#ifndef LTC_NO_ROLC
static inline unsigned ROLc(unsigned word, const int i)
{
asm ("roll %2,%0"
:"=r" (word)
:"0" (word),"I" (i));
return word;
}
static inline unsigned RORc(unsigned word, const int i)
{
asm ("rorl %2,%0"
:"=r" (word)
:"0" (word),"I" (i));
return word;
}
#else
#define ROLc ROL
#define RORc ROR
#endif
#elif !defined(__STRICT_ANSI__) && defined(LTC_PPC32)
static inline unsigned ROL(unsigned word, int i)
{
asm ("rotlw %0,%0,%2"
:"=r" (word)
:"0" (word),"r" (i));
return word;
}
static inline unsigned ROR(unsigned word, int i)
{
asm ("rotlw %0,%0,%2"
:"=r" (word)
:"0" (word),"r" (32-i));
return word;
}
#ifndef LTC_NO_ROLC
static inline unsigned ROLc(unsigned word, const int i)
{
asm ("rotlwi %0,%0,%2"
:"=r" (word)
:"0" (word),"I" (i));
return word;
}
static inline unsigned RORc(unsigned word, const int i)
{
asm ("rotrwi %0,%0,%2"
:"=r" (word)
:"0" (word),"I" (i));
return word;
}
#else
#define ROLc ROL
#define RORc ROR
#endif
#else
/* rotates the hard way */
#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
#define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
#endif
/* 64-bit Rotates */
#if !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__x86_64__) && !defined(LTC_NO_ASM)
static inline unsigned long ROL64(unsigned long word, int i)
{
asm("rolq %%cl,%0"
:"=r" (word)
:"0" (word),"c" (i));
return word;
}
static inline unsigned long ROR64(unsigned long word, int i)
{
asm("rorq %%cl,%0"
:"=r" (word)
:"0" (word),"c" (i));
return word;
}
#ifndef LTC_NO_ROLC
static inline unsigned long ROL64c(unsigned long word, const int i)
{
asm("rolq %2,%0"
:"=r" (word)
:"0" (word),"J" (i));
return word;
}
static inline unsigned long ROR64c(unsigned long word, const int i)
{
asm("rorq %2,%0"
:"=r" (word)
:"0" (word),"J" (i));
return word;
}
#else /* LTC_NO_ROLC */
#define ROL64c ROL64
#define ROR64c ROR64
#endif
#else /* Not x86_64 */
#define ROL64(x, y) \
( (((x)<<((ulong64)(y)&63)) | \
(((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
#define ROR64(x, y) \
( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
#define ROL64c(x, y) \
( (((x)<<((ulong64)(y)&63)) | \
(((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
#define ROR64c(x, y) \
( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
#endif
#ifndef MAX
#define MAX(x, y) ( ((x)>(y))?(x):(y) )
#endif
#ifndef MIN
#define MIN(x, y) ( ((x)<(y))?(x):(y) )
#endif
/* extract a byte portably */
#ifdef _MSC_VER
#define byte(x, n) ((unsigned char)((x) >> (8 * (n))))
#else
#define byte(x, n) (((x) >> (8 * (n))) & 255)
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_macros.h,v $ */
/* $Revision: 1.15 $ */
/* $Date: 2006/11/29 23:43:57 $ */

View File

@@ -0,0 +1,500 @@
/** math functions **/
#define LTC_MP_LT -1
#define LTC_MP_EQ 0
#define LTC_MP_GT 1
#define LTC_MP_NO 0
#define LTC_MP_YES 1
#ifndef LTC_MECC
typedef void ecc_point;
#endif
#ifndef LTC_MRSA
typedef void rsa_key;
#endif
/** math descriptor */
typedef struct {
/** Name of the math provider */
char *name;
/** Bits per digit, amount of bits must fit in an unsigned long */
int bits_per_digit;
/* ---- init/deinit functions ---- */
/** initialize a bignum
@param a The number to initialize
@return CRYPT_OK on success
*/
int (*init)(void **a);
/** init copy
@param dst The number to initialize and write to
@param src The number to copy from
@return CRYPT_OK on success
*/
int (*init_copy)(void **dst, void *src);
/** deinit
@param a The number to free
@return CRYPT_OK on success
*/
void (*deinit)(void *a);
/* ---- data movement ---- */
/** negate
@param src The number to negate
@param dst The destination
@return CRYPT_OK on success
*/
int (*neg)(void *src, void *dst);
/** copy
@param src The number to copy from
@param dst The number to write to
@return CRYPT_OK on success
*/
int (*copy)(void *src, void *dst);
/* ---- trivial low level functions ---- */
/** set small constant
@param a Number to write to
@param n Source upto bits_per_digit (actually meant for very small constants)
@return CRYPT_OK on succcess
*/
int (*set_int)(void *a, unsigned long n);
/** get small constant
@param a Number to read, only fetches upto bits_per_digit from the number
@return The lower bits_per_digit of the integer (unsigned)
*/
unsigned long (*get_int)(void *a);
/** get digit n
@param a The number to read from
@param n The number of the digit to fetch
@return The bits_per_digit sized n'th digit of a
*/
unsigned long (*get_digit)(void *a, int n);
/** Get the number of digits that represent the number
@param a The number to count
@return The number of digits used to represent the number
*/
int (*get_digit_count)(void *a);
/** compare two integers
@param a The left side integer
@param b The right side integer
@return LTC_MP_LT if a < b, LTC_MP_GT if a > b and LTC_MP_EQ otherwise. (signed comparison)
*/
int (*compare)(void *a, void *b);
/** compare against int
@param a The left side integer
@param b The right side integer (upto bits_per_digit)
@return LTC_MP_LT if a < b, LTC_MP_GT if a > b and LTC_MP_EQ otherwise. (signed comparison)
*/
int (*compare_d)(void *a, unsigned long n);
/** Count the number of bits used to represent the integer
@param a The integer to count
@return The number of bits required to represent the integer
*/
int (*count_bits)(void * a);
/** Count the number of LSB bits which are zero
@param a The integer to count
@return The number of contiguous zero LSB bits
*/
int (*count_lsb_bits)(void *a);
/** Compute a power of two
@param a The integer to store the power in
@param n The power of two you want to store (a = 2^n)
@return CRYPT_OK on success
*/
int (*twoexpt)(void *a , int n);
/* ---- radix conversions ---- */
/** read ascii string
@param a The integer to store into
@param str The string to read
@param radix The radix the integer has been represented in (2-64)
@return CRYPT_OK on success
*/
int (*read_radix)(void *a, const char *str, int radix);
/** write number to string
@param a The integer to store
@param str The destination for the string
@param radix The radix the integer is to be represented in (2-64)
@return CRYPT_OK on success
*/
int (*write_radix)(void *a, char *str, int radix);
/** get size as unsigned char string
@param a The integer to get the size (when stored in array of octets)
@return The length of the integer
*/
unsigned long (*unsigned_size)(void *a);
/** store an integer as an array of octets
@param src The integer to store
@param dst The buffer to store the integer in
@return CRYPT_OK on success
*/
int (*unsigned_write)(void *src, unsigned char *dst);
/** read an array of octets and store as integer
@param dst The integer to load
@param src The array of octets
@param len The number of octets
@return CRYPT_OK on success
*/
int (*unsigned_read)(void *dst, unsigned char *src, unsigned long len);
/* ---- basic math ---- */
/** add two integers
@param a The first source integer
@param b The second source integer
@param c The destination of "a + b"
@return CRYPT_OK on success
*/
int (*add)(void *a, void *b, void *c);
/** add two integers
@param a The first source integer
@param b The second source integer (single digit of upto bits_per_digit in length)
@param c The destination of "a + b"
@return CRYPT_OK on success
*/
int (*addi)(void *a, unsigned long b, void *c);
/** subtract two integers
@param a The first source integer
@param b The second source integer
@param c The destination of "a - b"
@return CRYPT_OK on success
*/
int (*sub)(void *a, void *b, void *c);
/** subtract two integers
@param a The first source integer
@param b The second source integer (single digit of upto bits_per_digit in length)
@param c The destination of "a - b"
@return CRYPT_OK on success
*/
int (*subi)(void *a, unsigned long b, void *c);
/** multiply two integers
@param a The first source integer
@param b The second source integer (single digit of upto bits_per_digit in length)
@param c The destination of "a * b"
@return CRYPT_OK on success
*/
int (*mul)(void *a, void *b, void *c);
/** multiply two integers
@param a The first source integer
@param b The second source integer (single digit of upto bits_per_digit in length)
@param c The destination of "a * b"
@return CRYPT_OK on success
*/
int (*muli)(void *a, unsigned long b, void *c);
/** Square an integer
@param a The integer to square
@param b The destination
@return CRYPT_OK on success
*/
int (*sqr)(void *a, void *b);
/** Divide an integer
@param a The dividend
@param b The divisor
@param c The quotient (can be NULL to signify don't care)
@param d The remainder (can be NULL to signify don't care)
@return CRYPT_OK on success
*/
int (*mpdiv)(void *a, void *b, void *c, void *d);
/** divide by two
@param a The integer to divide (shift right)
@param b The destination
@return CRYPT_OK on success
*/
int (*div_2)(void *a, void *b);
/** Get remainder (small value)
@param a The integer to reduce
@param b The modulus (upto bits_per_digit in length)
@param c The destination for the residue
@return CRYPT_OK on success
*/
int (*modi)(void *a, unsigned long b, unsigned long *c);
/** gcd
@param a The first integer
@param b The second integer
@param c The destination for (a, b)
@return CRYPT_OK on success
*/
int (*gcd)(void *a, void *b, void *c);
/** lcm
@param a The first integer
@param b The second integer
@param c The destination for [a, b]
@return CRYPT_OK on success
*/
int (*lcm)(void *a, void *b, void *c);
/** Modular multiplication
@param a The first source
@param b The second source
@param c The modulus
@param d The destination (a*b mod c)
@return CRYPT_OK on success
*/
int (*mulmod)(void *a, void *b, void *c, void *d);
/** Modular squaring
@param a The first source
@param b The modulus
@param c The destination (a*a mod b)
@return CRYPT_OK on success
*/
int (*sqrmod)(void *a, void *b, void *c);
/** Modular inversion
@param a The value to invert
@param b The modulus
@param c The destination (1/a mod b)
@return CRYPT_OK on success
*/
int (*invmod)(void *, void *, void *);
/* ---- reduction ---- */
/** setup montgomery
@param a The modulus
@param b The destination for the reduction digit
@return CRYPT_OK on success
*/
int (*montgomery_setup)(void *a, void **b);
/** get normalization value
@param a The destination for the normalization value
@param b The modulus
@return CRYPT_OK on success
*/
int (*montgomery_normalization)(void *a, void *b);
/** reduce a number
@param a The number [and dest] to reduce
@param b The modulus
@param c The value "b" from montgomery_setup()
@return CRYPT_OK on success
*/
int (*montgomery_reduce)(void *a, void *b, void *c);
/** clean up (frees memory)
@param a The value "b" from montgomery_setup()
@return CRYPT_OK on success
*/
void (*montgomery_deinit)(void *a);
/* ---- exponentiation ---- */
/** Modular exponentiation
@param a The base integer
@param b The power (can be negative) integer
@param c The modulus integer
@param d The destination
@return CRYPT_OK on success
*/
int (*exptmod)(void *a, void *b, void *c, void *d);
/** Primality testing
@param a The integer to test
@param b The destination of the result (FP_YES if prime)
@return CRYPT_OK on success
*/
int (*isprime)(void *a, int *b);
/* ---- (optional) ecc point math ---- */
/** ECC GF(p) point multiplication (from the NIST curves)
@param k The integer to multiply the point by
@param G The point to multiply
@param R The destination for kG
@param modulus The modulus for the field
@param map Boolean indicated whether to map back to affine or not (can be ignored if you work in affine only)
@return CRYPT_OK on success
*/
int (*ecc_ptmul)(void *k, ecc_point *G, ecc_point *R, void *modulus, int map);
/** ECC GF(p) point addition
@param P The first point
@param Q The second point
@param R The destination of P + Q
@param modulus The modulus
@param mp The "b" value from montgomery_setup()
@return CRYPT_OK on success
*/
int (*ecc_ptadd)(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp);
/** ECC GF(p) point double
@param P The first point
@param R The destination of 2P
@param modulus The modulus
@param mp The "b" value from montgomery_setup()
@return CRYPT_OK on success
*/
int (*ecc_ptdbl)(ecc_point *P, ecc_point *R, void *modulus, void *mp);
/** ECC mapping from projective to affine, currently uses (x,y,z) => (x/z^2, y/z^3, 1)
@param P The point to map
@param modulus The modulus
@param mp The "b" value from montgomery_setup()
@return CRYPT_OK on success
@remark The mapping can be different but keep in mind a ecc_point only has three
integers (x,y,z) so if you use a different mapping you have to make it fit.
*/
int (*ecc_map)(ecc_point *P, void *modulus, void *mp);
/** Computes kA*A + kB*B = C using Shamir's Trick
@param A First point to multiply
@param kA What to multiple A by
@param B Second point to multiply
@param kB What to multiple B by
@param C [out] Destination point (can overlap with A or B
@param modulus Modulus for curve
@return CRYPT_OK on success
*/
int (*ecc_mul2add)(ecc_point *A, void *kA,
ecc_point *B, void *kB,
ecc_point *C,
void *modulus);
/* ---- (optional) rsa optimized math (for internal CRT) ---- */
/** RSA Key Generation
@param prng An active PRNG state
@param wprng The index of the PRNG desired
@param size The size of the modulus (key size) desired (octets)
@param e The "e" value (public key). e==65537 is a good choice
@param key [out] Destination of a newly created private key pair
@return CRYPT_OK if successful, upon error all allocated ram is freed
*/
int (*rsa_keygen)(prng_state *prng, int wprng, int size, long e, rsa_key *key);
/** RSA exponentiation
@param in The octet array representing the base
@param inlen The length of the input
@param out The destination (to be stored in an octet array format)
@param outlen The length of the output buffer and the resulting size (zero padded to the size of the modulus)
@param which PK_PUBLIC for public RSA and PK_PRIVATE for private RSA
@param key The RSA key to use
@return CRYPT_OK on success
*/
int (*rsa_me)(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen, int which,
rsa_key *key);
} ltc_math_descriptor;
extern ltc_math_descriptor ltc_mp;
int ltc_init_multi(void **a, ...);
void ltc_deinit_multi(void *a, ...);
#ifdef LTM_DESC
extern const ltc_math_descriptor ltm_desc;
#endif
#ifdef TFM_DESC
extern const ltc_math_descriptor tfm_desc;
#endif
#ifdef GMP_DESC
extern const ltc_math_descriptor gmp_desc;
#endif
#if !defined(DESC_DEF_ONLY) && defined(LTC_SOURCE)
#define MP_DIGIT_BIT ltc_mp.bits_per_digit
/* some handy macros */
#define mp_init(a) ltc_mp.init(a)
#define mp_init_multi ltc_init_multi
#define mp_clear(a) ltc_mp.deinit(a)
#define mp_clear_multi ltc_deinit_multi
#define mp_init_copy(a, b) ltc_mp.init_copy(a, b)
#define mp_neg(a, b) ltc_mp.neg(a, b)
#define mp_copy(a, b) ltc_mp.copy(a, b)
#define mp_set(a, b) ltc_mp.set_int(a, b)
#define mp_set_int(a, b) ltc_mp.set_int(a, b)
#define mp_get_int(a) ltc_mp.get_int(a)
#define mp_get_digit(a, n) ltc_mp.get_digit(a, n)
#define mp_get_digit_count(a) ltc_mp.get_digit_count(a)
#define mp_cmp(a, b) ltc_mp.compare(a, b)
#define mp_cmp_d(a, b) ltc_mp.compare_d(a, b)
#define mp_count_bits(a) ltc_mp.count_bits(a)
#define mp_cnt_lsb(a) ltc_mp.count_lsb_bits(a)
#define mp_2expt(a, b) ltc_mp.twoexpt(a, b)
#define mp_read_radix(a, b, c) ltc_mp.read_radix(a, b, c)
#define mp_toradix(a, b, c) ltc_mp.write_radix(a, b, c)
#define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a)
#define mp_to_unsigned_bin(a, b) ltc_mp.unsigned_write(a, b)
#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
#define mp_add(a, b, c) ltc_mp.add(a, b, c)
#define mp_add_d(a, b, c) ltc_mp.addi(a, b, c)
#define mp_sub(a, b, c) ltc_mp.sub(a, b, c)
#define mp_sub_d(a, b, c) ltc_mp.subi(a, b, c)
#define mp_mul(a, b, c) ltc_mp.mul(a, b, c)
#define mp_mul_d(a, b, c) ltc_mp.muli(a, b, c)
#define mp_sqr(a, b) ltc_mp.sqr(a, b)
#define mp_div(a, b, c, d) ltc_mp.mpdiv(a, b, c, d)
#define mp_div_2(a, b) ltc_mp.div_2(a, b)
#define mp_mod(a, b, c) ltc_mp.mpdiv(a, b, NULL, c)
#define mp_mod_d(a, b, c) ltc_mp.modi(a, b, c)
#define mp_gcd(a, b, c) ltc_mp.gcd(a, b, c)
#define mp_lcm(a, b, c) ltc_mp.lcm(a, b, c)
#define mp_mulmod(a, b, c, d) ltc_mp.mulmod(a, b, c, d)
#define mp_sqrmod(a, b, c) ltc_mp.sqrmod(a, b, c)
#define mp_invmod(a, b, c) ltc_mp.invmod(a, b, c)
#define mp_montgomery_setup(a, b) ltc_mp.montgomery_setup(a, b)
#define mp_montgomery_normalization(a, b) ltc_mp.montgomery_normalization(a, b)
#define mp_montgomery_reduce(a, b, c) ltc_mp.montgomery_reduce(a, b, c)
#define mp_montgomery_free(a) ltc_mp.montgomery_deinit(a)
#define mp_exptmod(a,b,c,d) ltc_mp.exptmod(a,b,c,d)
#define mp_prime_is_prime(a, b, c) ltc_mp.isprime(a, c)
#define mp_iszero(a) (mp_cmp_d(a, 0) == LTC_MP_EQ ? LTC_MP_YES : LTC_MP_NO)
#define mp_isodd(a) (mp_get_digit_count(a) > 0 ? (mp_get_digit(a, 0) & 1 ? LTC_MP_YES : LTC_MP_NO) : LTC_MP_NO)
#define mp_exch(a, b) do { void *ABC__tmp = a; a = b; b = ABC__tmp; } while(0);
#define mp_tohex(a, b) mp_toradix(a, b, 16)
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_math.h,v $ */
/* $Revision: 1.44 $ */
/* $Date: 2007/05/12 14:32:35 $ */

View File

@@ -0,0 +1,23 @@
/* ---- LTC_BASE64 Routines ---- */
#ifdef LTC_BASE64
int base64_encode(const unsigned char *in, unsigned long len,
unsigned char *out, unsigned long *outlen);
int base64_decode(const unsigned char *in, unsigned long len,
unsigned char *out, unsigned long *outlen);
#endif
/* ---- MEM routines ---- */
void zeromem(void *dst, size_t len);
void burn_stack(unsigned long len);
const char *error_to_string(int err);
extern const char *crypt_build_settings;
/* ---- HMM ---- */
int crypt_fsa(void *mp, ...);
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_misc.h,v $ */
/* $Revision: 1.5 $ */
/* $Date: 2007/05/12 14:32:35 $ */

View File

@@ -0,0 +1,558 @@
/* ---- NUMBER THEORY ---- */
enum {
PK_PUBLIC=0,
PK_PRIVATE=1
};
int rand_prime(void *N, long len, prng_state *prng, int wprng);
/* ---- RSA ---- */
#ifdef LTC_MRSA
/* Min and Max RSA key sizes (in bits) */
#define MIN_RSA_SIZE 1024
#define MAX_RSA_SIZE 4096
/** RSA LTC_PKCS style key */
typedef struct Rsa_key {
/** Type of key, PK_PRIVATE or PK_PUBLIC */
int type;
/** The public exponent */
void *e;
/** The private exponent */
void *d;
/** The modulus */
void *N;
/** The p factor of N */
void *p;
/** The q factor of N */
void *q;
/** The 1/q mod p CRT param */
void *qP;
/** The d mod (p - 1) CRT param */
void *dP;
/** The d mod (q - 1) CRT param */
void *dQ;
} rsa_key;
int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key);
int rsa_exptmod(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen, int which,
rsa_key *key);
void rsa_free(rsa_key *key);
/* These use LTC_PKCS #1 v2.0 padding */
#define rsa_encrypt_key(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _prng, _prng_idx, _hash_idx, _key) \
rsa_encrypt_key_ex(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _prng, _prng_idx, _hash_idx, LTC_LTC_PKCS_1_OAEP, _key)
#define rsa_decrypt_key(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash_idx, _stat, _key) \
rsa_decrypt_key_ex(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash_idx, LTC_LTC_PKCS_1_OAEP, _stat, _key)
#define rsa_sign_hash(_in, _inlen, _out, _outlen, _prng, _prng_idx, _hash_idx, _saltlen, _key) \
rsa_sign_hash_ex(_in, _inlen, _out, _outlen, LTC_LTC_PKCS_1_PSS, _prng, _prng_idx, _hash_idx, _saltlen, _key)
#define rsa_verify_hash(_sig, _siglen, _hash, _hashlen, _hash_idx, _saltlen, _stat, _key) \
rsa_verify_hash_ex(_sig, _siglen, _hash, _hashlen, LTC_LTC_PKCS_1_PSS, _hash_idx, _saltlen, _stat, _key)
/* These can be switched between LTC_PKCS #1 v2.x and LTC_PKCS #1 v1.5 paddings */
int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
const unsigned char *lparam, unsigned long lparamlen,
prng_state *prng, int prng_idx, int hash_idx, int padding, rsa_key *key);
int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
const unsigned char *lparam, unsigned long lparamlen,
int hash_idx, int padding,
int *stat, rsa_key *key);
int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
int padding,
prng_state *prng, int prng_idx,
int hash_idx, unsigned long saltlen,
rsa_key *key);
int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int padding,
int hash_idx, unsigned long saltlen,
int *stat, rsa_key *key);
/* LTC_PKCS #1 import/export */
int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key);
int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key);
/* Ladik: Added for verifying Blizzard strong signature verification */
int rsa_verify_simple(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int *stat,
rsa_key *key);
#endif
/* ---- Katja ---- */
#ifdef MKAT
/* Min and Max KAT key sizes (in bits) */
#define MIN_KAT_SIZE 1024
#define MAX_KAT_SIZE 4096
/** Katja LTC_PKCS style key */
typedef struct KAT_key {
/** Type of key, PK_PRIVATE or PK_PUBLIC */
int type;
/** The private exponent */
void *d;
/** The modulus */
void *N;
/** The p factor of N */
void *p;
/** The q factor of N */
void *q;
/** The 1/q mod p CRT param */
void *qP;
/** The d mod (p - 1) CRT param */
void *dP;
/** The d mod (q - 1) CRT param */
void *dQ;
/** The pq param */
void *pq;
} katja_key;
int katja_make_key(prng_state *prng, int wprng, int size, katja_key *key);
int katja_exptmod(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen, int which,
katja_key *key);
void katja_free(katja_key *key);
/* These use LTC_PKCS #1 v2.0 padding */
int katja_encrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
const unsigned char *lparam, unsigned long lparamlen,
prng_state *prng, int prng_idx, int hash_idx, katja_key *key);
int katja_decrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
const unsigned char *lparam, unsigned long lparamlen,
int hash_idx, int *stat,
katja_key *key);
/* LTC_PKCS #1 import/export */
int katja_export(unsigned char *out, unsigned long *outlen, int type, katja_key *key);
int katja_import(const unsigned char *in, unsigned long inlen, katja_key *key);
#endif
/* ---- ECC Routines ---- */
#ifdef LTC_MECC
/* size of our temp buffers for exported keys */
#define ECC_BUF_SIZE 256
/* max private key size */
#define ECC_MAXSIZE 66
/** Structure defines a NIST GF(p) curve */
typedef struct {
/** The size of the curve in octets */
int size;
/** name of curve */
char *name;
/** The prime that defines the field the curve is in (encoded in hex) */
char *prime;
/** The fields B param (hex) */
char *B;
/** The order of the curve (hex) */
char *order;
/** The x co-ordinate of the base point on the curve (hex) */
char *Gx;
/** The y co-ordinate of the base point on the curve (hex) */
char *Gy;
} ltc_ecc_set_type;
/** A point on a ECC curve, stored in Jacbobian format such that (x,y,z) => (x/z^2, y/z^3, 1) when interpretted as affine */
typedef struct {
/** The x co-ordinate */
void *x;
/** The y co-ordinate */
void *y;
/** The z co-ordinate */
void *z;
} ecc_point;
/** An ECC key */
typedef struct {
/** Type of key, PK_PRIVATE or PK_PUBLIC */
int type;
/** Index into the ltc_ecc_sets[] for the parameters of this curve; if -1, then this key is using user supplied curve in dp */
int idx;
/** pointer to domain parameters; either points to NIST curves (identified by idx >= 0) or user supplied curve */
const ltc_ecc_set_type *dp;
/** The public key */
ecc_point pubkey;
/** The private key */
void *k;
} ecc_key;
/** the ECC params provided */
extern const ltc_ecc_set_type ltc_ecc_sets[];
int ecc_test(void);
void ecc_sizes(int *low, int *high);
int ecc_get_size(ecc_key *key);
int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key);
int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp);
void ecc_free(ecc_key *key);
int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key);
int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
int ecc_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_set_type *dp);
int ecc_ansi_x963_export(ecc_key *key, unsigned char *out, unsigned long *outlen);
int ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
int ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, ltc_ecc_set_type *dp);
int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key,
unsigned char *out, unsigned long *outlen);
int ecc_encrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, int hash,
ecc_key *key);
int ecc_decrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
ecc_key *key);
int ecc_sign_hash(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, ecc_key *key);
int ecc_verify_hash(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int *stat, ecc_key *key);
/* low level functions */
ecc_point *ltc_ecc_new_point(void);
void ltc_ecc_del_point(ecc_point *p);
int ltc_ecc_is_valid_idx(int n);
/* point ops (mp == montgomery digit) */
#if !defined(LTC_MECC_ACCEL) || defined(LTM_LTC_DESC) || defined(GMP_LTC_DESC)
/* R = 2P */
int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *mp);
/* R = P + Q */
int ltc_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp);
#endif
#if defined(LTC_MECC_FP)
/* optimized point multiplication using fixed point cache (HAC algorithm 14.117) */
int ltc_ecc_fp_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map);
/* functions for saving/loading/freeing/adding to fixed point cache */
int ltc_ecc_fp_save_state(unsigned char **out, unsigned long *outlen);
int ltc_ecc_fp_restore_state(unsigned char *in, unsigned long inlen);
void ltc_ecc_fp_free(void);
int ltc_ecc_fp_add_point(ecc_point *g, void *modulus, int lock);
/* lock/unlock all points currently in fixed point cache */
void ltc_ecc_fp_tablelock(int lock);
#endif
/* R = kG */
int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map);
#ifdef LTC_ECC_SHAMIR
/* kA*A + kB*B = C */
int ltc_ecc_mul2add(ecc_point *A, void *kA,
ecc_point *B, void *kB,
ecc_point *C,
void *modulus);
#ifdef LTC_MECC_FP
/* Shamir's trick with optimized point multiplication using fixed point cache */
int ltc_ecc_fp_mul2add(ecc_point *A, void *kA,
ecc_point *B, void *kB,
ecc_point *C, void *modulus);
#endif
#endif
/* map P to affine from projective */
int ltc_ecc_map(ecc_point *P, void *modulus, void *mp);
#endif
#ifdef LTC_MDSA
/* Max diff between group and modulus size in bytes */
#define LTC_MDSA_DELTA 512
/* Max DSA group size in bytes (default allows 4k-bit groups) */
#define LTC_MDSA_MAX_GROUP 512
/** DSA key structure */
typedef struct {
/** The key type, PK_PRIVATE or PK_PUBLIC */
int type;
/** The order of the sub-group used in octets */
int qord;
/** The generator */
void *g;
/** The prime used to generate the sub-group */
void *q;
/** The large prime that generats the field the contains the sub-group */
void *p;
/** The private key */
void *x;
/** The public key */
void *y;
} dsa_key;
int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key);
void dsa_free(dsa_key *key);
int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen,
void *r, void *s,
prng_state *prng, int wprng, dsa_key *key);
int dsa_sign_hash(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, dsa_key *key);
int dsa_verify_hash_raw( void *r, void *s,
const unsigned char *hash, unsigned long hashlen,
int *stat, dsa_key *key);
int dsa_verify_hash(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int *stat, dsa_key *key);
int dsa_encrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, int hash,
dsa_key *key);
int dsa_decrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
dsa_key *key);
int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key);
int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key);
int dsa_verify_key(dsa_key *key, int *stat);
int dsa_shared_secret(void *private_key, void *base,
dsa_key *public_key,
unsigned char *out, unsigned long *outlen);
#endif
#ifdef LTC_DER
/* DER handling */
enum {
LTC_ASN1_EOL,
LTC_ASN1_BOOLEAN,
LTC_ASN1_INTEGER,
LTC_ASN1_SHORT_INTEGER,
LTC_ASN1_BIT_STRING,
LTC_ASN1_OCTET_STRING,
LTC_ASN1_NULL,
LTC_ASN1_OBJECT_IDENTIFIER,
LTC_ASN1_IA5_STRING,
LTC_ASN1_PRINTABLE_STRING,
LTC_ASN1_UTF8_STRING,
LTC_ASN1_UTCTIME,
LTC_ASN1_CHOICE,
LTC_ASN1_SEQUENCE,
LTC_ASN1_SET,
LTC_ASN1_SETOF
};
/** A LTC ASN.1 list type */
typedef struct ltc_asn1_list_ {
/** The LTC ASN.1 enumerated type identifier */
int type;
/** The data to encode or place for decoding */
void *data;
/** The size of the input or resulting output */
unsigned long size;
/** The used flag, this is used by the CHOICE ASN.1 type to indicate which choice was made */
int used;
/** prev/next entry in the list */
struct ltc_asn1_list_ *prev, *next, *child, *parent;
} ltc_asn1_list;
#define LTC_SET_ASN1(list, index, Type, Data, Size) \
do { \
int LTC_MACRO_temp = (index); \
ltc_asn1_list *LTC_MACRO_list = (list); \
LTC_MACRO_list[LTC_MACRO_temp].type = (Type); \
LTC_MACRO_list[LTC_MACRO_temp].data = (void*)(Data); \
LTC_MACRO_list[LTC_MACRO_temp].size = (Size); \
LTC_MACRO_list[LTC_MACRO_temp].used = 0; \
} while (0);
/* SEQUENCE */
int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
unsigned char *out, unsigned long *outlen, int type_of);
#define der_encode_sequence(list, inlen, out, outlen) der_encode_sequence_ex(list, inlen, out, outlen, LTC_ASN1_SEQUENCE)
int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen,
ltc_asn1_list *list, unsigned long outlen, int ordered);
#define der_decode_sequence(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 1)
int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
unsigned long *outlen);
/* SET */
#define der_decode_set(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 0)
#define der_length_set der_length_sequence
int der_encode_set(ltc_asn1_list *list, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int der_encode_setof(ltc_asn1_list *list, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
/* VA list handy helpers with triplets of <type, size, data> */
int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...);
/* FLEXI DECODER handle unknown list decoder */
int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out);
void der_free_sequence_flexi(ltc_asn1_list *list);
void der_sequence_free(ltc_asn1_list *in);
/* BOOLEAN */
int der_length_boolean(unsigned long *outlen);
int der_encode_boolean(int in,
unsigned char *out, unsigned long *outlen);
int der_decode_boolean(const unsigned char *in, unsigned long inlen,
int *out);
/* INTEGER */
int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen);
int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num);
int der_length_integer(void *num, unsigned long *len);
/* INTEGER -- handy for 0..2^32-1 values */
int der_decode_short_integer(const unsigned char *in, unsigned long inlen, unsigned long *num);
int der_encode_short_integer(unsigned long num, unsigned char *out, unsigned long *outlen);
int der_length_short_integer(unsigned long num, unsigned long *outlen);
/* BIT STRING */
int der_encode_bit_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int der_decode_bit_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int der_length_bit_string(unsigned long nbits, unsigned long *outlen);
/* OCTET STRING */
int der_encode_octet_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int der_length_octet_string(unsigned long noctets, unsigned long *outlen);
/* OBJECT IDENTIFIER */
int der_encode_object_identifier(unsigned long *words, unsigned long nwords,
unsigned char *out, unsigned long *outlen);
int der_decode_object_identifier(const unsigned char *in, unsigned long inlen,
unsigned long *words, unsigned long *outlen);
int der_length_object_identifier(unsigned long *words, unsigned long nwords, unsigned long *outlen);
unsigned long der_object_identifier_bits(unsigned long x);
/* IA5 STRING */
int der_encode_ia5_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen);
int der_ia5_char_encode(int c);
int der_ia5_value_decode(int v);
/* Printable STRING */
int der_encode_printable_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int der_length_printable_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen);
int der_printable_char_encode(int c);
int der_printable_value_decode(int v);
/* UTF-8 */
#if (defined(SIZE_MAX) || __STDC_VERSION__ >= 199901L || defined(WCHAR_MAX) || defined(_WCHAR_T) || defined(_WCHAR_T_DEFINED) || defined (__WCHAR_TYPE__)) && !defined(LTC_NO_WCHAR)
#include <wchar.h>
#else
typedef ulong32 wchar_t;
#endif
int der_encode_utf8_string(const wchar_t *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen);
int der_decode_utf8_string(const unsigned char *in, unsigned long inlen,
wchar_t *out, unsigned long *outlen);
unsigned long der_utf8_charsize(const wchar_t c);
int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen);
/* CHOICE */
int der_decode_choice(const unsigned char *in, unsigned long *inlen,
ltc_asn1_list *list, unsigned long outlen);
/* UTCTime */
typedef struct {
unsigned YY, /* year */
MM, /* month */
DD, /* day */
hh, /* hour */
mm, /* minute */
ss, /* second */
off_dir, /* timezone offset direction 0 == +, 1 == - */
off_hh, /* timezone offset hours */
off_mm; /* timezone offset minutes */
} ltc_utctime;
int der_encode_utctime(ltc_utctime *utctime,
unsigned char *out, unsigned long *outlen);
int der_decode_utctime(const unsigned char *in, unsigned long *inlen,
ltc_utctime *out);
int der_length_utctime(ltc_utctime *utctime, unsigned long *outlen);
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_pk.h,v $ */
/* $Revision: 1.81 $ */
/* $Date: 2007/05/12 14:32:35 $ */

View File

@@ -0,0 +1,89 @@
/* LTC_PKCS Header Info */
/* ===> LTC_PKCS #1 -- RSA Cryptography <=== */
#ifdef LTC_PKCS_1
enum ltc_pkcs_1_v1_5_blocks
{
LTC_LTC_PKCS_1_EMSA = 1, /* Block type 1 (LTC_PKCS #1 v1.5 signature padding) */
LTC_LTC_PKCS_1_EME = 2 /* Block type 2 (LTC_PKCS #1 v1.5 encryption padding) */
};
enum ltc_pkcs_1_paddings
{
LTC_LTC_PKCS_1_V1_5 = 1, /* LTC_PKCS #1 v1.5 padding (\sa ltc_pkcs_1_v1_5_blocks) */
LTC_LTC_PKCS_1_OAEP = 2, /* LTC_PKCS #1 v2.0 encryption padding */
LTC_LTC_PKCS_1_PSS = 3 /* LTC_PKCS #1 v2.1 signature padding */
};
int pkcs_1_mgf1( int hash_idx,
const unsigned char *seed, unsigned long seedlen,
unsigned char *mask, unsigned long masklen);
int pkcs_1_i2osp(void *n, unsigned long modulus_len, unsigned char *out);
int pkcs_1_os2ip(void *n, unsigned char *in, unsigned long inlen);
/* *** v1.5 padding */
int pkcs_1_v1_5_encode(const unsigned char *msg,
unsigned long msglen,
int block_type,
unsigned long modulus_bitlen,
prng_state *prng,
int prng_idx,
unsigned char *out,
unsigned long *outlen);
int pkcs_1_v1_5_decode(const unsigned char *msg,
unsigned long msglen,
int block_type,
unsigned long modulus_bitlen,
unsigned char *out,
unsigned long *outlen,
int *is_valid);
/* *** v2.1 padding */
int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen,
const unsigned char *lparam, unsigned long lparamlen,
unsigned long modulus_bitlen, prng_state *prng,
int prng_idx, int hash_idx,
unsigned char *out, unsigned long *outlen);
int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
const unsigned char *lparam, unsigned long lparamlen,
unsigned long modulus_bitlen, int hash_idx,
unsigned char *out, unsigned long *outlen,
int *res);
int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
unsigned long saltlen, prng_state *prng,
int prng_idx, int hash_idx,
unsigned long modulus_bitlen,
unsigned char *out, unsigned long *outlen);
int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
const unsigned char *sig, unsigned long siglen,
unsigned long saltlen, int hash_idx,
unsigned long modulus_bitlen, int *res);
#endif /* LTC_PKCS_1 */
/* ===> LTC_PKCS #5 -- Password Based Cryptography <=== */
#ifdef LTC_PKCS_5
/* Algorithm #1 (old) */
int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
const unsigned char *salt,
int iteration_count, int hash_idx,
unsigned char *out, unsigned long *outlen);
/* Algorithm #2 (new) */
int pkcs_5_alg2(const unsigned char *password, unsigned long password_len,
const unsigned char *salt, unsigned long salt_len,
int iteration_count, int hash_idx,
unsigned char *out, unsigned long *outlen);
#endif /* LTC_PKCS_5 */
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_pkcs.h,v $ */
/* $Revision: 1.8 $ */
/* $Date: 2007/05/12 14:32:35 $ */

View File

@@ -0,0 +1,199 @@
/* ---- PRNG Stuff ---- */
#ifdef LTC_YARROW
struct yarrow_prng {
int cipher, hash;
unsigned char pool[MAXBLOCKSIZE];
symmetric_CTR ctr;
LTC_MUTEX_TYPE(prng_lock)
};
#endif
#ifdef LTC_RC4
struct rc4_prng {
int x, y;
unsigned char buf[256];
};
#endif
#ifdef LTC_FORTUNA
struct fortuna_prng {
hash_state pool[LTC_FORTUNA_POOLS]; /* the pools */
symmetric_key skey;
unsigned char K[32], /* the current key */
IV[16]; /* IV for CTR mode */
unsigned long pool_idx, /* current pool we will add to */
pool0_len, /* length of 0'th pool */
wd;
ulong64 reset_cnt; /* number of times we have reset */
LTC_MUTEX_TYPE(prng_lock)
};
#endif
#ifdef LTC_SOBER128
struct sober128_prng {
ulong32 R[17], /* Working storage for the shift register */
initR[17], /* saved register contents */
konst, /* key dependent constant */
sbuf; /* partial word encryption buffer */
int nbuf, /* number of part-word stream bits buffered */
flag, /* first add_entropy call or not? */
set; /* did we call add_entropy to set key? */
};
#endif
typedef union Prng_state {
char dummy[1];
#ifdef LTC_YARROW
struct yarrow_prng yarrow;
#endif
#ifdef LTC_RC4
struct rc4_prng rc4;
#endif
#ifdef LTC_FORTUNA
struct fortuna_prng fortuna;
#endif
#ifdef LTC_SOBER128
struct sober128_prng sober128;
#endif
} prng_state;
/** PRNG descriptor */
extern struct ltc_prng_descriptor {
/** Name of the PRNG */
char *name;
/** size in bytes of exported state */
int export_size;
/** Start a PRNG state
@param prng [out] The state to initialize
@return CRYPT_OK if successful
*/
int (*start)(prng_state *prng);
/** Add entropy to the PRNG
@param in The entropy
@param inlen Length of the entropy (octets)\
@param prng The PRNG state
@return CRYPT_OK if successful
*/
int (*add_entropy)(const unsigned char *in, unsigned long inlen, prng_state *prng);
/** Ready a PRNG state to read from
@param prng The PRNG state to ready
@return CRYPT_OK if successful
*/
int (*ready)(prng_state *prng);
/** Read from the PRNG
@param out [out] Where to store the data
@param outlen Length of data desired (octets)
@param prng The PRNG state to read from
@return Number of octets read
*/
unsigned long (*read)(unsigned char *out, unsigned long outlen, prng_state *prng);
/** Terminate a PRNG state
@param prng The PRNG state to terminate
@return CRYPT_OK if successful
*/
int (*done)(prng_state *prng);
/** Export a PRNG state
@param out [out] The destination for the state
@param outlen [in/out] The max size and resulting size of the PRNG state
@param prng The PRNG to export
@return CRYPT_OK if successful
*/
int (*pexport)(unsigned char *out, unsigned long *outlen, prng_state *prng);
/** Import a PRNG state
@param in The data to import
@param inlen The length of the data to import (octets)
@param prng The PRNG to initialize/import
@return CRYPT_OK if successful
*/
int (*pimport)(const unsigned char *in, unsigned long inlen, prng_state *prng);
/** Self-test the PRNG
@return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
*/
int (*test)(void);
} prng_descriptor[];
#ifdef LTC_YARROW
int yarrow_start(prng_state *prng);
int yarrow_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
int yarrow_ready(prng_state *prng);
unsigned long yarrow_read(unsigned char *out, unsigned long outlen, prng_state *prng);
int yarrow_done(prng_state *prng);
int yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
int yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
int yarrow_test(void);
extern const struct ltc_prng_descriptor yarrow_desc;
#endif
#ifdef LTC_FORTUNA
int fortuna_start(prng_state *prng);
int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
int fortuna_ready(prng_state *prng);
unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state *prng);
int fortuna_done(prng_state *prng);
int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
int fortuna_test(void);
extern const struct ltc_prng_descriptor fortuna_desc;
#endif
#ifdef LTC_RC4
int rc4_start(prng_state *prng);
int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
int rc4_ready(prng_state *prng);
unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng);
int rc4_done(prng_state *prng);
int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
int rc4_test(void);
extern const struct ltc_prng_descriptor rc4_desc;
#endif
#ifdef LTC_SPRNG
int sprng_start(prng_state *prng);
int sprng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
int sprng_ready(prng_state *prng);
unsigned long sprng_read(unsigned char *out, unsigned long outlen, prng_state *prng);
int sprng_done(prng_state *prng);
int sprng_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
int sprng_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
int sprng_test(void);
extern const struct ltc_prng_descriptor sprng_desc;
#endif
#ifdef LTC_SOBER128
int sober128_start(prng_state *prng);
int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
int sober128_ready(prng_state *prng);
unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng);
int sober128_done(prng_state *prng);
int sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
int sober128_test(void);
extern const struct ltc_prng_descriptor sober128_desc;
#endif
int find_prng(const char *name);
int register_prng(const struct ltc_prng_descriptor *prng);
int unregister_prng(const struct ltc_prng_descriptor *prng);
int prng_is_valid(int idx);
LTC_MUTEX_PROTO(ltc_prng_mutex)
/* Slow RNG you **might** be able to use to seed a PRNG with. Be careful as this
* might not work on all platforms as planned
*/
unsigned long rng_get_bytes(unsigned char *out,
unsigned long outlen,
void (*callback)(void));
int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void));
/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_prng.h,v $ */
/* $Revision: 1.9 $ */
/* $Date: 2007/05/12 14:32:35 $ */

View File

@@ -0,0 +1,30 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
*/
#include "../headers/tomcrypt.h"
#include <signal.h>
/**
@file crypt_argchk.c
Perform argument checking, Tom St Denis
*/
#if (ARGTYPE == 0)
void crypt_argchk(char *v, char *s, int d)
{
fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n",
v, d, s);
(void)raise(SIGABRT);
}
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_argchk.c,v $ */
/* $Revision: 1.5 $ */
/* $Date: 2006/12/28 01:27:24 $ */

View File

@@ -0,0 +1,27 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
*/
#include "../headers/tomcrypt.h"
/**
@file crypt_hash_descriptor.c
Stores the hash descriptor table, Tom St Denis
*/
struct ltc_hash_descriptor hash_descriptor[TAB_SIZE] = {
{ NULL, 0, 0, 0, { 0 }, 0, NULL, NULL, NULL, NULL, NULL }
};
LTC_MUTEX_GLOBAL(ltc_hash_mutex)
/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_hash_descriptor.c,v $ */
/* $Revision: 1.10 $ */
/* $Date: 2006/12/28 01:27:24 $ */

View File

@@ -0,0 +1,36 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
*/
#include "../headers/tomcrypt.h"
/**
@file crypt_hash_is_valid.c
Determine if hash is valid, Tom St Denis
*/
/*
Test if a hash index is valid
@param idx The index of the hash to search for
@return CRYPT_OK if valid
*/
int hash_is_valid(int idx)
{
LTC_MUTEX_LOCK(&ltc_hash_mutex);
if (idx < 0 || idx >= TAB_SIZE || hash_descriptor[idx].name == NULL) {
LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
return CRYPT_INVALID_HASH;
}
LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
return CRYPT_OK;
}
/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_hash_is_valid.c,v $ */
/* $Revision: 1.6 $ */
/* $Date: 2006/12/28 01:27:24 $ */

View File

@@ -0,0 +1,43 @@
/*****************************************************************************/
/* crypt_libc.c Copyright (c) Ladislav Zezula 2010 */
/*---------------------------------------------------------------------------*/
/* Description: */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 05.05.10 1.00 Lad The first version of crypt_libc.c */
/*****************************************************************************/
// LibTomCrypt header
#include <stdlib.h>
#include "../headers/tomcrypt.h"
void * LibTomMalloc(size_t n)
{
return malloc(n);
}
void * LibTomCalloc(size_t n, size_t s)
{
return calloc(n, s);
}
void * LibTomRealloc(void *p, size_t n)
{
return realloc(p, n);
}
void LibTomFree(void * p)
{
free(p);
}
clock_t LibTomClock(void)
{
return clock();
}
void LibTomQsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *))
{
qsort(base, nmemb, size, compar);
}

15
dep/SFMT/CMakeLists.txt Normal file
View File

@@ -0,0 +1,15 @@
# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
add_library(sfmt INTERFACE)
target_include_directories(sfmt
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})

363
dep/SFMT/SFMT.h Normal file
View File

@@ -0,0 +1,363 @@
/*
* Copyright notice
* ================
* GNU General Public License http://www.gnu.org/licenses/gpl.html
* This C++ implementation of SFMT contains parts of the original C code
* which was published under the following BSD license, which is therefore
* in effect in addition to the GNU General Public License.
* Copyright (c) 2006, 2007 by Mutsuo Saito, Makoto Matsumoto and Hiroshima University.
* Copyright (c) 2008 by Agner Fog.
* Copyright (c) 2008-2013 Trinity Core
*
* BSD License:
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* > Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* > Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* > Neither the name of the Hiroshima University nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SFMT_H
#define SFMT_H
#include <emmintrin.h> // Define SSE2 intrinsics
#include "randomc.h" // Define integer types etc
#include <time.h>
#include <new>
// Choose one of the possible Mersenne exponents.
// Higher values give longer cycle length and use more memory:
//#define MEXP 607
//#define MEXP 1279
//#define MEXP 2281
//#define MEXP 4253
#define MEXP 11213
//#define MEXP 19937
//#define MEXP 44497
// Define constants for the selected Mersenne exponent:
#if MEXP == 44497
#define SFMT_N 348 // Size of state vector
#define SFMT_M 330 // Position of intermediate feedback
#define SFMT_SL1 5 // Left shift of W[N-1], 32-bit words
#define SFMT_SL2 3 // Left shift of W[0], *8, 128-bit words
#define SFMT_SR1 9 // Right shift of W[M], 32-bit words
#define SFMT_SR2 3 // Right shift of W[N-2], *8, 128-bit words
#define SFMT_MASK 0xeffffffb,0xdfbebfff,0xbfbf7bef,0x9ffd7bff // AND mask
#define SFMT_PARITY 1,0,0xa3ac4000,0xecc1327a // Period certification vector
#elif MEXP == 19937
#define SFMT_N 156 // Size of state vector
#define SFMT_M 122 // Position of intermediate feedback
#define SFMT_SL1 18 // Left shift of W[N-1], 32-bit words
#define SFMT_SL2 1 // Left shift of W[0], *8, 128-bit words
#define SFMT_SR1 11 // Right shift of W[M], 32-bit words
#define SFMT_SR2 1 // Right shift of W[N-2], *8, 128-bit words
#define SFMT_MASK 0xdfffffef,0xddfecb7f,0xbffaffff,0xbffffff6 // AND mask
#define SFMT_PARITY 1,0,0,0x13c9e684 // Period certification vector
#elif MEXP == 11213
#define SFMT_N 88 // Size of state vector
#define SFMT_M 68 // Position of intermediate feedback
#define SFMT_SL1 14 // Left shift of W[N-1], 32-bit words
#define SFMT_SL2 3 // Left shift of W[0], *8, 128-bit words
#define SFMT_SR1 7 // Right shift of W[M], 32-bit words
#define SFMT_SR2 3 // Right shift of W[N-2], *8, 128-bit words
#define SFMT_MASK 0xeffff7fb,0xffffffef,0xdfdfbfff,0x7fffdbfd // AND mask
#define SFMT_PARITY 1,0,0xe8148000,0xd0c7afa3 // Period certification vector
#elif MEXP == 4253
#define SFMT_N 34 // Size of state vector
#define SFMT_M 17 // Position of intermediate feedback
#define SFMT_SL1 20 // Left shift of W[N-1], 32-bit words
#define SFMT_SL2 1 // Left shift of W[0], *8, 128-bit words
#define SFMT_SR1 7 // Right shift of W[M], 32-bit words
#define SFMT_SR2 1 // Right shift of W[N-2], *8, 128-bit words
#define SFMT_MASK 0x9f7bffff, 0x9fffff5f, 0x3efffffb, 0xfffff7bb // AND mask
#define SFMT_PARITY 0xa8000001, 0xaf5390a3, 0xb740b3f8, 0x6c11486d // Period certification vector
#elif MEXP == 2281
#define SFMT_N 18 // Size of state vector
#define SFMT_M 12 // Position of intermediate feedback
#define SFMT_SL1 19 // Left shift of W[N-1], 32-bit words
#define SFMT_SL2 1 // Left shift of W[0], *8, 128-bit words
#define SFMT_SR1 5 // Right shift of W[M], 32-bit words
#define SFMT_SR2 1 // Right shift of W[N-2], *8, 128-bit words
#define SFMT_MASK 0xbff7ffbf, 0xfdfffffe, 0xf7ffef7f, 0xf2f7cbbf // AND mask
#define SFMT_PARITY 0x00000001, 0x00000000, 0x00000000, 0x41dfa600 // Period certification vector
#elif MEXP == 1279
#define SFMT_N 10 // Size of state vector
#define SFMT_M 7 // Position of intermediate feedback
#define SFMT_SL1 14 // Left shift of W[N-1], 32-bit words
#define SFMT_SL2 3 // Left shift of W[0], *8, 128-bit words
#define SFMT_SR1 5 // Right shift of W[M], 32-bit words
#define SFMT_SR2 1 // Right shift of W[N-2], *8, 128-bit words
#define SFMT_MASK 0xf7fefffd, 0x7fefcfff, 0xaff3ef3f, 0xb5ffff7f // AND mask
#define SFMT_PARITY 0x00000001, 0x00000000, 0x00000000, 0x20000000 // Period certification vector
#elif MEXP == 607
#define SFMT_N 5 // Size of state vector
#define SFMT_M 2 // Position of intermediate feedback
#define SFMT_SL1 15 // Left shift of W[N-1], 32-bit words
#define SFMT_SL2 3 // Left shift of W[0], *8, 128-bit words
#define SFMT_SR1 13 // Right shift of W[M], 32-bit words
#define SFMT_SR2 3 // Right shift of W[N-2], *8, 128-bit words
#define SFMT_MASK 0xfdff37ff, 0xef7f3f7d, 0xff777b7d, 0x7ff7fb2f // AND mask
#define SFMT_PARITY 0x00000001, 0x00000000, 0x00000000, 0x5986f054 // Period certification vector
#endif
// Functions used by SFMTRand::RandomInitByArray (UNUSED AND COMMENTED OUT)
/*
static uint32_t func1(uint32_t x) {
return (x ^ (x >> 27)) * 1664525U;
}
static uint32_t func2(uint32_t x) {
return (x ^ (x >> 27)) * 1566083941U;
}
*/
// Subfunction for the sfmt algorithm
static inline __m128i sfmt_recursion(__m128i const &a, __m128i const &b,
__m128i const &c, __m128i const &d, __m128i const &mask) {
__m128i a1, b1, c1, d1, z1, z2;
b1 = _mm_srli_epi32(b, SFMT_SR1);
a1 = _mm_slli_si128(a, SFMT_SL2);
c1 = _mm_srli_si128(c, SFMT_SR2);
d1 = _mm_slli_epi32(d, SFMT_SL1);
b1 = _mm_and_si128(b1, mask);
z1 = _mm_xor_si128(a, a1);
z2 = _mm_xor_si128(b1, d1);
z1 = _mm_xor_si128(z1, c1);
z2 = _mm_xor_si128(z1, z2);
return z2;
}
namespace boost {
template <typename T> class thread_specific_ptr;
}
// Class for SFMT generator
class SFMTRand { // Encapsulate random number generator
friend class boost::thread_specific_ptr<SFMTRand>;
public:
SFMTRand()
{
LastInterval = 0;
RandomInit((int)(time(0)));
}
void RandomInit(int seed) // Re-seed
{
// Re-seed
uint32_t i; // Loop counter
uint32_t y = seed; // Temporary
uint32_t statesize = SFMT_N*4; // Size of state vector
// Fill state vector with random numbers from seed
uint32_t* s = (uint32_t*)&state;
s[0] = y;
const uint32_t factor = 1812433253U;// Multiplication factor
for (i = 1; i < statesize; i++) {
y = factor * (y ^ (y >> 30)) + i;
((uint32_t*)state)[i] = y;
}
// Further initialization and period certification
Init2();
}
int32_t IRandom(int32_t min, int32_t max) // Output random integer
{
// Output random integer in the interval min <= x <= max
// Slightly inaccurate if (max-min+1) is not a power of 2
if (max <= min) {
if (max == min) return min; else return 0x80000000;
}
// Assume 64 bit integers supported. Use multiply and shift method
uint32_t interval; // Length of interval
uint64_t longran; // Random bits * interval
uint32_t iran; // Longran / 2^32
interval = (uint32_t)(max - min + 1);
longran = (uint64_t)BRandom() * interval;
iran = (uint32_t)(longran >> 32);
// Convert back to signed and return result
return (int32_t)iran + min;
}
uint32_t URandom(uint32_t min, uint32_t max)
{
// Output random integer in the interval min <= x <= max
// Slightly inaccurate if (max-min+1) is not a power of 2
if (max <= min) {
if (max == min) return min; else return 0;
}
// Assume 64 bit integers supported. Use multiply and shift method
uint32_t interval; // Length of interval
uint64_t longran; // Random bits * interval
uint32_t iran; // Longran / 2^32
interval = (uint32_t)(max - min + 1);
longran = (uint64_t)BRandom() * interval;
iran = (uint32_t)(longran >> 32);
// Convert back to signed and return result
return iran + min;
}
double Random() // Output random floating point number
{
// Output random floating point number
if (ix >= SFMT_N*4-1) {
// Make sure we have at least two 32-bit numbers
Generate();
}
uint64_t r = *(uint64_t*)((uint32_t*)state+ix);
ix += 2;
// 52 bits resolution for compatibility with assembly version:
return (int64_t)(r >> 12) * (1./(67108864.0*67108864.0));
}
uint32_t BRandom() // Output random bits
{
// Output 32 random bits
uint32_t y;
if (ix >= SFMT_N*4) {
Generate();
}
y = ((uint32_t*)state)[ix++];
return y;
}
void* operator new(size_t size, std::nothrow_t const&)
{
return _mm_malloc(size, 16);
}
void operator delete(void* ptr, std::nothrow_t const&)
{
_mm_free(ptr);
}
void* operator new(size_t size)
{
return _mm_malloc(size, 16);
}
void operator delete(void* ptr)
{
_mm_free(ptr);
}
void* operator new[](size_t size, std::nothrow_t const&)
{
return _mm_malloc(size, 16);
}
void operator delete[](void* ptr, std::nothrow_t const&)
{
_mm_free(ptr);
}
void* operator new[](size_t size)
{
return _mm_malloc(size, 16);
}
void operator delete[](void* ptr)
{
_mm_free(ptr);
}
private:
void Init2() // Various initializations and period certification
{
// Various initializations and period certification
uint32_t i, j, temp;
// Initialize mask
static const uint32_t maskinit[4] = {SFMT_MASK};
mask = _mm_loadu_si128((__m128i*)maskinit);
// Period certification
// Define period certification vector
static const uint32_t parityvec[4] = {SFMT_PARITY};
// Check if parityvec & state[0] has odd parity
temp = 0;
for (i = 0; i < 4; i++)
temp ^= parityvec[i] & ((uint32_t*)state)[i];
for (i = 16; i > 0; i >>= 1) temp ^= temp >> i;
if (!(temp & 1)) {
// parity is even. Certification failed
// Find a nonzero bit in period certification vector
for (i = 0; i < 4; i++) {
if (parityvec[i]) {
for (j = 1; j; j <<= 1) {
if (parityvec[i] & j) {
// Flip the corresponding bit in state[0] to change parity
((uint32_t*)state)[i] ^= j;
// Done. Exit i and j loops
i = 5; break;
}
}
}
}
}
// Generate first random numbers and set ix = 0
Generate();
}
void Generate() // Fill state array with new random numbers
{
// Fill state array with new random numbers
int i;
__m128i r, r1, r2;
r1 = state[SFMT_N - 2];
r2 = state[SFMT_N - 1];
for (i = 0; i < SFMT_N - SFMT_M; i++) {
r = sfmt_recursion(state[i], state[i + SFMT_M], r1, r2, mask);
state[i] = r;
r1 = r2;
r2 = r;
}
for (; i < SFMT_N; i++) {
r = sfmt_recursion(state[i], state[i + SFMT_M - SFMT_N], r1, r2, mask);
state[i] = r;
r1 = r2;
r2 = r;
}
ix = 0;
}
__m128i mask; // AND mask
__m128i state[SFMT_N]; // State vector for SFMT generator
uint32_t ix; // Index into state array
uint32_t LastInterval; // Last interval length for IRandom
uint32_t RLimit; // Rejection limit used by IRandom
};
#endif // SFMT_H

65
dep/SFMT/randomc.h Normal file
View File

@@ -0,0 +1,65 @@
/*
* Copyright notice
* ================
* GNU General Public License http://www.gnu.org/licenses/gpl.html
* This C++ implementation of SFMT contains parts of the original C code
* which was published under the following BSD license, which is therefore
* in effect in addition to the GNU General Public License.
* Copyright (c) 2006, 2007 by Mutsuo Saito, Makoto Matsumoto and Hiroshima University.
* Copyright (c) 2008 by Agner Fog.
* Copyright (c) 2012 Trinity Core
*
* BSD License:
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* > Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* > Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* > Neither the name of the Hiroshima University nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef RANDOMC_H
#define RANDOMC_H
// Define integer types with known size: int32_t, uint32_t, int64_t, uint64_t.
// If this doesn't work then insert compiler-specific definitions here:
#if defined(__GNUC__)
// Compilers supporting C99 or C++0x have inttypes.h defining these integer types
#include <inttypes.h>
#define INT64_SUPPORTED // Remove this if the compiler doesn't support 64-bit integers
#elif defined(_WIN16) || defined(__MSDOS__) || defined(_MSDOS)
// 16 bit systems use long int for 32 bit integer
typedef signed long int int32_t;
typedef unsigned long int uint32_t;
#elif defined(_MSC_VER)
// Microsoft have their own definition
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#define INT64_SUPPORTED // Remove this if the compiler doesn't support 64-bit integers
#else
// This works with most compilers
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
#define INT64_SUPPORTED // Remove this if the compiler doesn't support 64-bit integers
#endif
#endif // RANDOMC_H

67
dep/boost/CMakeLists.txt Normal file
View File

@@ -0,0 +1,67 @@
if(WIN32)
set(BOOST_DEBUG ON)
if(DEFINED ENV{BOOST_ROOT})
set(BOOST_ROOT $ENV{BOOST_ROOT})
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0)
set(BOOST_LIBRARYDIR ${BOOST_ROOT}/lib${PLATFORM}-msvc-12.0)
elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10)
set(BOOST_LIBRARYDIR ${BOOST_ROOT}/lib${PLATFORM}-msvc-14.0)
else()
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.20)
list(APPEND BOOST_LIBRARYDIR
${BOOST_ROOT}/lib${PLATFORM}-msvc-14.1
${BOOST_ROOT}/lib${PLATFORM}-msvc-14.0 )
else()
list(APPEND BOOST_LIBRARYDIR
${BOOST_ROOT}/lib${PLATFORM}-msvc-14.2
${BOOST_ROOT}/lib${PLATFORM}-msvc-14.1 )
endif()
endif()
else()
message(FATAL_ERROR "No BOOST_ROOT environment variable could be found! Please make sure it is set and the points to your Boost installation.")
endif()
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
endif()
find_package(Boost 1.64 REQUIRED system filesystem thread program_options iostreams regex)
# Find if Boost was compiled in C++03 mode because it requires -DBOOST_NO_CXX11_SCOPED_ENUMS
include (CheckCXXSourceCompiles)
set(CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_IOSTREAMS_LIBRARY})
set(CMAKE_REQUIRED_FLAGS "-std=c++11")
unset(boost_filesystem_copy_links_without_NO_SCOPED_ENUM CACHE)
check_cxx_source_compiles("
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
int main() { boost::filesystem::copy_file(boost::filesystem::path(), boost::filesystem::path()); }"
boost_filesystem_copy_links_without_NO_SCOPED_ENUM)
unset(CMAKE_REQUIRED_INCLUDES CACHE)
unset(CMAKE_REQUIRED_LIBRARIES CACHE)
unset(CMAKE_REQUIRED_FLAGS CACHE)
if (NOT boost_filesystem_copy_links_without_NO_SCOPED_ENUM)
set(OPTIONAL_BOOST_NO_SCOPED_ENUMS -DBOOST_NO_CXX11_SCOPED_ENUMS)
endif()
add_library(boost INTERFACE)
target_link_libraries(boost
INTERFACE
${Boost_LIBRARIES})
target_include_directories(boost
INTERFACE
${Boost_INCLUDE_DIRS})
target_compile_definitions(boost
INTERFACE
-DBOOST_DATE_TIME_NO_LIB
-DBOOST_REGEX_NO_LIB
-DBOOST_CHRONO_NO_LIB
${OPTIONAL_BOOST_NO_SCOPED_ENUMS})

37
dep/bzip2/CMakeLists.txt Normal file
View File

@@ -0,0 +1,37 @@
# Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
if(UNIX)
# Look for an installed bzip2 on unix
find_package(BZip2 REQUIRED)
add_library(bzip2 SHARED IMPORTED GLOBAL)
set_target_properties(bzip2
PROPERTIES
IMPORTED_LOCATION
"${BZIP2_LIBRARIES}"
INTERFACE_INCLUDE_DIRECTORIES
"${BZIP2_INCLUDE_DIRS}")
else()
# Use the bundled source on windows
file(GLOB sources *.c)
add_library(bzip2 STATIC
${sources})
target_include_directories(bzip2
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(bzip2
PROPERTIES
FOLDER
"dep")
endif()

42
dep/bzip2/LICENSE Normal file
View File

@@ -0,0 +1,42 @@
--------------------------------------------------------------------------
This program, "bzip2", the associated library "libbzip2", and all
documentation, are copyright (C) 1996-2010 Julian R Seward. All
rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. 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.
3. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
4. The name of the author may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Julian Seward, jseward@bzip.org
bzip2/libbzip2 version 1.0.6 of 6 September 2010
--------------------------------------------------------------------------

215
dep/bzip2/README Normal file
View File

@@ -0,0 +1,215 @@
This is the README for bzip2/libzip2.
This version is fully compatible with the previous public releases.
------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in this file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------
Complete documentation is available in Postscript form (manual.ps),
PDF (manual.pdf) or html (manual.html). A plain-text version of the
manual page is available as bzip2.txt.
HOW TO BUILD -- UNIX
Type 'make'. This builds the library libbz2.a and then the programs
bzip2 and bzip2recover. Six self-tests are run. If the self-tests
complete ok, carry on to installation:
To install in /usr/local/bin, /usr/local/lib, /usr/local/man and
/usr/local/include, type
make install
To install somewhere else, eg, /xxx/yyy/{bin,lib,man,include}, type
make install PREFIX=/xxx/yyy
If you are (justifiably) paranoid and want to see what 'make install'
is going to do, you can first do
make -n install or
make -n install PREFIX=/xxx/yyy respectively.
The -n instructs make to show the commands it would execute, but not
actually execute them.
HOW TO BUILD -- UNIX, shared library libbz2.so.
Do 'make -f Makefile-libbz2_so'. This Makefile seems to work for
Linux-ELF (RedHat 7.2 on an x86 box), with gcc. I make no claims
that it works for any other platform, though I suspect it probably
will work for most platforms employing both ELF and gcc.
bzip2-shared, a client of the shared library, is also built, but not
self-tested. So I suggest you also build using the normal Makefile,
since that conducts a self-test. A second reason to prefer the
version statically linked to the library is that, on x86 platforms,
building shared objects makes a valuable register (%ebx) unavailable
to gcc, resulting in a slowdown of 10%-20%, at least for bzip2.
Important note for people upgrading .so's from 0.9.0/0.9.5 to version
1.0.X. All the functions in the library have been renamed, from (eg)
bzCompress to BZ2_bzCompress, to avoid namespace pollution.
Unfortunately this means that the libbz2.so created by
Makefile-libbz2_so will not work with any program which used an older
version of the library. I do encourage library clients to make the
effort to upgrade to use version 1.0, since it is both faster and more
robust than previous versions.
HOW TO BUILD -- Windows 95, NT, DOS, Mac, etc.
It's difficult for me to support compilation on all these platforms.
My approach is to collect binaries for these platforms, and put them
on the master web site (http://www.bzip.org). Look there. However
(FWIW), bzip2-1.0.X is very standard ANSI C and should compile
unmodified with MS Visual C. If you have difficulties building, you
might want to read README.COMPILATION.PROBLEMS.
At least using MS Visual C++ 6, you can build from the unmodified
sources by issuing, in a command shell:
nmake -f makefile.msc
(you may need to first run the MSVC-provided script VCVARS32.BAT
so as to set up paths to the MSVC tools correctly).
VALIDATION
Correct operation, in the sense that a compressed file can always be
decompressed to reproduce the original, is obviously of paramount
importance. To validate bzip2, I used a modified version of Mark
Nelson's churn program. Churn is an automated test driver which
recursively traverses a directory structure, using bzip2 to compress
and then decompress each file it encounters, and checking that the
decompressed data is the same as the original.
Please read and be aware of the following:
WARNING:
This program and library (attempts to) compress data by
performing several non-trivial transformations on it.
Unless you are 100% familiar with *all* the algorithms
contained herein, and with the consequences of modifying them,
you should NOT meddle with the compression or decompression
machinery. Incorrect changes can and very likely *will*
lead to disastrous loss of data.
DISCLAIMER:
I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE
USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED.
Every compression of a file implies an assumption that the
compressed file can be decompressed to reproduce the original.
Great efforts in design, coding and testing have been made to
ensure that this program works correctly. However, the complexity
of the algorithms, and, in particular, the presence of various
special cases in the code which occur with very low but non-zero
probability make it impossible to rule out the possibility of bugs
remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS
PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER
SMALL, THAT THE DATA WILL NOT BE RECOVERABLE.
That is not to say this program is inherently unreliable.
Indeed, I very much hope the opposite is true. bzip2/libbzip2
has been carefully constructed and extensively tested.
PATENTS:
To the best of my knowledge, bzip2/libbzip2 does not use any
patented algorithms. However, I do not have the resources
to carry out a patent search. Therefore I cannot give any
guarantee of the above statement.
WHAT'S NEW IN 0.9.0 (as compared to 0.1pl2) ?
* Approx 10% faster compression, 30% faster decompression
* -t (test mode) is a lot quicker
* Can decompress concatenated compressed files
* Programming interface, so programs can directly read/write .bz2 files
* Less restrictive (BSD-style) licensing
* Flag handling more compatible with GNU gzip
* Much more documentation, i.e., a proper user manual
* Hopefully, improved portability (at least of the library)
WHAT'S NEW IN 0.9.5 ?
* Compression speed is much less sensitive to the input
data than in previous versions. Specifically, the very
slow performance caused by repetitive data is fixed.
* Many small improvements in file and flag handling.
* A Y2K statement.
WHAT'S NEW IN 1.0.0 ?
See the CHANGES file.
WHAT'S NEW IN 1.0.2 ?
See the CHANGES file.
WHAT'S NEW IN 1.0.3 ?
See the CHANGES file.
WHAT'S NEW IN 1.0.4 ?
See the CHANGES file.
WHAT'S NEW IN 1.0.5 ?
See the CHANGES file.
WHAT'S NEW IN 1.0.6 ?
See the CHANGES file.
I hope you find bzip2 useful. Feel free to contact me at
jseward@bzip.org
if you have any suggestions or queries. Many people mailed me with
comments, suggestions and patches after the releases of bzip-0.15,
bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1,
1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this
feedback. I thank you for your comments.
bzip2's "home" is http://www.bzip.org/
Julian Seward
jseward@bzip.org
Cambridge, UK.
18 July 1996 (version 0.15)
25 August 1996 (version 0.21)
7 August 1997 (bzip2, version 0.1)
29 August 1997 (bzip2, version 0.1pl2)
23 August 1998 (bzip2, version 0.9.0)
8 June 1999 (bzip2, version 0.9.5)
4 Sept 1999 (bzip2, version 0.9.5d)
5 May 2000 (bzip2, version 1.0pre8)
30 December 2001 (bzip2, version 1.0.2pre1)
15 February 2005 (bzip2, version 1.0.3)
20 December 2006 (bzip2, version 1.0.4)
10 December 2007 (bzip2, version 1.0.5)
6 Sept 2010 (bzip2, version 1.0.6)

1094
dep/bzip2/blocksort.c Normal file

File diff suppressed because it is too large Load Diff

1572
dep/bzip2/bzlib.c Normal file

File diff suppressed because it is too large Load Diff

282
dep/bzip2/bzlib.h Normal file
View File

@@ -0,0 +1,282 @@
/*-------------------------------------------------------------*/
/*--- Public header file for the library. ---*/
/*--- bzlib.h ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#ifndef _BZLIB_H
#define _BZLIB_H
#ifdef __cplusplus
extern "C" {
#endif
#define BZ_RUN 0
#define BZ_FLUSH 1
#define BZ_FINISH 2
#define BZ_OK 0
#define BZ_RUN_OK 1
#define BZ_FLUSH_OK 2
#define BZ_FINISH_OK 3
#define BZ_STREAM_END 4
#define BZ_SEQUENCE_ERROR (-1)
#define BZ_PARAM_ERROR (-2)
#define BZ_MEM_ERROR (-3)
#define BZ_DATA_ERROR (-4)
#define BZ_DATA_ERROR_MAGIC (-5)
#define BZ_IO_ERROR (-6)
#define BZ_UNEXPECTED_EOF (-7)
#define BZ_OUTBUFF_FULL (-8)
#define BZ_CONFIG_ERROR (-9)
typedef
struct {
char *next_in;
unsigned int avail_in;
unsigned int total_in_lo32;
unsigned int total_in_hi32;
char *next_out;
unsigned int avail_out;
unsigned int total_out_lo32;
unsigned int total_out_hi32;
void *state;
void *(*bzalloc)(void *,int,int);
void (*bzfree)(void *,void *);
void *opaque;
}
bz_stream;
#ifndef BZ_IMPORT
#define BZ_EXPORT
#endif
#ifndef BZ_NO_STDIO
/* Need a definitition for FILE */
#include <stdio.h>
#endif
#ifdef _WIN32
# include <windows.h>
# ifdef small
/* windows.h define small to char */
# undef small
# endif
# ifdef BZ_EXPORT
# define BZ_API(func) WINAPI func
# define BZ_EXTERN extern
# else
/* import windows dll dynamically */
# define BZ_API(func) (WINAPI * func)
# define BZ_EXTERN
# endif
#else
# define BZ_API(func) func
# define BZ_EXTERN extern
#endif
/*-- Core (low-level) library functions --*/
BZ_EXTERN int BZ_API(BZ2_bzCompressInit) (
bz_stream* strm,
int blockSize100k,
int verbosity,
int workFactor
);
BZ_EXTERN int BZ_API(BZ2_bzCompress) (
bz_stream* strm,
int action
);
BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) (
bz_stream* strm
);
BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) (
bz_stream *strm,
int verbosity,
int small
);
BZ_EXTERN int BZ_API(BZ2_bzDecompress) (
bz_stream* strm
);
BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) (
bz_stream *strm
);
/*-- High(er) level library functions --*/
#ifndef BZ_NO_STDIO
#define BZ_MAX_UNUSED 5000
typedef void BZFILE;
BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) (
int* bzerror,
FILE* f,
int verbosity,
int small,
void* unused,
int nUnused
);
BZ_EXTERN void BZ_API(BZ2_bzReadClose) (
int* bzerror,
BZFILE* b
);
BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) (
int* bzerror,
BZFILE* b,
void** unused,
int* nUnused
);
BZ_EXTERN int BZ_API(BZ2_bzRead) (
int* bzerror,
BZFILE* b,
void* buf,
int len
);
BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) (
int* bzerror,
FILE* f,
int blockSize100k,
int verbosity,
int workFactor
);
BZ_EXTERN void BZ_API(BZ2_bzWrite) (
int* bzerror,
BZFILE* b,
void* buf,
int len
);
BZ_EXTERN void BZ_API(BZ2_bzWriteClose) (
int* bzerror,
BZFILE* b,
int abandon,
unsigned int* nbytes_in,
unsigned int* nbytes_out
);
BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) (
int* bzerror,
BZFILE* b,
int abandon,
unsigned int* nbytes_in_lo32,
unsigned int* nbytes_in_hi32,
unsigned int* nbytes_out_lo32,
unsigned int* nbytes_out_hi32
);
#endif
/*-- Utility functions --*/
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) (
char* dest,
unsigned int* destLen,
char* source,
unsigned int sourceLen,
int blockSize100k,
int verbosity,
int workFactor
);
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) (
char* dest,
unsigned int* destLen,
char* source,
unsigned int sourceLen,
int small,
int verbosity
);
/*--
Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
to support better zlib compatibility.
This code is not _officially_ part of libbzip2 (yet);
I haven't tested it, documented it, or considered the
threading-safeness of it.
If this code breaks, please contact both Yoshioka and me.
--*/
BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
void
);
#ifndef BZ_NO_STDIO
BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
const char *path,
const char *mode
);
BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
int fd,
const char *mode
);
BZ_EXTERN int BZ_API(BZ2_bzread) (
BZFILE* b,
void* buf,
int len
);
BZ_EXTERN int BZ_API(BZ2_bzwrite) (
BZFILE* b,
void* buf,
int len
);
BZ_EXTERN int BZ_API(BZ2_bzflush) (
BZFILE* b
);
BZ_EXTERN void BZ_API(BZ2_bzclose) (
BZFILE* b
);
BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
BZFILE *b,
int *errnum
);
#endif
#ifdef __cplusplus
}
#endif
#endif
/*-------------------------------------------------------------*/
/*--- end bzlib.h ---*/
/*-------------------------------------------------------------*/

509
dep/bzip2/bzlib_private.h Normal file
View File

@@ -0,0 +1,509 @@
/*-------------------------------------------------------------*/
/*--- Private header file for the library. ---*/
/*--- bzlib_private.h ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#ifndef _BZLIB_PRIVATE_H
#define _BZLIB_PRIVATE_H
#include <stdlib.h>
#ifndef BZ_NO_STDIO
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#endif
#include "bzlib.h"
/*-- General stuff. --*/
#define BZ_VERSION "1.0.6, 6-Sept-2010"
typedef char Char;
typedef unsigned char Bool;
typedef unsigned char UChar;
typedef int Int32;
typedef unsigned int UInt32;
typedef short Int16;
typedef unsigned short UInt16;
#define True ((Bool)1)
#define False ((Bool)0)
#ifndef __GNUC__
#define __inline__ /* */
#endif
#ifndef BZ_NO_STDIO
extern void BZ2_bz__AssertH__fail ( int errcode );
#define AssertH(cond,errcode) \
{ if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
#if BZ_DEBUG
#define AssertD(cond,msg) \
{ if (!(cond)) { \
fprintf ( stderr, \
"\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
exit(1); \
}}
#else
#define AssertD(cond,msg) /* */
#endif
#define VPrintf0(zf) \
fprintf(stderr,zf)
#define VPrintf1(zf,za1) \
fprintf(stderr,zf,za1)
#define VPrintf2(zf,za1,za2) \
fprintf(stderr,zf,za1,za2)
#define VPrintf3(zf,za1,za2,za3) \
fprintf(stderr,zf,za1,za2,za3)
#define VPrintf4(zf,za1,za2,za3,za4) \
fprintf(stderr,zf,za1,za2,za3,za4)
#define VPrintf5(zf,za1,za2,za3,za4,za5) \
fprintf(stderr,zf,za1,za2,za3,za4,za5)
#else
extern void bz_internal_error ( int errcode );
#define AssertH(cond,errcode) \
{ if (!(cond)) bz_internal_error ( errcode ); }
#define AssertD(cond,msg) do { } while (0)
#define VPrintf0(zf) do { } while (0)
#define VPrintf1(zf,za1) do { } while (0)
#define VPrintf2(zf,za1,za2) do { } while (0)
#define VPrintf3(zf,za1,za2,za3) do { } while (0)
#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0)
#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
#endif
#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp))
/*-- Header bytes. --*/
#define BZ_HDR_B 0x42 /* 'B' */
#define BZ_HDR_Z 0x5a /* 'Z' */
#define BZ_HDR_h 0x68 /* 'h' */
#define BZ_HDR_0 0x30 /* '0' */
/*-- Constants for the back end. --*/
#define BZ_MAX_ALPHA_SIZE 258
#define BZ_MAX_CODE_LEN 23
#define BZ_RUNA 0
#define BZ_RUNB 1
#define BZ_N_GROUPS 6
#define BZ_G_SIZE 50
#define BZ_N_ITERS 4
#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
/*-- Stuff for randomising repetitive blocks. --*/
extern Int32 BZ2_rNums[512];
#define BZ_RAND_DECLS \
Int32 rNToGo; \
Int32 rTPos \
#define BZ_RAND_INIT_MASK \
s->rNToGo = 0; \
s->rTPos = 0 \
#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
#define BZ_RAND_UPD_MASK \
if (s->rNToGo == 0) { \
s->rNToGo = BZ2_rNums[s->rTPos]; \
s->rTPos++; \
if (s->rTPos == 512) s->rTPos = 0; \
} \
s->rNToGo--;
/*-- Stuff for doing CRCs. --*/
extern UInt32 BZ2_crc32Table[256];
#define BZ_INITIALISE_CRC(crcVar) \
{ \
crcVar = 0xffffffffL; \
}
#define BZ_FINALISE_CRC(crcVar) \
{ \
crcVar = ~(crcVar); \
}
#define BZ_UPDATE_CRC(crcVar,cha) \
{ \
crcVar = (crcVar << 8) ^ \
BZ2_crc32Table[(crcVar >> 24) ^ \
((UChar)cha)]; \
}
/*-- States and modes for compression. --*/
#define BZ_M_IDLE 1
#define BZ_M_RUNNING 2
#define BZ_M_FLUSHING 3
#define BZ_M_FINISHING 4
#define BZ_S_OUTPUT 1
#define BZ_S_INPUT 2
#define BZ_N_RADIX 2
#define BZ_N_QSORT 12
#define BZ_N_SHELL 18
#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
/*-- Structure holding all the compression-side stuff. --*/
typedef
struct {
/* pointer back to the struct bz_stream */
bz_stream* strm;
/* mode this stream is in, and whether inputting */
/* or outputting data */
Int32 mode;
Int32 state;
/* remembers avail_in when flush/finish requested */
UInt32 avail_in_expect;
/* for doing the block sorting */
UInt32* arr1;
UInt32* arr2;
UInt32* ftab;
Int32 origPtr;
/* aliases for arr1 and arr2 */
UInt32* ptr;
UChar* block;
UInt16* mtfv;
UChar* zbits;
/* for deciding when to use the fallback sorting algorithm */
Int32 workFactor;
/* run-length-encoding of the input */
UInt32 state_in_ch;
Int32 state_in_len;
BZ_RAND_DECLS;
/* input and output limits and current posns */
Int32 nblock;
Int32 nblockMAX;
Int32 numZ;
Int32 state_out_pos;
/* map of bytes used in block */
Int32 nInUse;
Bool inUse[256];
UChar unseqToSeq[256];
/* the buffer for bit stream creation */
UInt32 bsBuff;
Int32 bsLive;
/* block and combined CRCs */
UInt32 blockCRC;
UInt32 combinedCRC;
/* misc administratium */
Int32 verbosity;
Int32 blockNo;
Int32 blockSize100k;
/* stuff for coding the MTF values */
Int32 nMTF;
Int32 mtfFreq [BZ_MAX_ALPHA_SIZE];
UChar selector [BZ_MAX_SELECTORS];
UChar selectorMtf[BZ_MAX_SELECTORS];
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
/* second dimension: only 3 needed; 4 makes index calculations faster */
UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4];
}
EState;
/*-- externs for compression. --*/
extern void
BZ2_blockSort ( EState* );
extern void
BZ2_compressBlock ( EState*, Bool );
extern void
BZ2_bsInitWrite ( EState* );
extern void
BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
extern void
BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
/*-- states for decompression. --*/
#define BZ_X_IDLE 1
#define BZ_X_OUTPUT 2
#define BZ_X_MAGIC_1 10
#define BZ_X_MAGIC_2 11
#define BZ_X_MAGIC_3 12
#define BZ_X_MAGIC_4 13
#define BZ_X_BLKHDR_1 14
#define BZ_X_BLKHDR_2 15
#define BZ_X_BLKHDR_3 16
#define BZ_X_BLKHDR_4 17
#define BZ_X_BLKHDR_5 18
#define BZ_X_BLKHDR_6 19
#define BZ_X_BCRC_1 20
#define BZ_X_BCRC_2 21
#define BZ_X_BCRC_3 22
#define BZ_X_BCRC_4 23
#define BZ_X_RANDBIT 24
#define BZ_X_ORIGPTR_1 25
#define BZ_X_ORIGPTR_2 26
#define BZ_X_ORIGPTR_3 27
#define BZ_X_MAPPING_1 28
#define BZ_X_MAPPING_2 29
#define BZ_X_SELECTOR_1 30
#define BZ_X_SELECTOR_2 31
#define BZ_X_SELECTOR_3 32
#define BZ_X_CODING_1 33
#define BZ_X_CODING_2 34
#define BZ_X_CODING_3 35
#define BZ_X_MTF_1 36
#define BZ_X_MTF_2 37
#define BZ_X_MTF_3 38
#define BZ_X_MTF_4 39
#define BZ_X_MTF_5 40
#define BZ_X_MTF_6 41
#define BZ_X_ENDHDR_2 42
#define BZ_X_ENDHDR_3 43
#define BZ_X_ENDHDR_4 44
#define BZ_X_ENDHDR_5 45
#define BZ_X_ENDHDR_6 46
#define BZ_X_CCRC_1 47
#define BZ_X_CCRC_2 48
#define BZ_X_CCRC_3 49
#define BZ_X_CCRC_4 50
/*-- Constants for the fast MTF decoder. --*/
#define MTFA_SIZE 4096
#define MTFL_SIZE 16
/*-- Structure holding all the decompression-side stuff. --*/
typedef
struct {
/* pointer back to the struct bz_stream */
bz_stream* strm;
/* state indicator for this stream */
Int32 state;
/* for doing the final run-length decoding */
UChar state_out_ch;
Int32 state_out_len;
Bool blockRandomised;
BZ_RAND_DECLS;
/* the buffer for bit stream reading */
UInt32 bsBuff;
Int32 bsLive;
/* misc administratium */
Int32 blockSize100k;
Bool smallDecompress;
Int32 currBlockNo;
Int32 verbosity;
/* for undoing the Burrows-Wheeler transform */
Int32 origPtr;
UInt32 tPos;
Int32 k0;
Int32 unzftab[256];
Int32 nblock_used;
Int32 cftab[257];
Int32 cftabCopy[257];
/* for undoing the Burrows-Wheeler transform (FAST) */
UInt32 *tt;
/* for undoing the Burrows-Wheeler transform (SMALL) */
UInt16 *ll16;
UChar *ll4;
/* stored and calculated CRCs */
UInt32 storedBlockCRC;
UInt32 storedCombinedCRC;
UInt32 calculatedBlockCRC;
UInt32 calculatedCombinedCRC;
/* map of bytes used in block */
Int32 nInUse;
Bool inUse[256];
Bool inUse16[16];
UChar seqToUnseq[256];
/* for decoding the MTF values */
UChar mtfa [MTFA_SIZE];
Int32 mtfbase[256 / MTFL_SIZE];
UChar selector [BZ_MAX_SELECTORS];
UChar selectorMtf[BZ_MAX_SELECTORS];
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 minLens[BZ_N_GROUPS];
/* save area for scalars in the main decompress code */
Int32 save_i;
Int32 save_j;
Int32 save_t;
Int32 save_alphaSize;
Int32 save_nGroups;
Int32 save_nSelectors;
Int32 save_EOB;
Int32 save_groupNo;
Int32 save_groupPos;
Int32 save_nextSym;
Int32 save_nblockMAX;
Int32 save_nblock;
Int32 save_es;
Int32 save_N;
Int32 save_curr;
Int32 save_zt;
Int32 save_zn;
Int32 save_zvec;
Int32 save_zj;
Int32 save_gSel;
Int32 save_gMinlen;
Int32* save_gLimit;
Int32* save_gBase;
Int32* save_gPerm;
}
DState;
/*-- Macros for decompression. --*/
#define BZ_GET_FAST(cccc) \
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
s->tPos = s->tt[s->tPos]; \
cccc = (UChar)(s->tPos & 0xff); \
s->tPos >>= 8;
#define BZ_GET_FAST_C(cccc) \
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
c_tPos = c_tt[c_tPos]; \
cccc = (UChar)(c_tPos & 0xff); \
c_tPos >>= 8;
#define SET_LL4(i,n) \
{ if (((i) & 0x1) == 0) \
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \
}
#define GET_LL4(i) \
((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
#define SET_LL(i,n) \
{ s->ll16[i] = (UInt16)(n & 0x0000ffff); \
SET_LL4(i, n >> 16); \
}
#define GET_LL(i) \
(((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
#define BZ_GET_SMALL(cccc) \
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \
s->tPos = GET_LL(s->tPos);
/*-- externs for decompression. --*/
extern Int32
BZ2_indexIntoF ( Int32, Int32* );
extern Int32
BZ2_decompress ( DState* );
extern void
BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
Int32, Int32, Int32 );
#endif
/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
#ifdef BZ_NO_STDIO
#ifndef NULL
#define NULL 0
#endif
#endif
/*-------------------------------------------------------------*/
/*--- end bzlib_private.h ---*/
/*-------------------------------------------------------------*/

672
dep/bzip2/compress.c Normal file
View File

@@ -0,0 +1,672 @@
/*-------------------------------------------------------------*/
/*--- Compression machinery (not incl block sorting) ---*/
/*--- compress.c ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
/* CHANGES
0.9.0 -- original version.
0.9.0a/b -- no changes in this file.
0.9.0c -- changed setting of nGroups in sendMTFValues()
so as to do a bit better on small files
*/
#include "bzlib_private.h"
/*---------------------------------------------------*/
/*--- Bit stream I/O ---*/
/*---------------------------------------------------*/
/*---------------------------------------------------*/
void BZ2_bsInitWrite ( EState* s )
{
s->bsLive = 0;
s->bsBuff = 0;
}
/*---------------------------------------------------*/
static
void bsFinishWrite ( EState* s )
{
while (s->bsLive > 0) {
s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
s->numZ++;
s->bsBuff <<= 8;
s->bsLive -= 8;
}
}
/*---------------------------------------------------*/
#define bsNEEDW(nz) \
{ \
while (s->bsLive >= 8) { \
s->zbits[s->numZ] \
= (UChar)(s->bsBuff >> 24); \
s->numZ++; \
s->bsBuff <<= 8; \
s->bsLive -= 8; \
} \
}
/*---------------------------------------------------*/
static
__inline__
void bsW ( EState* s, Int32 n, UInt32 v )
{
bsNEEDW ( n );
s->bsBuff |= (v << (32 - s->bsLive - n));
s->bsLive += n;
}
/*---------------------------------------------------*/
static
void bsPutUInt32 ( EState* s, UInt32 u )
{
bsW ( s, 8, (u >> 24) & 0xffL );
bsW ( s, 8, (u >> 16) & 0xffL );
bsW ( s, 8, (u >> 8) & 0xffL );
bsW ( s, 8, u & 0xffL );
}
/*---------------------------------------------------*/
static
void bsPutUChar ( EState* s, UChar c )
{
bsW( s, 8, (UInt32)c );
}
/*---------------------------------------------------*/
/*--- The back end proper ---*/
/*---------------------------------------------------*/
/*---------------------------------------------------*/
static
void makeMaps_e ( EState* s )
{
Int32 i;
s->nInUse = 0;
for (i = 0; i < 256; i++)
if (s->inUse[i]) {
s->unseqToSeq[i] = s->nInUse;
s->nInUse++;
}
}
/*---------------------------------------------------*/
static
void generateMTFValues ( EState* s )
{
UChar yy[256];
Int32 i, j;
Int32 zPend;
Int32 wr;
Int32 EOB;
/*
After sorting (eg, here),
s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
and
((UChar*)s->arr2) [ 0 .. s->nblock-1 ]
holds the original block data.
The first thing to do is generate the MTF values,
and put them in
((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
Because there are strictly fewer or equal MTF values
than block values, ptr values in this area are overwritten
with MTF values only when they are no longer needed.
The final compressed bitstream is generated into the
area starting at
(UChar*) (&((UChar*)s->arr2)[s->nblock])
These storage aliases are set up in bzCompressInit(),
except for the last one, which is arranged in
compressBlock().
*/
UInt32* ptr = s->ptr;
UChar* block = s->block;
UInt16* mtfv = s->mtfv;
makeMaps_e ( s );
EOB = s->nInUse+1;
for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
wr = 0;
zPend = 0;
for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
for (i = 0; i < s->nblock; i++) {
UChar ll_i;
AssertD ( wr <= i, "generateMTFValues(1)" );
j = ptr[i]-1; if (j < 0) j += s->nblock;
ll_i = s->unseqToSeq[block[j]];
AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
if (yy[0] == ll_i) {
zPend++;
} else {
if (zPend > 0) {
zPend--;
while (True) {
if (zPend & 1) {
mtfv[wr] = BZ_RUNB; wr++;
s->mtfFreq[BZ_RUNB]++;
} else {
mtfv[wr] = BZ_RUNA; wr++;
s->mtfFreq[BZ_RUNA]++;
}
if (zPend < 2) break;
zPend = (zPend - 2) / 2;
};
zPend = 0;
}
{
register UChar rtmp;
register UChar* ryy_j;
register UChar rll_i;
rtmp = yy[1];
yy[1] = yy[0];
ryy_j = &(yy[1]);
rll_i = ll_i;
while ( rll_i != rtmp ) {
register UChar rtmp2;
ryy_j++;
rtmp2 = rtmp;
rtmp = *ryy_j;
*ryy_j = rtmp2;
};
yy[0] = rtmp;
j = ryy_j - &(yy[0]);
mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
}
}
}
if (zPend > 0) {
zPend--;
while (True) {
if (zPend & 1) {
mtfv[wr] = BZ_RUNB; wr++;
s->mtfFreq[BZ_RUNB]++;
} else {
mtfv[wr] = BZ_RUNA; wr++;
s->mtfFreq[BZ_RUNA]++;
}
if (zPend < 2) break;
zPend = (zPend - 2) / 2;
};
zPend = 0;
}
mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
s->nMTF = wr;
}
/*---------------------------------------------------*/
#define BZ_LESSER_ICOST 0
#define BZ_GREATER_ICOST 15
static
void sendMTFValues ( EState* s )
{
Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
Int32 nGroups, nBytes;
/*--
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
is a global since the decoder also needs it.
Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
are also globals only used in this proc.
Made global to keep stack frame size small.
--*/
UInt16 cost[BZ_N_GROUPS];
Int32 fave[BZ_N_GROUPS];
UInt16* mtfv = s->mtfv;
if (s->verbosity >= 3)
VPrintf3( " %d in block, %d after MTF & 1-2 coding, "
"%d+2 syms in use\n",
s->nblock, s->nMTF, s->nInUse );
alphaSize = s->nInUse+2;
for (t = 0; t < BZ_N_GROUPS; t++)
for (v = 0; v < alphaSize; v++)
s->len[t][v] = BZ_GREATER_ICOST;
/*--- Decide how many coding tables to use ---*/
AssertH ( s->nMTF > 0, 3001 );
if (s->nMTF < 200) nGroups = 2; else
if (s->nMTF < 600) nGroups = 3; else
if (s->nMTF < 1200) nGroups = 4; else
if (s->nMTF < 2400) nGroups = 5; else
nGroups = 6;
/*--- Generate an initial set of coding tables ---*/
{
Int32 nPart, remF, tFreq, aFreq;
nPart = nGroups;
remF = s->nMTF;
gs = 0;
while (nPart > 0) {
tFreq = remF / nPart;
ge = gs-1;
aFreq = 0;
while (aFreq < tFreq && ge < alphaSize-1) {
ge++;
aFreq += s->mtfFreq[ge];
}
if (ge > gs
&& nPart != nGroups && nPart != 1
&& ((nGroups-nPart) % 2 == 1)) {
aFreq -= s->mtfFreq[ge];
ge--;
}
if (s->verbosity >= 3)
VPrintf5( " initial group %d, [%d .. %d], "
"has %d syms (%4.1f%%)\n",
nPart, gs, ge, aFreq,
(100.0 * (float)aFreq) / (float)(s->nMTF) );
for (v = 0; v < alphaSize; v++)
if (v >= gs && v <= ge)
s->len[nPart-1][v] = BZ_LESSER_ICOST; else
s->len[nPart-1][v] = BZ_GREATER_ICOST;
nPart--;
gs = ge+1;
remF -= aFreq;
}
}
/*---
Iterate up to BZ_N_ITERS times to improve the tables.
---*/
for (iter = 0; iter < BZ_N_ITERS; iter++) {
for (t = 0; t < nGroups; t++) fave[t] = 0;
for (t = 0; t < nGroups; t++)
for (v = 0; v < alphaSize; v++)
s->rfreq[t][v] = 0;
/*---
Set up an auxiliary length table which is used to fast-track
the common case (nGroups == 6).
---*/
if (nGroups == 6) {
for (v = 0; v < alphaSize; v++) {
s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
}
}
nSelectors = 0;
totc = 0;
gs = 0;
while (True) {
/*--- Set group start & end marks. --*/
if (gs >= s->nMTF) break;
ge = gs + BZ_G_SIZE - 1;
if (ge >= s->nMTF) ge = s->nMTF-1;
/*--
Calculate the cost of this group as coded
by each of the coding tables.
--*/
for (t = 0; t < nGroups; t++) cost[t] = 0;
if (nGroups == 6 && 50 == ge-gs+1) {
/*--- fast track the common case ---*/
register UInt32 cost01, cost23, cost45;
register UInt16 icv;
cost01 = cost23 = cost45 = 0;
# define BZ_ITER(nn) \
icv = mtfv[gs+(nn)]; \
cost01 += s->len_pack[icv][0]; \
cost23 += s->len_pack[icv][1]; \
cost45 += s->len_pack[icv][2]; \
BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4);
BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9);
BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
# undef BZ_ITER
cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
} else {
/*--- slow version which correctly handles all situations ---*/
for (i = gs; i <= ge; i++) {
UInt16 icv = mtfv[i];
for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
}
}
/*--
Find the coding table which is best for this group,
and record its identity in the selector table.
--*/
bc = 999999999; bt = -1;
for (t = 0; t < nGroups; t++)
if (cost[t] < bc) { bc = cost[t]; bt = t; };
totc += bc;
fave[bt]++;
s->selector[nSelectors] = bt;
nSelectors++;
/*--
Increment the symbol frequencies for the selected table.
--*/
if (nGroups == 6 && 50 == ge-gs+1) {
/*--- fast track the common case ---*/
# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4);
BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9);
BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
# undef BZ_ITUR
} else {
/*--- slow version which correctly handles all situations ---*/
for (i = gs; i <= ge; i++)
s->rfreq[bt][ mtfv[i] ]++;
}
gs = ge+1;
}
if (s->verbosity >= 3) {
VPrintf2 ( " pass %d: size is %d, grp uses are ",
iter+1, totc/8 );
for (t = 0; t < nGroups; t++)
VPrintf1 ( "%d ", fave[t] );
VPrintf0 ( "\n" );
}
/*--
Recompute the tables based on the accumulated frequencies.
--*/
/* maxLen was changed from 20 to 17 in bzip2-1.0.3. See
comment in huffman.c for details. */
for (t = 0; t < nGroups; t++)
BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]),
alphaSize, 17 /*20*/ );
}
AssertH( nGroups < 8, 3002 );
AssertH( nSelectors < 32768 &&
nSelectors <= (2 + (900000 / BZ_G_SIZE)),
3003 );
/*--- Compute MTF values for the selectors. ---*/
{
UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
for (i = 0; i < nGroups; i++) pos[i] = i;
for (i = 0; i < nSelectors; i++) {
ll_i = s->selector[i];
j = 0;
tmp = pos[j];
while ( ll_i != tmp ) {
j++;
tmp2 = tmp;
tmp = pos[j];
pos[j] = tmp2;
};
pos[0] = tmp;
s->selectorMtf[i] = j;
}
};
/*--- Assign actual codes for the tables. --*/
for (t = 0; t < nGroups; t++) {
minLen = 32;
maxLen = 0;
for (i = 0; i < alphaSize; i++) {
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
if (s->len[t][i] < minLen) minLen = s->len[t][i];
}
AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
AssertH ( !(minLen < 1), 3005 );
BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]),
minLen, maxLen, alphaSize );
}
/*--- Transmit the mapping table. ---*/
{
Bool inUse16[16];
for (i = 0; i < 16; i++) {
inUse16[i] = False;
for (j = 0; j < 16; j++)
if (s->inUse[i * 16 + j]) inUse16[i] = True;
}
nBytes = s->numZ;
for (i = 0; i < 16; i++)
if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
for (i = 0; i < 16; i++)
if (inUse16[i])
for (j = 0; j < 16; j++) {
if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
}
if (s->verbosity >= 3)
VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes );
}
/*--- Now the selectors. ---*/
nBytes = s->numZ;
bsW ( s, 3, nGroups );
bsW ( s, 15, nSelectors );
for (i = 0; i < nSelectors; i++) {
for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
bsW(s,1,0);
}
if (s->verbosity >= 3)
VPrintf1( "selectors %d, ", s->numZ-nBytes );
/*--- Now the coding tables. ---*/
nBytes = s->numZ;
for (t = 0; t < nGroups; t++) {
Int32 curr = s->len[t][0];
bsW ( s, 5, curr );
for (i = 0; i < alphaSize; i++) {
while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
bsW ( s, 1, 0 );
}
}
if (s->verbosity >= 3)
VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
/*--- And finally, the block data proper ---*/
nBytes = s->numZ;
selCtr = 0;
gs = 0;
while (True) {
if (gs >= s->nMTF) break;
ge = gs + BZ_G_SIZE - 1;
if (ge >= s->nMTF) ge = s->nMTF-1;
AssertH ( s->selector[selCtr] < nGroups, 3006 );
if (nGroups == 6 && 50 == ge-gs+1) {
/*--- fast track the common case ---*/
UInt16 mtfv_i;
UChar* s_len_sel_selCtr
= &(s->len[s->selector[selCtr]][0]);
Int32* s_code_sel_selCtr
= &(s->code[s->selector[selCtr]][0]);
# define BZ_ITAH(nn) \
mtfv_i = mtfv[gs+(nn)]; \
bsW ( s, \
s_len_sel_selCtr[mtfv_i], \
s_code_sel_selCtr[mtfv_i] )
BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4);
BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9);
BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
# undef BZ_ITAH
} else {
/*--- slow version which correctly handles all situations ---*/
for (i = gs; i <= ge; i++) {
bsW ( s,
s->len [s->selector[selCtr]] [mtfv[i]],
s->code [s->selector[selCtr]] [mtfv[i]] );
}
}
gs = ge+1;
selCtr++;
}
AssertH( selCtr == nSelectors, 3007 );
if (s->verbosity >= 3)
VPrintf1( "codes %d\n", s->numZ-nBytes );
}
/*---------------------------------------------------*/
void BZ2_compressBlock ( EState* s, Bool is_last_block )
{
if (s->nblock > 0) {
BZ_FINALISE_CRC ( s->blockCRC );
s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
s->combinedCRC ^= s->blockCRC;
if (s->blockNo > 1) s->numZ = 0;
if (s->verbosity >= 2)
VPrintf4( " block %d: crc = 0x%08x, "
"combined CRC = 0x%08x, size = %d\n",
s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
BZ2_blockSort ( s );
}
s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
/*-- If this is the first block, create the stream header. --*/
if (s->blockNo == 1) {
BZ2_bsInitWrite ( s );
bsPutUChar ( s, BZ_HDR_B );
bsPutUChar ( s, BZ_HDR_Z );
bsPutUChar ( s, BZ_HDR_h );
bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
}
if (s->nblock > 0) {
bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
/*-- Now the block's CRC, so it is in a known place. --*/
bsPutUInt32 ( s, s->blockCRC );
/*--
Now a single bit indicating (non-)randomisation.
As of version 0.9.5, we use a better sorting algorithm
which makes randomisation unnecessary. So always set
the randomised bit to 'no'. Of course, the decoder
still needs to be able to handle randomised blocks
so as to maintain backwards compatibility with
older versions of bzip2.
--*/
bsW(s,1,0);
bsW ( s, 24, s->origPtr );
generateMTFValues ( s );
sendMTFValues ( s );
}
/*-- If this is the last block, add the stream trailer. --*/
if (is_last_block) {
bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
bsPutUInt32 ( s, s->combinedCRC );
if (s->verbosity >= 2)
VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC );
bsFinishWrite ( s );
}
}
/*-------------------------------------------------------------*/
/*--- end compress.c ---*/
/*-------------------------------------------------------------*/

104
dep/bzip2/crctable.c Normal file
View File

@@ -0,0 +1,104 @@
/*-------------------------------------------------------------*/
/*--- Table for doing CRCs ---*/
/*--- crctable.c ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#include "bzlib_private.h"
/*--
I think this is an implementation of the AUTODIN-II,
Ethernet & FDDI 32-bit CRC standard. Vaguely derived
from code by Rob Warnock, in Section 51 of the
comp.compression FAQ.
--*/
UInt32 BZ2_crc32Table[256] = {
/*-- Ugly, innit? --*/
0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
};
/*-------------------------------------------------------------*/
/*--- end crctable.c ---*/
/*-------------------------------------------------------------*/

646
dep/bzip2/decompress.c Normal file
View File

@@ -0,0 +1,646 @@
/*-------------------------------------------------------------*/
/*--- Decompression machinery ---*/
/*--- decompress.c ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#include "bzlib_private.h"
/*---------------------------------------------------*/
static
void makeMaps_d ( DState* s )
{
Int32 i;
s->nInUse = 0;
for (i = 0; i < 256; i++)
if (s->inUse[i]) {
s->seqToUnseq[s->nInUse] = i;
s->nInUse++;
}
}
/*---------------------------------------------------*/
#define RETURN(rrr) \
{ retVal = rrr; goto save_state_and_return; };
#define GET_BITS(lll,vvv,nnn) \
case lll: s->state = lll; \
while (True) { \
if (s->bsLive >= nnn) { \
UInt32 v; \
v = (s->bsBuff >> \
(s->bsLive-nnn)) & ((1 << nnn)-1); \
s->bsLive -= nnn; \
vvv = v; \
break; \
} \
if (s->strm->avail_in == 0) RETURN(BZ_OK); \
s->bsBuff \
= (s->bsBuff << 8) | \
((UInt32) \
(*((UChar*)(s->strm->next_in)))); \
s->bsLive += 8; \
s->strm->next_in++; \
s->strm->avail_in--; \
s->strm->total_in_lo32++; \
if (s->strm->total_in_lo32 == 0) \
s->strm->total_in_hi32++; \
}
#define GET_UCHAR(lll,uuu) \
GET_BITS(lll,uuu,8)
#define GET_BIT(lll,uuu) \
GET_BITS(lll,uuu,1)
/*---------------------------------------------------*/
#define GET_MTF_VAL(label1,label2,lval) \
{ \
if (groupPos == 0) { \
groupNo++; \
if (groupNo >= nSelectors) \
RETURN(BZ_DATA_ERROR); \
groupPos = BZ_G_SIZE; \
gSel = s->selector[groupNo]; \
gMinlen = s->minLens[gSel]; \
gLimit = &(s->limit[gSel][0]); \
gPerm = &(s->perm[gSel][0]); \
gBase = &(s->base[gSel][0]); \
} \
groupPos--; \
zn = gMinlen; \
GET_BITS(label1, zvec, zn); \
while (1) { \
if (zn > 20 /* the longest code */) \
RETURN(BZ_DATA_ERROR); \
if (zvec <= gLimit[zn]) break; \
zn++; \
GET_BIT(label2, zj); \
zvec = (zvec << 1) | zj; \
}; \
if (zvec - gBase[zn] < 0 \
|| zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \
RETURN(BZ_DATA_ERROR); \
lval = gPerm[zvec - gBase[zn]]; \
}
/*---------------------------------------------------*/
Int32 BZ2_decompress ( DState* s )
{
UChar uc;
Int32 retVal;
Int32 minLen, maxLen;
bz_stream* strm = s->strm;
/* stuff that needs to be saved/restored */
Int32 i;
Int32 j;
Int32 t;
Int32 alphaSize;
Int32 nGroups;
Int32 nSelectors;
Int32 EOB;
Int32 groupNo;
Int32 groupPos;
Int32 nextSym;
Int32 nblockMAX;
Int32 nblock;
Int32 es;
Int32 N;
Int32 curr;
Int32 zt;
Int32 zn;
Int32 zvec;
Int32 zj;
Int32 gSel;
Int32 gMinlen;
Int32* gLimit;
Int32* gBase;
Int32* gPerm;
if (s->state == BZ_X_MAGIC_1) {
/*initialise the save area*/
s->save_i = 0;
s->save_j = 0;
s->save_t = 0;
s->save_alphaSize = 0;
s->save_nGroups = 0;
s->save_nSelectors = 0;
s->save_EOB = 0;
s->save_groupNo = 0;
s->save_groupPos = 0;
s->save_nextSym = 0;
s->save_nblockMAX = 0;
s->save_nblock = 0;
s->save_es = 0;
s->save_N = 0;
s->save_curr = 0;
s->save_zt = 0;
s->save_zn = 0;
s->save_zvec = 0;
s->save_zj = 0;
s->save_gSel = 0;
s->save_gMinlen = 0;
s->save_gLimit = NULL;
s->save_gBase = NULL;
s->save_gPerm = NULL;
}
/*restore from the save area*/
i = s->save_i;
j = s->save_j;
t = s->save_t;
alphaSize = s->save_alphaSize;
nGroups = s->save_nGroups;
nSelectors = s->save_nSelectors;
EOB = s->save_EOB;
groupNo = s->save_groupNo;
groupPos = s->save_groupPos;
nextSym = s->save_nextSym;
nblockMAX = s->save_nblockMAX;
nblock = s->save_nblock;
es = s->save_es;
N = s->save_N;
curr = s->save_curr;
zt = s->save_zt;
zn = s->save_zn;
zvec = s->save_zvec;
zj = s->save_zj;
gSel = s->save_gSel;
gMinlen = s->save_gMinlen;
gLimit = s->save_gLimit;
gBase = s->save_gBase;
gPerm = s->save_gPerm;
retVal = BZ_OK;
switch (s->state) {
GET_UCHAR(BZ_X_MAGIC_1, uc);
if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
GET_UCHAR(BZ_X_MAGIC_2, uc);
if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
GET_UCHAR(BZ_X_MAGIC_3, uc)
if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
if (s->blockSize100k < (BZ_HDR_0 + 1) ||
s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
s->blockSize100k -= BZ_HDR_0;
if (s->smallDecompress) {
s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
s->ll4 = BZALLOC(
((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar)
);
if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
} else {
s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
}
GET_UCHAR(BZ_X_BLKHDR_1, uc);
if (uc == 0x17) goto endhdr_2;
if (uc != 0x31) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_2, uc);
if (uc != 0x41) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_3, uc);
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_4, uc);
if (uc != 0x26) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_5, uc);
if (uc != 0x53) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_6, uc);
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
s->currBlockNo++;
if (s->verbosity >= 2)
VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo );
s->storedBlockCRC = 0;
GET_UCHAR(BZ_X_BCRC_1, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_BCRC_2, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_BCRC_3, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_BCRC_4, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
s->origPtr = 0;
GET_UCHAR(BZ_X_ORIGPTR_1, uc);
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
GET_UCHAR(BZ_X_ORIGPTR_2, uc);
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
GET_UCHAR(BZ_X_ORIGPTR_3, uc);
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
if (s->origPtr < 0)
RETURN(BZ_DATA_ERROR);
if (s->origPtr > 10 + 100000*s->blockSize100k)
RETURN(BZ_DATA_ERROR);
/*--- Receive the mapping table ---*/
for (i = 0; i < 16; i++) {
GET_BIT(BZ_X_MAPPING_1, uc);
if (uc == 1)
s->inUse16[i] = True; else
s->inUse16[i] = False;
}
for (i = 0; i < 256; i++) s->inUse[i] = False;
for (i = 0; i < 16; i++)
if (s->inUse16[i])
for (j = 0; j < 16; j++) {
GET_BIT(BZ_X_MAPPING_2, uc);
if (uc == 1) s->inUse[i * 16 + j] = True;
}
makeMaps_d ( s );
if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
alphaSize = s->nInUse+2;
/*--- Now the selectors ---*/
GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
for (i = 0; i < nSelectors; i++) {
j = 0;
while (True) {
GET_BIT(BZ_X_SELECTOR_3, uc);
if (uc == 0) break;
j++;
if (j >= nGroups) RETURN(BZ_DATA_ERROR);
}
s->selectorMtf[i] = j;
}
/*--- Undo the MTF values for the selectors. ---*/
{
UChar pos[BZ_N_GROUPS], tmp, v;
for (v = 0; v < nGroups; v++) pos[v] = v;
for (i = 0; i < nSelectors; i++) {
v = s->selectorMtf[i];
tmp = pos[v];
while (v > 0) { pos[v] = pos[v-1]; v--; }
pos[0] = tmp;
s->selector[i] = tmp;
}
}
/*--- Now the coding tables ---*/
for (t = 0; t < nGroups; t++) {
GET_BITS(BZ_X_CODING_1, curr, 5);
for (i = 0; i < alphaSize; i++) {
while (True) {
if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
GET_BIT(BZ_X_CODING_2, uc);
if (uc == 0) break;
GET_BIT(BZ_X_CODING_3, uc);
if (uc == 0) curr++; else curr--;
}
s->len[t][i] = curr;
}
}
/*--- Create the Huffman decoding tables ---*/
for (t = 0; t < nGroups; t++) {
minLen = 32;
maxLen = 0;
for (i = 0; i < alphaSize; i++) {
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
if (s->len[t][i] < minLen) minLen = s->len[t][i];
}
BZ2_hbCreateDecodeTables (
&(s->limit[t][0]),
&(s->base[t][0]),
&(s->perm[t][0]),
&(s->len[t][0]),
minLen, maxLen, alphaSize
);
s->minLens[t] = minLen;
}
/*--- Now the MTF values ---*/
EOB = s->nInUse+1;
nblockMAX = 100000 * s->blockSize100k;
groupNo = -1;
groupPos = 0;
for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
/*-- MTF init --*/
{
Int32 ii, jj, kk;
kk = MTFA_SIZE-1;
for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
kk--;
}
s->mtfbase[ii] = kk + 1;
}
}
/*-- end MTF init --*/
nblock = 0;
GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
while (True) {
if (nextSym == EOB) break;
if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
es = -1;
N = 1;
do {
/* Check that N doesn't get too big, so that es doesn't
go negative. The maximum value that can be
RUNA/RUNB encoded is equal to the block size (post
the initial RLE), viz, 900k, so bounding N at 2
million should guard against overflow without
rejecting any legitimate inputs. */
if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR);
if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
if (nextSym == BZ_RUNB) es = es + (1+1) * N;
N = N * 2;
GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
}
while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
es++;
uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
s->unzftab[uc] += es;
if (s->smallDecompress)
while (es > 0) {
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
s->ll16[nblock] = (UInt16)uc;
nblock++;
es--;
}
else
while (es > 0) {
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
s->tt[nblock] = (UInt32)uc;
nblock++;
es--;
};
continue;
} else {
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
/*-- uc = MTF ( nextSym-1 ) --*/
{
Int32 ii, jj, kk, pp, lno, off;
UInt32 nn;
nn = (UInt32)(nextSym - 1);
if (nn < MTFL_SIZE) {
/* avoid general-case expense */
pp = s->mtfbase[0];
uc = s->mtfa[pp+nn];
while (nn > 3) {
Int32 z = pp+nn;
s->mtfa[(z) ] = s->mtfa[(z)-1];
s->mtfa[(z)-1] = s->mtfa[(z)-2];
s->mtfa[(z)-2] = s->mtfa[(z)-3];
s->mtfa[(z)-3] = s->mtfa[(z)-4];
nn -= 4;
}
while (nn > 0) {
s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
};
s->mtfa[pp] = uc;
} else {
/* general case */
lno = nn / MTFL_SIZE;
off = nn % MTFL_SIZE;
pp = s->mtfbase[lno] + off;
uc = s->mtfa[pp];
while (pp > s->mtfbase[lno]) {
s->mtfa[pp] = s->mtfa[pp-1]; pp--;
};
s->mtfbase[lno]++;
while (lno > 0) {
s->mtfbase[lno]--;
s->mtfa[s->mtfbase[lno]]
= s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
lno--;
}
s->mtfbase[0]--;
s->mtfa[s->mtfbase[0]] = uc;
if (s->mtfbase[0] == 0) {
kk = MTFA_SIZE-1;
for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
kk--;
}
s->mtfbase[ii] = kk + 1;
}
}
}
}
/*-- end uc = MTF ( nextSym-1 ) --*/
s->unzftab[s->seqToUnseq[uc]]++;
if (s->smallDecompress)
s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]);
nblock++;
GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
continue;
}
}
/* Now we know what nblock is, we can do a better sanity
check on s->origPtr.
*/
if (s->origPtr < 0 || s->origPtr >= nblock)
RETURN(BZ_DATA_ERROR);
/*-- Set up cftab to facilitate generation of T^(-1) --*/
/* Check: unzftab entries in range. */
for (i = 0; i <= 255; i++) {
if (s->unzftab[i] < 0 || s->unzftab[i] > nblock)
RETURN(BZ_DATA_ERROR);
}
/* Actually generate cftab. */
s->cftab[0] = 0;
for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
/* Check: cftab entries in range. */
for (i = 0; i <= 256; i++) {
if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
/* s->cftab[i] can legitimately be == nblock */
RETURN(BZ_DATA_ERROR);
}
}
/* Check: cftab entries non-descending. */
for (i = 1; i <= 256; i++) {
if (s->cftab[i-1] > s->cftab[i]) {
RETURN(BZ_DATA_ERROR);
}
}
s->state_out_len = 0;
s->state_out_ch = 0;
BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
s->state = BZ_X_OUTPUT;
if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
if (s->smallDecompress) {
/*-- Make a copy of cftab, used in generation of T --*/
for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
/*-- compute the T vector --*/
for (i = 0; i < nblock; i++) {
uc = (UChar)(s->ll16[i]);
SET_LL(i, s->cftabCopy[uc]);
s->cftabCopy[uc]++;
}
/*-- Compute T^(-1) by pointer reversal on T --*/
i = s->origPtr;
j = GET_LL(i);
do {
Int32 tmp = GET_LL(j);
SET_LL(j, i);
i = j;
j = tmp;
}
while (i != s->origPtr);
s->tPos = s->origPtr;
s->nblock_used = 0;
if (s->blockRandomised) {
BZ_RAND_INIT_MASK;
BZ_GET_SMALL(s->k0); s->nblock_used++;
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
} else {
BZ_GET_SMALL(s->k0); s->nblock_used++;
}
} else {
/*-- compute the T^(-1) vector --*/
for (i = 0; i < nblock; i++) {
uc = (UChar)(s->tt[i] & 0xff);
s->tt[s->cftab[uc]] |= (i << 8);
s->cftab[uc]++;
}
s->tPos = s->tt[s->origPtr] >> 8;
s->nblock_used = 0;
if (s->blockRandomised) {
BZ_RAND_INIT_MASK;
BZ_GET_FAST(s->k0); s->nblock_used++;
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
} else {
BZ_GET_FAST(s->k0); s->nblock_used++;
}
}
RETURN(BZ_OK);
endhdr_2:
GET_UCHAR(BZ_X_ENDHDR_2, uc);
if (uc != 0x72) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_3, uc);
if (uc != 0x45) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_4, uc);
if (uc != 0x38) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_5, uc);
if (uc != 0x50) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_6, uc);
if (uc != 0x90) RETURN(BZ_DATA_ERROR);
s->storedCombinedCRC = 0;
GET_UCHAR(BZ_X_CCRC_1, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_CCRC_2, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_CCRC_3, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_CCRC_4, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
s->state = BZ_X_IDLE;
RETURN(BZ_STREAM_END);
default: AssertH ( False, 4001 );
}
AssertH ( False, 4002 );
save_state_and_return:
s->save_i = i;
s->save_j = j;
s->save_t = t;
s->save_alphaSize = alphaSize;
s->save_nGroups = nGroups;
s->save_nSelectors = nSelectors;
s->save_EOB = EOB;
s->save_groupNo = groupNo;
s->save_groupPos = groupPos;
s->save_nextSym = nextSym;
s->save_nblockMAX = nblockMAX;
s->save_nblock = nblock;
s->save_es = es;
s->save_N = N;
s->save_curr = curr;
s->save_zt = zt;
s->save_zn = zn;
s->save_zvec = zvec;
s->save_zj = zj;
s->save_gSel = gSel;
s->save_gMinlen = gMinlen;
s->save_gLimit = gLimit;
s->save_gBase = gBase;
s->save_gPerm = gPerm;
return retVal;
}
/*-------------------------------------------------------------*/
/*--- end decompress.c ---*/
/*-------------------------------------------------------------*/

205
dep/bzip2/huffman.c Normal file
View File

@@ -0,0 +1,205 @@
/*-------------------------------------------------------------*/
/*--- Huffman coding low-level stuff ---*/
/*--- huffman.c ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#include "bzlib_private.h"
/*---------------------------------------------------*/
#define WEIGHTOF(zz0) ((zz0) & 0xffffff00)
#define DEPTHOF(zz1) ((zz1) & 0x000000ff)
#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
#define ADDWEIGHTS(zw1,zw2) \
(WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \
(1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
#define UPHEAP(z) \
{ \
Int32 zz, tmp; \
zz = z; tmp = heap[zz]; \
while (weight[tmp] < weight[heap[zz >> 1]]) { \
heap[zz] = heap[zz >> 1]; \
zz >>= 1; \
} \
heap[zz] = tmp; \
}
#define DOWNHEAP(z) \
{ \
Int32 zz, yy, tmp; \
zz = z; tmp = heap[zz]; \
while (True) { \
yy = zz << 1; \
if (yy > nHeap) break; \
if (yy < nHeap && \
weight[heap[yy+1]] < weight[heap[yy]]) \
yy++; \
if (weight[tmp] < weight[heap[yy]]) break; \
heap[zz] = heap[yy]; \
zz = yy; \
} \
heap[zz] = tmp; \
}
/*---------------------------------------------------*/
void BZ2_hbMakeCodeLengths ( UChar *len,
Int32 *freq,
Int32 alphaSize,
Int32 maxLen )
{
/*--
Nodes and heap entries run from 1. Entry 0
for both the heap and nodes is a sentinel.
--*/
Int32 nNodes, nHeap, n1, n2, i, j, k;
Bool tooLong;
Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ];
Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ];
for (i = 0; i < alphaSize; i++)
weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
while (True) {
nNodes = alphaSize;
nHeap = 0;
heap[0] = 0;
weight[0] = 0;
parent[0] = -2;
for (i = 1; i <= alphaSize; i++) {
parent[i] = -1;
nHeap++;
heap[nHeap] = i;
UPHEAP(nHeap);
}
AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
while (nHeap > 1) {
n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
nNodes++;
parent[n1] = parent[n2] = nNodes;
weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
parent[nNodes] = -1;
nHeap++;
heap[nHeap] = nNodes;
UPHEAP(nHeap);
}
AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
tooLong = False;
for (i = 1; i <= alphaSize; i++) {
j = 0;
k = i;
while (parent[k] >= 0) { k = parent[k]; j++; }
len[i-1] = j;
if (j > maxLen) tooLong = True;
}
if (! tooLong) break;
/* 17 Oct 04: keep-going condition for the following loop used
to be 'i < alphaSize', which missed the last element,
theoretically leading to the possibility of the compressor
looping. However, this count-scaling step is only needed if
one of the generated Huffman code words is longer than
maxLen, which up to and including version 1.0.2 was 20 bits,
which is extremely unlikely. In version 1.0.3 maxLen was
changed to 17 bits, which has minimal effect on compression
ratio, but does mean this scaling step is used from time to
time, enough to verify that it works.
This means that bzip2-1.0.3 and later will only produce
Huffman codes with a maximum length of 17 bits. However, in
order to preserve backwards compatibility with bitstreams
produced by versions pre-1.0.3, the decompressor must still
handle lengths of up to 20. */
for (i = 1; i <= alphaSize; i++) {
j = weight[i] >> 8;
j = 1 + (j / 2);
weight[i] = j << 8;
}
}
}
/*---------------------------------------------------*/
void BZ2_hbAssignCodes ( Int32 *code,
UChar *length,
Int32 minLen,
Int32 maxLen,
Int32 alphaSize )
{
Int32 n, vec, i;
vec = 0;
for (n = minLen; n <= maxLen; n++) {
for (i = 0; i < alphaSize; i++)
if (length[i] == n) { code[i] = vec; vec++; };
vec <<= 1;
}
}
/*---------------------------------------------------*/
void BZ2_hbCreateDecodeTables ( Int32 *limit,
Int32 *base,
Int32 *perm,
UChar *length,
Int32 minLen,
Int32 maxLen,
Int32 alphaSize )
{
Int32 pp, i, j, vec;
pp = 0;
for (i = minLen; i <= maxLen; i++)
for (j = 0; j < alphaSize; j++)
if (length[j] == i) { perm[pp] = j; pp++; };
for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
vec = 0;
for (i = minLen; i <= maxLen; i++) {
vec += (base[i+1] - base[i]);
limit[i] = vec-1;
vec <<= 1;
}
for (i = minLen + 1; i <= maxLen; i++)
base[i] = ((limit[i-1] + 1) << 1) - base[i];
}
/*-------------------------------------------------------------*/
/*--- end huffman.c ---*/
/*-------------------------------------------------------------*/

84
dep/bzip2/randtable.c Normal file
View File

@@ -0,0 +1,84 @@
/*-------------------------------------------------------------*/
/*--- Table for randomising repetitive blocks ---*/
/*--- randtable.c ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#include "bzlib_private.h"
/*---------------------------------------------*/
Int32 BZ2_rNums[512] = {
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
936, 638
};
/*-------------------------------------------------------------*/
/*--- end randtable.c ---*/
/*-------------------------------------------------------------*/

31
dep/cds/CMakeLists.txt Normal file
View File

@@ -0,0 +1,31 @@
# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# Gather source files.
GetFilesWithSourceGroups(GLOB_RECURSE CDS_FILES ${CMAKE_CURRENT_SOURCE_DIR} src/*.cpp cds/*.h)
# Define library target.
# add_library(cds ${CDS_FILES})
# Set include dirs for this library (done last, so it's not inherited by subprojects like Tervel, NBDS).
# include_directories(${CMAKE_CURRENT_SOURCE_DIR})
# set_target_properties(cds PROPERTIES LINKER_LANGUAGE CXX)
add_library(cds STATIC ${CDS_FILES})
target_include_directories(cds
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(cds
PROPERTIES
FOLDER
"dep")

521
dep/cds/cds/algo/atomic.h Normal file
View File

@@ -0,0 +1,521 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CXX11_ATOMIC_H
#define CDSLIB_CXX11_ATOMIC_H
#include <cds/details/defs.h>
#include <cds/user_setup/cache_line.h>
namespace cds {
/// C++11 Atomic library support
/** @anchor cds_cxx11_atomic
\p libcds can use the following implementations of the atomics:
- STL \p &lt;atomic&gt;. This is used by default
- \p boost.atomic for boost 1.54 and above. To use it you should define \p CDS_USE_BOOST_ATOMIC for
your compiler invocation, for example, for gcc specify \p -DCDS_USE_BOOST_ATOMIC
in command line
- \p libcds implementation of atomic operation according to C++11 standard as
specified in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf">N3242, p.29</a>.
\p libcds implementation is not the full standard compliant, it provides only C++ part of standard,
for example, \p libcds has no static initialization of the atomic variables and some other C features.
However, that imlementation is enough for the library purposes. Supported architecture: x86, amd64,
ia64 (Itanium) 64bit, 64bit Sparc. To use \p libcds atomic you should define \p CDS_USE_LIBCDS_ATOMIC
in the compiler command line (\p -DCDS_USE_LIBCDS_ATOMIC for gcc/clang).
@note For Clang compiler \p libcds doesn't use native \p libc++ \p &lt;atomic&gt; due some problems.
Instead, \p libcds atomic is used by default, or you can try to use \p boost.atomic.
The library defines \p atomics alias for atomic namespace:
- <tt>namespace atomics = std</tt> for STL
- <tt>namespace atomics = boost</tt> for \p boost.atomic
- <tt>namespace atomics = cds::cxx11_atomic</tt> for library-provided atomic implementation
*/
namespace cxx11_atomic {
}} // namespace cds::cxx11_atomic
//@cond
#if defined(CDS_USE_BOOST_ATOMIC)
// boost atomic
# include <boost/version.hpp>
# if BOOST_VERSION >= 105400
# include <boost/atomic.hpp>
namespace atomics = boost;
# define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace boost {
# define CDS_CXX11_ATOMIC_END_NAMESPACE }
# else
# error "Boost version 1.54 or above is needed for boost.atomic"
# endif
#elif defined(CDS_USE_LIBCDS_ATOMIC)
// libcds atomic
# include <cds/compiler/cxx11_atomic.h>
namespace atomics = cds::cxx11_atomic;
# define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace cds { namespace cxx11_atomic {
# define CDS_CXX11_ATOMIC_END_NAMESPACE }}
#else
// Compiler provided C++11 atomic
# include <atomic>
namespace atomics = std;
# define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace std {
# define CDS_CXX11_ATOMIC_END_NAMESPACE }
#endif
//@endcond
namespace cds {
/// Atomic primitives
/**
This namespace contains useful primitives derived from <tt>std::atomic</tt>.
*/
namespace atomicity {
/// Atomic event counter.
/**
This class is based on <tt>std::atomic_size_t</tt>.
It uses relaxed memory ordering \p memory_order_relaxed and may be used as a statistic counter.
*/
class event_counter
{
//@cond
atomics::atomic_size_t m_counter;
//@endcond
public:
typedef size_t value_type ; ///< Type of counter
public:
// Initializes event counter with zero
event_counter() CDS_NOEXCEPT
: m_counter(size_t(0))
{}
/// Assign operator
/**
Returns \p n.
*/
value_type operator =(
value_type n ///< new value of the counter
) CDS_NOEXCEPT
{
m_counter.exchange( n, atomics::memory_order_relaxed );
return n;
}
/// Addition
/**
Returns new value of the atomic counter.
*/
size_t operator +=(
size_t n ///< addendum
) CDS_NOEXCEPT
{
return m_counter.fetch_add( n, atomics::memory_order_relaxed ) + n;
}
/// Substraction
/**
Returns new value of the atomic counter.
*/
size_t operator -=(
size_t n ///< subtrahend
) CDS_NOEXCEPT
{
return m_counter.fetch_sub( n, atomics::memory_order_relaxed ) - n;
}
/// Get current value of the counter
operator size_t () const CDS_NOEXCEPT
{
return m_counter.load( atomics::memory_order_relaxed );
}
/// Preincrement
size_t operator ++() CDS_NOEXCEPT
{
return m_counter.fetch_add( 1, atomics::memory_order_relaxed ) + 1;
}
/// Postincrement
size_t operator ++(int) CDS_NOEXCEPT
{
return m_counter.fetch_add( 1, atomics::memory_order_relaxed );
}
/// Predecrement
size_t operator --() CDS_NOEXCEPT
{
return m_counter.fetch_sub( 1, atomics::memory_order_relaxed ) - 1;
}
/// Postdecrement
size_t operator --(int) CDS_NOEXCEPT
{
return m_counter.fetch_sub( 1, atomics::memory_order_relaxed );
}
/// Get current value of the counter
size_t get() const CDS_NOEXCEPT
{
return m_counter.load( atomics::memory_order_relaxed );
}
/// Resets the counter to 0
void reset() CDS_NOEXCEPT
{
m_counter.store( 0, atomics::memory_order_release );
}
};
/// Atomic item counter
/**
This class is simplified interface around \p std::atomic_size_t.
The class supports getting current value of the counter and increment/decrement its value.
See also: improved version that eliminates false sharing - \p cache_friendly_item_counter.
*/
class item_counter
{
public:
typedef atomics::atomic_size_t atomic_type; ///< atomic type used
typedef size_t counter_type; ///< Integral item counter type (size_t)
private:
//@cond
atomic_type m_Counter; ///< Atomic item counter
//@endcond
public:
/// Default ctor initializes the counter to zero.
item_counter()
: m_Counter(counter_type(0))
{}
/// Returns current value of the counter
counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
{
return m_Counter.load( order );
}
/// Same as \ref value() with relaxed memory ordering
operator counter_type() const
{
return value();
}
/// Returns underlying atomic interface
atomic_type& getAtomic()
{
return m_Counter;
}
/// Returns underlying atomic interface (const)
const atomic_type& getAtomic() const
{
return m_Counter;
}
/// Increments the counter. Semantics: postincrement
counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
{
return m_Counter.fetch_add( 1, order );
}
/// Increments the counter. Semantics: postincrement
counter_type inc( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
{
return m_Counter.fetch_add( count, order );
}
/// Decrements the counter. Semantics: postdecrement
counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
{
return m_Counter.fetch_sub( 1, order );
}
/// Decrements the counter. Semantics: postdecrement
counter_type dec( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
{
return m_Counter.fetch_sub( count, order );
}
/// Preincrement
counter_type operator ++()
{
return inc() + 1;
}
/// Postincrement
counter_type operator ++(int)
{
return inc();
}
/// Predecrement
counter_type operator --()
{
return dec() - 1;
}
/// Postdecrement
counter_type operator --(int)
{
return dec();
}
/// Increment by \p count
counter_type operator +=( counter_type count )
{
return inc( count ) + count;
}
/// Decrement by \p count
counter_type operator -=( counter_type count )
{
return dec( count ) - count;
}
/// Resets count to 0
void reset(atomics::memory_order order = atomics::memory_order_relaxed)
{
m_Counter.store( 0, order );
}
};
#if CDS_COMPILER == CDS_COMPILER_CLANG
// CLang unhappy: pad1_ and pad2_ - unused private field warning
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-private-field"
#endif
/// Atomic cache-friendly item counter
/**
Atomic item counter with cache-line padding to avoid false sharing.
Adding cache-line padding before and after atomic counter eliminates the contention
in read path of many containers and can notably improve search operations in sets/maps.
*/
class cache_friendly_item_counter
{
public:
typedef atomics::atomic_size_t atomic_type; ///< atomic type used
typedef size_t counter_type; ///< Integral item counter type (size_t)
private:
//@cond
char pad1_[cds::c_nCacheLineSize];
atomic_type m_Counter; ///< Atomic item counter
char pad2_[cds::c_nCacheLineSize - sizeof( atomic_type )];
//@endcond
public:
/// Default ctor initializes the counter to zero.
cache_friendly_item_counter()
: m_Counter(counter_type(0))
{}
/// Returns current value of the counter
counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
{
return m_Counter.load( order );
}
/// Same as \ref value() with relaxed memory ordering
operator counter_type() const
{
return value();
}
/// Returns underlying atomic interface
atomic_type& getAtomic()
{
return m_Counter;
}
/// Returns underlying atomic interface (const)
const atomic_type& getAtomic() const
{
return m_Counter;
}
/// Increments the counter. Semantics: postincrement
counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
{
return m_Counter.fetch_add( 1, order );
}
/// Increments the counter. Semantics: postincrement
counter_type inc( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
{
return m_Counter.fetch_add( count, order );
}
/// Decrements the counter. Semantics: postdecrement
counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
{
return m_Counter.fetch_sub( 1, order );
}
/// Decrements the counter. Semantics: postdecrement
counter_type dec( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
{
return m_Counter.fetch_sub( count, order );
}
/// Preincrement
counter_type operator ++()
{
return inc() + 1;
}
/// Postincrement
counter_type operator ++(int)
{
return inc();
}
/// Predecrement
counter_type operator --()
{
return dec() - 1;
}
/// Postdecrement
counter_type operator --(int)
{
return dec();
}
/// Increment by \p count
counter_type operator +=( counter_type count )
{
return inc( count ) + count;
}
/// Decrement by \p count
counter_type operator -=( counter_type count )
{
return dec( count ) - count;
}
/// Resets count to 0
void reset(atomics::memory_order order = atomics::memory_order_relaxed)
{
m_Counter.store( 0, order );
}
};
#if CDS_COMPILER == CDS_COMPILER_CLANG
# pragma GCC diagnostic pop
#endif
/// Empty item counter
/**
This class may be used instead of \ref item_counter when you do not need full \ref item_counter interface.
All methods of the class is empty and returns 0.
The object of this class should not be used in data structure that behavior significantly depends on item counting
(for example, in many hash map implementation).
*/
class empty_item_counter {
public:
typedef size_t counter_type ; ///< Counter type
public:
/// Returns 0
static counter_type value(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
{
return 0;
}
/// Same as \ref value(), always returns 0.
operator counter_type() const
{
return value();
}
/// Dummy increment. Always returns 0
static counter_type inc(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
{
return 0;
}
/// Dummy increment. Always returns 0
static counter_type inc( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
{
return 0;
}
/// Dummy increment. Always returns 0
static counter_type dec(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
{
return 0;
}
/// Dummy increment. Always returns 0
static counter_type dec( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
{
return 0;
}
/// Dummy pre-increment. Always returns 0
counter_type operator ++() const
{
return 0;
}
/// Dummy post-increment. Always returns 0
counter_type operator ++(int) const
{
return 0;
}
/// Dummy pre-decrement. Always returns 0
counter_type operator --() const
{
return 0;
}
/// Dummy post-decrement. Always returns 0
counter_type operator --(int) const
{
return 0;
}
/// Dummy increment by \p count, always returns 0
counter_type operator +=( counter_type count )
{
CDS_UNUSED( count );
return 0;
}
/// Dummy decrement by \p count, always returns 0
counter_type operator -=( counter_type count )
{
CDS_UNUSED( count );
return 0;
}
/// Dummy function
static void reset(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
{}
};
} // namespace atomicity
} // namespace cds
#endif // #ifndef CDSLIB_CXX11_ATOMIC_H

View File

@@ -0,0 +1,454 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_BACKOFF_STRATEGY_H
#define CDSLIB_BACKOFF_STRATEGY_H
/*
Filename: backoff_strategy.h
Created 2007.03.01 by Maxim Khiszinsky
Description:
Generic back-off strategies
Editions:
2007.03.01 Maxim Khiszinsky Created
2008.10.02 Maxim Khiszinsky Backoff action transfers from contructor to operator() for all backoff schemas
2009.09.10 Maxim Khiszinsky reset() function added
*/
#include <utility> // declval
#include <thread>
#include <chrono>
#include <cds/compiler/backoff.h>
namespace cds {
/// Different backoff schemes
/**
Back-off schema may be used in lock-free algorithms when the algorithm cannot perform some action because a conflict
with the other concurrent operation is encountered. In this case current thread can do another work or can call
processor's performance hint.
The interface of back-off strategy is following:
\code
struct backoff_strategy {
void operator()();
template <typename Predicate> bool operator()( Predicate pr );
void reset();
};
\endcode
\p operator() operator calls back-off strategy's action. It is main part of back-off strategy.
Interruptible back-off <tt>template < typename Predicate > bool operator()( Predicate pr )</tt>
allows to interrupt back-off spinning if \p pr predicate returns \p true.
\p Predicate is a functor with the following interface:
\code
struct predicate {
bool operator()();
};
\endcode
\p reset() function resets internal state of back-off strategy to initial state. It is required for some
back-off strategies, for example, exponential back-off.
*/
namespace backoff {
/// Empty backoff strategy. Do nothing
struct empty {
//@cond
void operator ()() const CDS_NOEXCEPT
{}
template <typename Predicate>
bool operator()(Predicate pr) const CDS_NOEXCEPT_( noexcept(std::declval<Predicate>()()))
{
return pr();
}
static void reset() CDS_NOEXCEPT
{}
//@endcond
};
/// Switch to another thread (yield). Good for thread preemption architecture.
struct yield {
//@cond
void operator ()() const CDS_NOEXCEPT
{
std::this_thread::yield();
}
template <typename Predicate>
bool operator()(Predicate pr) const CDS_NOEXCEPT_( noexcept(std::declval<Predicate>()()))
{
if ( pr())
return true;
operator()();
return false;
}
static void reset() CDS_NOEXCEPT
{}
//@endcond
};
/// Random pause
/**
This back-off strategy calls processor-specific pause hint instruction
if one is available for the processor architecture.
*/
struct pause {
//@cond
void operator ()() const CDS_NOEXCEPT
{
# ifdef CDS_backoff_hint_defined
platform::backoff_hint();
# endif
}
template <typename Predicate>
bool operator()(Predicate pr) const CDS_NOEXCEPT_( noexcept(std::declval<Predicate>()()))
{
if ( pr())
return true;
operator()();
return false;
}
static void reset() CDS_NOEXCEPT
{}
//@endcond
};
/// Processor hint back-off
/**
This back-off schema calls performance hint instruction if it is available for current processor.
Otherwise, it calls \p nop.
*/
struct hint
{
//@cond
void operator ()() const CDS_NOEXCEPT
{
# if defined(CDS_backoff_hint_defined)
platform::backoff_hint();
# elif defined(CDS_backoff_nop_defined)
platform::backoff_nop();
# endif
}
template <typename Predicate>
bool operator()(Predicate pr) const CDS_NOEXCEPT_(noexcept(std::declval<Predicate>()()))
{
if ( pr())
return true;
operator()();
return false;
}
static void reset() CDS_NOEXCEPT
{}
//@endcond
};
/// Exponential back-off
/**
This back-off strategy is composite. It consists of \p SpinBkoff and \p YieldBkoff
back-off strategy. In first, the strategy tries to apply repeatedly \p SpinBkoff
(spinning phase) until internal counter of failed attempts reaches its maximum
spinning value. Then, the strategy transits to high-contention phase
where it applies \p YieldBkoff until \p reset() is called.
On each spinning iteration the internal spinning counter is doubled.
Choosing the best value for maximum spinning bound is platform and task specific.
In this implementation, the default values for maximum and minimum spinning is statically
declared so you can set its value globally for your platform.
The third template argument, \p Tag, is used to separate implementation. For
example, you may define two \p exponential back-offs that is the best for your task A and B:
\code
#include <cds/algo/backoff_strategy.h>
namespace bkoff = cds::backoff;
struct tagA ; // tag to select task A implementation
struct tagB ; // tag to select task B implementation
// // define your back-off specialization
typedef bkoff::exponential<bkoff::hint, bkoff::yield, tagA> expBackOffA;
typedef bkoff::exponential<bkoff::hint, bkoff::yield, tagB> expBackOffB;
// // set up the best bounds for task A
expBackOffA::s_nExpMin = 32;
expBackOffA::s_nExpMax = 1024;
// // set up the best bounds for task B
expBackOffB::s_nExpMin = 2;
expBackOffB::s_nExpMax = 512;
\endcode
Another way of solving this problem is subclassing \p exponential back-off class:
\code
#include <cds/algo/backoff_strategy.h>
namespace bkoff = cds::backoff;
typedef bkoff::exponential<bkoff::hint, bkoff::yield> base_bkoff;
class expBackOffA: public base_bkoff
{
public:
expBackOffA()
: base_bkoff( 32, 1024 )
{}
};
class expBackOffB: public base_bkoff
{
public:
expBackOffB()
: base_bkoff( 2, 512 )
{}
};
\endcode
*/
template <typename SpinBkoff, typename YieldBkoff, typename Tag=void>
class exponential
{
public:
typedef SpinBkoff spin_backoff ; ///< spin back-off strategy
typedef YieldBkoff yield_backoff ; ///< yield back-off strategy
typedef Tag impl_tag ; ///< implementation separation tag
static size_t s_nExpMin ; ///< Default minimum spinning bound (16)
static size_t s_nExpMax ; ///< Default maximum spinning bound (16384)
protected:
size_t m_nExpCur ; ///< Current spinning
size_t m_nExpMin ; ///< Minimum spinning bound
size_t m_nExpMax ; ///< Maximum spinning bound
spin_backoff m_bkSpin ; ///< Spinning (fast-path) phase back-off strategy
yield_backoff m_bkYield ; ///< Yield phase back-off strategy
public:
/// Initializes m_nExpMin and m_nExpMax from default s_nExpMin and s_nExpMax respectively
exponential() CDS_NOEXCEPT
: m_nExpMin( s_nExpMin )
, m_nExpMax( s_nExpMax )
{
m_nExpCur = m_nExpMin;
}
/// Explicitly defined bounds of spinning
/**
The \p libcds library never calls this ctor.
*/
exponential(
size_t nExpMin, ///< Minimum spinning
size_t nExpMax ///< Maximum spinning
) CDS_NOEXCEPT
: m_nExpMin( nExpMin )
, m_nExpMax( nExpMax )
{
m_nExpCur = m_nExpMin;
}
//@cond
void operator ()() CDS_NOEXCEPT_(noexcept(std::declval<spin_backoff>()()) && noexcept(std::declval<yield_backoff>()()))
{
if ( m_nExpCur <= m_nExpMax ) {
for ( size_t n = 0; n < m_nExpCur; ++n )
m_bkSpin();
m_nExpCur *= 2;
}
else
m_bkYield();
}
template <typename Predicate>
bool operator()( Predicate pr ) CDS_NOEXCEPT_( noexcept(std::declval<Predicate>()()) && noexcept(std::declval<spin_backoff>()()) && noexcept(std::declval<yield_backoff>()()))
{
if ( m_nExpCur <= m_nExpMax ) {
for ( size_t n = 0; n < m_nExpCur; ++n ) {
if ( m_bkSpin(pr))
return true;
}
m_nExpCur *= 2;
}
else
return m_bkYield(pr);
return false;
}
void reset() CDS_NOEXCEPT_( noexcept( std::declval<spin_backoff>().reset()) && noexcept( std::declval<yield_backoff>().reset()))
{
m_nExpCur = m_nExpMin;
m_bkSpin.reset();
m_bkYield.reset();
}
//@endcond
};
//@cond
template <typename SpinBkoff, typename YieldBkoff, typename Tag>
size_t exponential<SpinBkoff, YieldBkoff, Tag>::s_nExpMin = 16;
template <typename SpinBkoff, typename YieldBkoff, typename Tag>
size_t exponential<SpinBkoff, YieldBkoff, Tag>::s_nExpMax = 16 * 1024;
//@endcond
/// Delay back-off strategy
/**
Template arguments:
- \p Duration - duration type, default is \p std::chrono::milliseconds
- \p Tag - a selector tag
Choosing the best value for th timeout is platform and task specific.
In this implementation, the default values for timeout is statically
declared so you can set its value globally for your platform.
The second template argument, \p Tag, is used to separate implementation. For
example, you may define two \p delay back-offs for 5 and 10 ms timeout:
\code
#include <cds/algo/backoff_strategy.h>
namespace bkoff = cds::backoff;
struct ms5 ; // tag to select 5ms
struct ms10 ; // tag to select 10ms
// // define your back-off specialization
typedef bkoff::delay<std::chrono::milliseconds, ms5> delay5;
typedef bkoff::delay<std::chrono::milliseconds, ms10> delay10;
// // set up the timeouts
delay5::s_nTimeout = 5;
delay10::s_nTimeout = 10;
\endcode
Another way of solving this problem is subclassing \p delay back-off class:
\code
#include <cds/algo/backoff_strategy.h>
namespace bkoff = cds::backoff;
typedef bkoff::delay<> delay_bkoff;
class delay5: public delay_bkoff {
public:
delay5(): delay_bkoff( 5 ) {}
};
class delay10: public delay_bkoff {
public:
delay10(): delay_bkoff( 10 ) {}
};
\endcode
*/
template <class Duration = std::chrono::milliseconds, typename Tag=void >
class delay
{
public:
typedef Duration duration_type; ///< Duration type (default \p std::chrono::milliseconds)
static unsigned int s_nTimeout; ///< default timeout, =5
protected:
///@cond
unsigned int const m_nTimeout;
///@endcond
public:
/// Default ctor takes the timeout from s_nTimeout
delay() CDS_NOEXCEPT
: m_nTimeout( s_nTimeout )
{}
/// Initializes timeout from \p nTimeout
CDS_CONSTEXPR explicit delay( unsigned int nTimeout ) CDS_NOEXCEPT
: m_nTimeout( nTimeout )
{}
//@cond
void operator()() const
{
std::this_thread::sleep_for( duration_type( m_nTimeout ));
}
template <typename Predicate>
bool operator()(Predicate pr) const
{
for ( unsigned int i = 0; i < m_nTimeout; i += 2 ) {
if ( pr())
return true;
std::this_thread::sleep_for( duration_type( 2 ));
}
return false;
}
static void reset() CDS_NOEXCEPT
{}
//@endcond
};
//@cond
template <class Duration, typename Tag>
unsigned int delay<Duration, Tag>::s_nTimeout = 5;
//@endcond
/// Delay back-off strategy, template version
/**
This is a template version of backoff::delay class.
Template parameter \p Timeout sets a delay timeout.
The declaration <tt>cds::backoff::delay_of< 5 > bkoff</tt> is equal for
<tt>cds::backoff::delay<> bkoff(5)</tt>.
*/
template <unsigned int Timeout, class Duration = std::chrono::milliseconds >
class delay_of: public delay<Duration>
{
//@cond
typedef delay<Duration> base_class;
public:
delay_of() CDS_NOEXCEPT
: base_class( Timeout )
{}
//@endcond
};
/// Default backoff strategy
typedef exponential<hint, yield> Default;
/// Default back-off strategy for lock primitives
typedef exponential<hint, yield> LockDefault;
} // namespace backoff
} // namespace cds
#endif // #ifndef CDSLIB_BACKOFF_STRATEGY_H

43
dep/cds/cds/algo/base.h Normal file
View File

@@ -0,0 +1,43 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_ALGO_BASE_H
#define CDSLIB_ALGO_BASE_H
#include <cds/details/defs.h>
namespace cds {
/// Different approaches and techniques for supporting high-concurrent data structure
namespace algo {}
} // namespace cds
#endif // #ifndef CDSLIB_ALGO_BASE_H

View File

@@ -0,0 +1,184 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_ALGO_BIT_REVERSAL_H
#define CDSLIB_ALGO_BIT_REVERSAL_H
#include <cds/algo/base.h>
// Source: http://stackoverflow.com/questions/746171/best-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c
namespace cds { namespace algo {
/// Bit reversal algorithms
namespace bit_reversal {
/// SWAR algorithm (source: http://aggregate.org/MAGIC/#Bit%20Reversal)
struct swar {
/// 32bit
uint32_t operator()( uint32_t x ) const
{
x = ( ( ( x & 0xaaaaaaaa ) >> 1 ) | ( ( x & 0x55555555 ) << 1 ) );
x = ( ( ( x & 0xcccccccc ) >> 2 ) | ( ( x & 0x33333333 ) << 2 ) );
x = ( ( ( x & 0xf0f0f0f0 ) >> 4 ) | ( ( x & 0x0f0f0f0f ) << 4 ) );
x = ( ( ( x & 0xff00ff00 ) >> 8 ) | ( ( x & 0x00ff00ff ) << 8 ) );
return( ( x >> 16 ) | ( x << 16 ) );
}
/// 64bit
uint64_t operator()( uint64_t x ) const
{
return ( static_cast<uint64_t>( operator()( static_cast<uint32_t>( x ) ) ) << 32 ) // low 32bit
| ( static_cast<uint64_t>( operator()( static_cast<uint32_t>( x >> 32 ) ) ) ); // high 32bit
}
};
/// Lookup table algorithm
struct lookup {
/// 32bit
uint32_t operator()( uint32_t x ) const
{
static uint8_t const table[] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
static_assert( sizeof( table ) / sizeof( table[0] ) == 256, "Table size mismatch" );
return ( static_cast<uint32_t>( table[x & 0xff] ) << 24 ) |
( static_cast<uint32_t>( table[( x >> 8 ) & 0xff] ) << 16 ) |
( static_cast<uint32_t>( table[( x >> 16 ) & 0xff] ) << 8 ) |
( static_cast<uint32_t>( table[( x >> 24 ) & 0xff] ) );
}
/// 64bit
uint64_t operator()( uint64_t x ) const
{
return ( static_cast<uint64_t>( operator()( static_cast<uint32_t>( x ) ) ) << 32 ) |
static_cast<uint64_t>( operator()( static_cast<uint32_t>( x >> 32 ) ) );
}
};
/// Mul-Div algorithm for 32bit architectire
/// Mul-Div algorithm
struct muldiv {
//@cond
static uint8_t muldiv32_byte( uint8_t b )
{
return static_cast<uint8_t>( ( ( b * 0x0802LU & 0x22110LU ) | ( b * 0x8020LU & 0x88440LU ) ) * 0x10101LU >> 16 );
}
static uint8_t muldiv64_byte( uint8_t b )
{
return static_cast<uint8_t>( ( b * 0x0202020202ULL & 0x010884422010ULL ) % 1023 );
}
// for 32bit architecture
static uint32_t muldiv32( uint32_t x )
{
return static_cast<uint32_t>( muldiv32_byte( static_cast<uint8_t>( x >> 24 ) ) )
| ( static_cast<uint32_t>( muldiv32_byte( static_cast<uint8_t>( x >> 16 ) ) ) << 8 )
| ( static_cast<uint32_t>( muldiv32_byte( static_cast<uint8_t>( x >> 8 ) ) ) << 16 )
| ( static_cast<uint32_t>( muldiv32_byte( static_cast<uint8_t>( x ) ) ) << 24 );
}
static uint64_t muldiv32( uint64_t x )
{
return static_cast<uint64_t>( muldiv32_byte( static_cast<uint8_t>( x >> 56 ) ) )
| ( static_cast<uint64_t>( muldiv32_byte( static_cast<uint8_t>( x >> 48 ) ) ) << 8 )
| ( static_cast<uint64_t>( muldiv32_byte( static_cast<uint8_t>( x >> 40 ) ) ) << 16 )
| ( static_cast<uint64_t>( muldiv32_byte( static_cast<uint8_t>( x >> 32 ) ) ) << 24 )
| ( static_cast<uint64_t>( muldiv32_byte( static_cast<uint8_t>( x >> 24 ) ) ) << 32 )
| ( static_cast<uint64_t>( muldiv32_byte( static_cast<uint8_t>( x >> 16 ) ) ) << 40 )
| ( static_cast<uint64_t>( muldiv32_byte( static_cast<uint8_t>( x >> 8 ) ) ) << 48 )
| ( static_cast<uint64_t>( muldiv32_byte( static_cast<uint8_t>( x ) ) ) << 56 );
}
/// for 64bit architectire
static uint32_t muldiv64( uint32_t x )
{
return static_cast<uint32_t>( muldiv64_byte( static_cast<uint8_t>( x >> 24 ) ) )
| ( static_cast<uint32_t>( muldiv64_byte( static_cast<uint8_t>( x >> 16 ) ) ) << 8 )
| ( static_cast<uint32_t>( muldiv64_byte( static_cast<uint8_t>( x >> 8 ) ) ) << 16 )
| ( static_cast<uint32_t>( muldiv64_byte( static_cast<uint8_t>( x ) ) ) << 24 );
}
static uint64_t muldiv64( uint64_t x )
{
return static_cast<uint64_t>( muldiv64_byte( static_cast<uint8_t>( x >> 56 ) ) )
| ( static_cast<uint64_t>( muldiv64_byte( static_cast<uint8_t>( x >> 48 ) ) ) << 8 )
| ( static_cast<uint64_t>( muldiv64_byte( static_cast<uint8_t>( x >> 40 ) ) ) << 16 )
| ( static_cast<uint64_t>( muldiv64_byte( static_cast<uint8_t>( x >> 32 ) ) ) << 24 )
| ( static_cast<uint64_t>( muldiv64_byte( static_cast<uint8_t>( x >> 24 ) ) ) << 32 )
| ( static_cast<uint64_t>( muldiv64_byte( static_cast<uint8_t>( x >> 16 ) ) ) << 40 )
| ( static_cast<uint64_t>( muldiv64_byte( static_cast<uint8_t>( x >> 8 ) ) ) << 48 )
| ( static_cast<uint64_t>( muldiv64_byte( static_cast<uint8_t>( x ) ) ) << 56 );
}
//@endcond
/// 32bit
uint32_t operator()( uint32_t x ) const
{
# if CDS_BUILD_BITS == 32
return muldiv32( x );
# else
return muldiv64( x );
# endif
}
/// 64bit
uint64_t operator()( uint64_t x ) const
{
# if CDS_BUILD_BITS == 32
return muldiv32( x );
# else
return muldiv64( x );
# endif
}
};
} // namespace bit_reversal
}} // namespace cds::algo
#endif // #ifndef CDSLIB_ALGO_BIT_REVERSAL_H

168
dep/cds/cds/algo/bitop.h Normal file
View File

@@ -0,0 +1,168 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_BITOP_H
#define CDSLIB_BITOP_H
/*
Different bit algorithms:
LSB get least significant bit number
MSB get most significant bit number
bswap swap byte order of word
RBO reverse bit order of word
Editions:
2007.10.08 Maxim.Khiszinsky Created
*/
#include <cds/details/defs.h>
#include <cds/compiler/bitop.h>
namespace cds {
/// Bit operations
namespace bitop {
///@cond none
namespace details {
template <int> struct BitOps;
// 32-bit bit ops
template <> struct BitOps<4> {
typedef uint32_t TUInt;
static int MSB( TUInt x ) { return bitop::platform::msb32( x ); }
static int LSB( TUInt x ) { return bitop::platform::lsb32( x ); }
static int MSBnz( TUInt x ) { return bitop::platform::msb32nz( x ); }
static int LSBnz( TUInt x ) { return bitop::platform::lsb32nz( x ); }
static int SBC( TUInt x ) { return bitop::platform::sbc32( x ) ; }
static int ZBC( TUInt x ) { return bitop::platform::zbc32( x ) ; }
static TUInt RBO( TUInt x ) { return bitop::platform::rbo32( x ); }
static bool complement( TUInt& x, int nBit ) { return bitop::platform::complement32( &x, nBit ); }
static TUInt RandXorShift(TUInt x) { return bitop::platform::RandXorShift32(x); }
};
// 64-bit bit ops
template <> struct BitOps<8> {
typedef uint64_t TUInt;
static int MSB( TUInt x ) { return bitop::platform::msb64( x ); }
static int LSB( TUInt x ) { return bitop::platform::lsb64( x ); }
static int MSBnz( TUInt x ) { return bitop::platform::msb64nz( x ); }
static int LSBnz( TUInt x ) { return bitop::platform::lsb64nz( x ); }
static int SBC( TUInt x ) { return bitop::platform::sbc64( x ) ; }
static int ZBC( TUInt x ) { return bitop::platform::zbc64( x ) ; }
static TUInt RBO( TUInt x ) { return bitop::platform::rbo64( x ); }
static bool complement( TUInt& x, int nBit ) { return bitop::platform::complement64( &x, nBit ); }
static TUInt RandXorShift(TUInt x) { return bitop::platform::RandXorShift64(x); }
};
} // namespace details
//@endcond
/// Get least significant bit (LSB) number (1..32/64), 0 if nArg == 0
template <typename T>
static inline int LSB( T nArg )
{
return details::BitOps< sizeof(T) >::LSB( (typename details::BitOps<sizeof(T)>::TUInt) nArg );
}
/// Get least significant bit (LSB) number (0..31/63)
/**
Precondition: nArg != 0
*/
template <typename T>
static inline int LSBnz( T nArg )
{
assert( nArg != 0 );
return details::BitOps< sizeof(T) >::LSBnz( (typename details::BitOps<sizeof(T)>::TUInt) nArg );
}
/// Get most significant bit (MSB) number (1..32/64), 0 if nArg == 0
template <typename T>
static inline int MSB( T nArg )
{
return details::BitOps< sizeof(T) >::MSB( (typename details::BitOps<sizeof(T)>::TUInt) nArg );
}
/// Get most significant bit (MSB) number (0..31/63)
/**
Precondition: nArg != 0
*/
template <typename T>
static inline int MSBnz( T nArg )
{
assert( nArg != 0 );
return details::BitOps< sizeof(T) >::MSBnz( (typename details::BitOps<sizeof(T)>::TUInt) nArg );
}
/// Get non-zero bit count of a word
template <typename T>
static inline int SBC( T nArg )
{
return details::BitOps< sizeof(T) >::SBC( (typename details::BitOps<sizeof(T)>::TUInt) nArg );
}
/// Get zero bit count of a word
template <typename T>
static inline int ZBC( T nArg )
{
return details::BitOps< sizeof(T) >::ZBC( (typename details::BitOps<sizeof(T)>::TUInt) nArg );
}
/// Reverse bit order of \p nArg
template <typename T>
static inline T RBO( T nArg )
{
return (T) details::BitOps< sizeof(T) >::RBO( (typename details::BitOps<sizeof(T)>::TUInt) nArg );
}
/// Complement bit \p nBit in \p nArg
template <typename T>
static inline bool complement( T& nArg, int nBit )
{
return details::BitOps< sizeof(T) >::complement( reinterpret_cast< typename details::BitOps<sizeof(T)>::TUInt& >( nArg ), nBit );
}
/// Simple random number generator
template <typename T>
static inline T RandXorShift( T x)
{
return (T) details::BitOps< sizeof(T) >::RandXorShift(x);
}
} // namespace bitop
} //namespace cds
#endif // #ifndef CDSLIB_BITOP_H

View File

@@ -0,0 +1,86 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_ALGO_ELIMINATION_H
#define CDSLIB_ALGO_ELIMINATION_H
#include <cds/algo/elimination_tls.h>
#include <cds/algo/elimination_opt.h>
#include <cds/algo/atomic.h>
#include <cds/threading/model.h>
namespace cds { namespace algo {
/// Elimination technique
/** @anchor cds_elimination_description
Elimination technique allows highly distributed coupling and execution of operations with reverse
semantics like the pushes and pops on a stack. If a push followed by a pop are performed
on a stack, the data structure's state does not change (similarly for a pop followed by a push).
This means that if one can cause pairs of pushes and pops to meet and pair up in
separate locations, the threads can exchange values without having to touch a centralized structure
since they have anyhow "eliminated" each other's effect on it. Elimination can be implemented
by using a collision array in which threads pick random locations in order to try and collide.
Pairs of threads that "collide" in some location run through a synchronization protocol,
and all such disjoint collisions can be performed in parallel. If a thread has not met another
in the selected location or if it met a thread with an operation that cannot be eliminated
(such as two push operations), an alternative scheme must be used.
*/
namespace elimination {
/// Base class describing an operation for eliminating
/**
This class contains some debugng info.
Actual operation descriptor depends on real container and its interface.
*/
struct operation_desc
{
record * pOwner; ///< Owner of the descriptor
};
/// Acquires elimination record for the current thread
template <typename OperationDesc>
static inline record * init_record( OperationDesc& op )
{
record& rec = cds::threading::elimination_record();
assert( rec.is_free());
op.pOwner = &rec;
rec.pOp = static_cast<operation_desc *>( &op );
return &rec;
}
/// Releases elimination record for the current thread
static inline void clear_record()
{
cds::threading::elimination_record().pOp = nullptr;
}
} // namespace elimination
}} // namespace cds::algo
#endif // CDSLIB_ALGO_ELIMINATION_H

View File

@@ -0,0 +1,65 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_ALGO_ELIMINATION_OPT_H
#define CDSLIB_ALGO_ELIMINATION_OPT_H
#include <cds/details/defs.h>
namespace cds { namespace opt {
/// Enable \ref cds_elimination_description "elimination back-off" for the container
template <bool Enable>
struct enable_elimination {
//@cond
template <class Base> struct pack: public Base
{
static CDS_CONSTEXPR const bool enable_elimination = Enable;
};
//@endcond
};
/// \ref cds_elimination_description "Elimination back-off strategy" option setter
/**
Back-off strategy for elimination.
Usually, elimination back-off strategy is \p cds::backoff::delay.
*/
template <typename Type>
struct elimination_backoff {
//@cond
template <class Base> struct pack: public Base
{
typedef Type elimination_backoff;
};
//@endcond
};
}} // namespace cds::opt
#endif // #ifndef CDSLIB_ALGO_ELIMINATION_OPT_H

View File

@@ -0,0 +1,62 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_ALGO_ELIMINATION_TLS_H
#define CDSLIB_ALGO_ELIMINATION_TLS_H
#include <cds/algo/base.h>
namespace cds { namespace algo { namespace elimination {
// Forwards
struct operation_desc;
/// Per-thread elimination record
/** @headerfile cds/algo/elimination.h
*/
struct record
{
operation_desc * pOp ; ///< Operation descriptor
/// Initialization
record()
: pOp( nullptr )
{}
/// Checks if the record is free
bool is_free() const
{
return pOp == nullptr;
}
};
}}} // cds::algo::elimination
#endif // #ifndef CDSLIB_ALGO_ELIMINATION_TLS_H

View File

@@ -0,0 +1,36 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_ALGO_FLAT_COMBINING_H
#define CDSLIB_ALGO_FLAT_COMBINING_H
#include <cds/algo/flat_combining/kernel.h>
#endif // #ifndef CDSLIB_ALGO_FLAT_COMBINING_H

View File

@@ -0,0 +1,92 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_ALGO_FLAT_COMBINING_DEFS_H
#define CDSLIB_ALGO_FLAT_COMBINING_DEFS_H
#include <cds/algo/atomic.h>
namespace cds { namespace algo { namespace flat_combining {
/// Special values of \p publication_record::nRequest
enum request_value
{
req_EmptyRecord, ///< Publication record is empty
req_Response, ///< Operation is done
req_Operation ///< First operation id for derived classes
};
/// \p publication_record state
enum record_state {
inactive, ///< Record is inactive
active, ///< Record is active
removed ///< Record should be removed
};
/// Record of publication list
/**
Each data structure based on flat combining contains a class derived from \p %publication_record
*/
struct publication_record {
atomics::atomic<unsigned int> nRequest; ///< Request field (depends on data structure)
atomics::atomic<unsigned int> nState; ///< Record state: inactive, active, removed
atomics::atomic<unsigned int> nAge; ///< Age of the record
atomics::atomic<publication_record *> pNext; ///< Next record in active publication list
atomics::atomic<publication_record *> pNextAllocated; ///< Next record in allocated publication list
/// Initializes publication record
publication_record()
: nRequest( req_EmptyRecord )
, nAge( 0 )
, pNext( nullptr )
, pNextAllocated( nullptr )
{
nState.store( inactive, atomics::memory_order_release );
}
/// Returns the value of \p nRequest field
unsigned int op( atomics::memory_order mo = atomics::memory_order_relaxed ) const
{
return nRequest.load( mo );
}
/// Checks if the operation is done
bool is_done() const
{
return nRequest.load( atomics::memory_order_relaxed ) == req_Response;
}
};
}}} // namespace cds::algo::flat_combining
#endif // CDSLIB_ALGO_FLAT_COMBINING_DEFS_H

View File

@@ -0,0 +1,900 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_ALGO_FLAT_COMBINING_KERNEL_H
#define CDSLIB_ALGO_FLAT_COMBINING_KERNEL_H
#include <cds/algo/flat_combining/defs.h>
#include <cds/algo/flat_combining/wait_strategy.h>
#include <cds/sync/spinlock.h>
#include <cds/details/allocator.h>
#include <cds/opt/options.h>
#include <cds/algo/int_algo.h>
namespace cds { namespace algo {
/// @defgroup cds_flat_combining_intrusive Intrusive flat combining containers
/// @defgroup cds_flat_combining_container Non-intrusive flat combining containers
/// Flat combining
/**
@anchor cds_flat_combining_description
Flat combining (FC) technique is invented by Hendler, Incze, Shavit and Tzafrir in their paper
[2010] <i>"Flat Combining and the Synchronization-Parallelism Tradeoff"</i>.
The technique converts a sequential data structure to its concurrent implementation.
A few structures are added to the sequential implementation: a <i>global lock</i>,
a <i>count</i> of the number of combining passes, and a pointer to the <i>head</i>
of a <i>publication list</i>. The publication list is a list of thread-local records
of a size proportional to the number of threads that are concurrently accessing the shared object.
Each thread \p t accessing the structure to perform an invocation of some method \p f()
on the shared object executes the following sequence of steps:
<ol>
<li>Write the invocation opcode and parameters (if any) of the method \p f() to be applied
sequentially to the shared object in the <i>request</i> field of your thread local publication
record (there is no need to use a load-store memory barrier). The <i>request</i> field will later
be used to receive the response. If your thread local publication record is marked as active
continue to step 2, otherwise continue to step 5.</li>
<li>Check if the global lock is taken. If so (another thread is an active combiner), spin on the <i>request</i>
field waiting for a response to the invocation (one can add a yield at this point to allow other threads
on the same core to run). Once in a while while spinning check if the lock is still taken and that your
record is active (you may use any of \p wait_strategy instead of spinning). If your record is inactive proceed to step 5.
Once the response is available, reset the request field to null and return the response.</li>
<li>If the lock is not taken, attempt to acquire it and become a combiner. If you fail,
return to spinning in step 2.</li>
<li>Otherwise, you hold the lock and are a combiner.
<ul>
<li>Increment the combining pass count by one.</li>
<li>Execute a \p fc_apply() by traversing the publication list from the head,
combining all non-null method call invocations, setting the <i>age</i> of each of these records
to the current <i>count</i>, applying the combined method calls to the structure D, and returning
responses to all the invocations. This traversal is guaranteed to be wait-free.</li>
<li>If the <i>count</i> is such that a cleanup needs to be performed, traverse the publication
list from the <i>head</i>. Starting from the second item (we always leave the item pointed to
by the head in the list), remove from the publication list all records whose <i>age</i> is
much smaller than the current <i>count</i>. This is done by removing the node and marking it
as inactive.</li>
<li>Release the lock.</li>
</ul>
<li>If you have no thread local publication record allocate one, marked as active. If you already
have one marked as inactive, mark it as active. Execute a store-load memory barrier. Proceed to insert
the record into the list with a successful CAS to the <i>head</i>. Then proceed to step 1.</li>
</ol>
As the test results show, the flat combining technique is suitable for non-intrusive containers
like stack, queue, deque. For intrusive concurrent containers the flat combining demonstrates
less impressive results.
\ref cds_flat_combining_container "List of FC-based containers" in libcds.
\ref cds_flat_combining_intrusive "List of intrusive FC-based containers" in libcds.
*/
namespace flat_combining {
/// Flat combining internal statistics
template <typename Counter = cds::atomicity::event_counter >
struct stat
{
typedef Counter counter_type; ///< Event counter type
counter_type m_nOperationCount ; ///< How many operations have been performed
counter_type m_nCombiningCount ; ///< Combining call count
counter_type m_nCompactPublicationList; ///< Count of publication list compacting
counter_type m_nDeactivatePubRecord; ///< How many publication records were deactivated during compacting
counter_type m_nActivatePubRecord; ///< Count of publication record activating
counter_type m_nPubRecordCreated ; ///< Count of created publication records
counter_type m_nPubRecordDeleted ; ///< Count of deleted publication records
counter_type m_nPassiveWaitCall; ///< Count of passive waiting call (\p kernel::wait_for_combining())
counter_type m_nPassiveWaitIteration;///< Count of iteration inside passive waiting
counter_type m_nPassiveWaitWakeup; ///< Count of forcing wake-up of passive wait cycle
counter_type m_nInvokeExclusive; ///< Count of call \p kernel::invoke_exclusive()
counter_type m_nWakeupByNotifying; ///< How many times the passive thread be waked up by a notification
counter_type m_nPassiveToCombiner; ///< How many times the passive thread becomes the combiner
/// Returns current combining factor
/**
Combining factor is how many operations perform in one combine pass:
<tt>combining_factor := m_nOperationCount / m_nCombiningCount</tt>
*/
double combining_factor() const
{
return m_nCombiningCount.get() ? double( m_nOperationCount.get()) / m_nCombiningCount.get() : 0.0;
}
//@cond
void onOperation() { ++m_nOperationCount; }
void onCombining() { ++m_nCombiningCount; }
void onCompactPublicationList() { ++m_nCompactPublicationList; }
void onDeactivatePubRecord() { ++m_nDeactivatePubRecord; }
void onActivatePubRecord() { ++m_nActivatePubRecord; }
void onCreatePubRecord() { ++m_nPubRecordCreated; }
void onDeletePubRecord() { ++m_nPubRecordDeleted; }
void onPassiveWait() { ++m_nPassiveWaitCall; }
void onPassiveWaitIteration() { ++m_nPassiveWaitIteration; }
void onPassiveWaitWakeup() { ++m_nPassiveWaitWakeup; }
void onInvokeExclusive() { ++m_nInvokeExclusive; }
void onWakeupByNotifying() { ++m_nWakeupByNotifying; }
void onPassiveToCombiner() { ++m_nPassiveToCombiner; }
//@endcond
};
/// Flat combining dummy internal statistics
struct empty_stat
{
//@cond
void onOperation() const {}
void onCombining() const {}
void onCompactPublicationList() const {}
void onDeactivatePubRecord() const {}
void onActivatePubRecord() const {}
void onCreatePubRecord() const {}
void onDeletePubRecord() const {}
void onPassiveWait() const {}
void onPassiveWaitIteration() const {}
void onPassiveWaitWakeup() const {}
void onInvokeExclusive() const {}
void onWakeupByNotifying() const {}
void onPassiveToCombiner() const {}
//@endcond
};
/// Type traits of \ref kernel class
/**
You can define different type traits for \ref kernel
by specifying your struct based on \p %traits
or by using \ref make_traits metafunction.
*/
struct traits
{
typedef cds::sync::spin lock_type; ///< Lock type
typedef cds::algo::flat_combining::wait_strategy::backoff< cds::backoff::delay_of<2>> wait_strategy; ///< Wait strategy
typedef CDS_DEFAULT_ALLOCATOR allocator; ///< Allocator used for TLS data (allocating \p publication_record derivatives)
typedef empty_stat stat; ///< Internal statistics
typedef opt::v::relaxed_ordering memory_model; ///< /// C++ memory ordering model
};
/// Metafunction converting option list to traits
/**
\p Options are:
- \p opt::lock_type - mutex type, default is \p cds::sync::spin
- \p opt::wait_strategy - wait strategy, see \p wait_strategy namespace, default is \p wait_strategy::backoff.
- \p opt::allocator - allocator type, default is \ref CDS_DEFAULT_ALLOCATOR
- \p opt::stat - internal statistics, possible type: \ref stat, \ref empty_stat (the default)
- \p opt::memory_model - C++ memory ordering model.
List of all available memory ordering see \p opt::memory_model.
Default is \p cds::opt::v::relaxed_ordering
*/
template <typename... Options>
struct make_traits {
# ifdef CDS_DOXYGEN_INVOKED
typedef implementation_defined type ; ///< Metafunction result
# else
typedef typename cds::opt::make_options<
typename cds::opt::find_type_traits< traits, Options... >::type
,Options...
>::type type;
# endif
};
/// The kernel of flat combining
/**
Template parameters:
- \p PublicationRecord - a type derived from \ref publication_record
- \p Traits - a type traits of flat combining, default is \p flat_combining::traits.
\ref make_traits metafunction can be used to create type traits
The kernel object should be a member of a container class. The container cooperates with flat combining
kernel object. There are two ways to interact with the kernel:
- One-by-one processing the active records of the publication list. This mode provides by \p combine() function:
the container acquires its publication record by \p acquire_record(), fills its fields and calls
\p combine() function of its kernel object. If the current thread becomes a combiner, the kernel
calls \p fc_apply() function of the container for each active non-empty record. Then, the container
should release its publication record by \p release_record(). Only one pass through the publication
list is possible.
- Batch processing - \p batch_combine() function. It this mode the container obtains access
to entire publication list. This mode allows the container to perform an elimination, for example,
the stack can collide \p push() and \p pop() requests. The sequence of invocations is the following:
the container acquires its publication record by \p acquire_record(), fills its field and call
\p batch_combine() function of its kernel object. If the current thread becomes a combiner,
the kernel calls \p fc_process() function of the container passing two iterators pointing to
the begin and the end of publication list (see \ref iterator class). The iterators allow
multiple pass through active records of publication list. For each processed record the container
should call \p operation_done() function. On the end, the container should release
its record by \p release_record().
*/
template <
typename PublicationRecord
,typename Traits = traits
>
class kernel
{
public:
typedef Traits traits; ///< Type traits
typedef typename traits::lock_type global_lock_type; ///< Global lock type
typedef typename traits::wait_strategy wait_strategy; ///< Wait strategy type
typedef typename traits::allocator allocator; ///< Allocator type (used for allocating publication_record_type data)
typedef typename traits::stat stat; ///< Internal statistics
typedef typename traits::memory_model memory_model; ///< C++ memory model
typedef typename wait_strategy::template make_publication_record<PublicationRecord>::type publication_record_type; ///< Publication record type
protected:
//@cond
typedef cds::details::Allocator< publication_record_type, allocator > cxx11_allocator; ///< internal helper cds::details::Allocator
typedef std::lock_guard<global_lock_type> lock_guard;
//@endcond
protected:
atomics::atomic<unsigned int> m_nCount; ///< Total count of combining passes. Used as an age.
publication_record_type* m_pHead; ///< Head of active publication list
publication_record_type* m_pAllocatedHead; ///< Head of allocated publication list
boost::thread_specific_ptr< publication_record_type > m_pThreadRec; ///< Thread-local publication record
mutable global_lock_type m_Mutex; ///< Global mutex
mutable stat m_Stat; ///< Internal statistics
unsigned int const m_nCompactFactor; ///< Publication list compacting factor (the list will be compacted through \p %m_nCompactFactor combining passes)
unsigned int const m_nCombinePassCount; ///< Number of combining passes
wait_strategy m_waitStrategy; ///< Wait strategy
public:
/// Initializes the object
/**
Compact factor = 1024
Combiner pass count = 8
*/
kernel()
: kernel( 1024, 8 )
{}
/// Initializes the object
kernel(
unsigned int nCompactFactor ///< Publication list compacting factor (the list will be compacted through \p nCompactFactor combining passes)
,unsigned int nCombinePassCount ///< Number of combining passes for combiner thread
)
: m_nCount(0)
, m_pHead( nullptr )
, m_pAllocatedHead( nullptr )
, m_pThreadRec( tls_cleanup )
, m_nCompactFactor( (unsigned int)( cds::beans::ceil2( nCompactFactor ) - 1 )) // binary mask
, m_nCombinePassCount( nCombinePassCount )
{
assert( m_pThreadRec.get() == nullptr );
publication_record_type* pRec = cxx11_allocator().New();
m_pAllocatedHead =
m_pHead = pRec;
m_pThreadRec.reset( pRec );
m_Stat.onCreatePubRecord();
}
/// Destroys the object and all publication records
~kernel()
{
m_pThreadRec.reset(); // calls tls_cleanup()
// delete all publication records
for ( publication_record* p = m_pAllocatedHead; p; ) {
publication_record * pRec = p;
p = p->pNextAllocated.load( memory_model::memory_order_relaxed );
free_publication_record( static_cast<publication_record_type *>( pRec ));
}
}
/// Gets publication list record for the current thread
/**
If there is no publication record for the current thread
the function allocates it.
*/
publication_record_type * acquire_record()
{
publication_record_type * pRec = m_pThreadRec.get();
if ( !pRec ) {
// Allocate new publication record
pRec = cxx11_allocator().New();
m_pThreadRec.reset( pRec );
m_Stat.onCreatePubRecord();
// Insert in allocated list
assert( m_pAllocatedHead != nullptr );
publication_record* p = m_pAllocatedHead->pNextAllocated.load( memory_model::memory_order_relaxed );
do {
pRec->pNextAllocated.store( p, memory_model::memory_order_release );
} while ( !m_pAllocatedHead->pNextAllocated.compare_exchange_weak( p, pRec, memory_model::memory_order_release, atomics::memory_order_acquire ));
publish( pRec );
}
else if ( pRec->nState.load( memory_model::memory_order_acquire ) != active )
publish( pRec );
assert( pRec->op() == req_EmptyRecord );
return pRec;
}
/// Marks publication record for the current thread as empty
void release_record( publication_record_type * pRec )
{
assert( pRec->is_done());
pRec->nRequest.store( req_EmptyRecord, memory_model::memory_order_release );
}
/// Trying to execute operation \p nOpId
/**
\p pRec is the publication record acquiring by \ref acquire_record earlier.
\p owner is a container that is owner of flat combining kernel object.
As a result the current thread can become a combiner or can wait for
another combiner performs \p pRec operation.
If the thread becomes a combiner, the kernel calls \p owner.fc_apply
for each active non-empty publication record.
*/
template <class Container>
void combine( unsigned int nOpId, publication_record_type * pRec, Container& owner )
{
assert( nOpId >= req_Operation );
assert( pRec );
pRec->nRequest.store( nOpId, memory_model::memory_order_release );
m_Stat.onOperation();
try_combining( owner, pRec );
}
/// Trying to execute operation \p nOpId in batch-combine mode
/**
\p pRec is the publication record acquiring by \p acquire_record() earlier.
\p owner is a container that owns flat combining kernel object.
As a result the current thread can become a combiner or can wait for
another combiner performs \p pRec operation.
If the thread becomes a combiner, the kernel calls \p owner.fc_process()
giving the container the full access over publication list. This function
is useful for an elimination technique if the container supports any kind of
that. The container can perform multiple pass through publication list.
\p owner.fc_process() has two arguments - forward iterators on begin and end of
publication list, see \ref iterator class. For each processed record the container
should call \p operation_done() function to mark the record as processed.
On the end of \p %batch_combine the \p combine() function is called
to process rest of publication records.
*/
template <class Container>
void batch_combine( unsigned int nOpId, publication_record_type* pRec, Container& owner )
{
assert( nOpId >= req_Operation );
assert( pRec );
pRec->nRequest.store( nOpId, memory_model::memory_order_release );
m_Stat.onOperation();
try_batch_combining( owner, pRec );
}
/// Invokes \p Func in exclusive mode
/**
Some operation in flat combining containers should be called in exclusive mode
i.e the current thread should become the combiner to process the operation.
The typical example is \p empty() function.
\p %invoke_exclusive() allows do that: the current thread becomes the combiner,
invokes \p f exclusively but unlike a typical usage the thread does not process any pending request.
Instead, after end of \p f call the current thread wakes up a pending thread if any.
*/
template <typename Func>
void invoke_exclusive( Func f )
{
{
lock_guard l( m_Mutex );
f();
}
m_waitStrategy.wakeup( *this );
m_Stat.onInvokeExclusive();
}
/// Marks \p rec as executed
/**
This function should be called by container if \p batch_combine() mode is used.
For usual combining (see \p combine()) this function is excess.
*/
void operation_done( publication_record& rec )
{
rec.nRequest.store( req_Response, memory_model::memory_order_release );
m_waitStrategy.notify( *this, static_cast<publication_record_type&>( rec ));
}
/// Internal statistics
stat const& statistics() const
{
return m_Stat;
}
//@cond
// For container classes based on flat combining
stat& internal_statistics() const
{
return m_Stat;
}
//@endcond
/// Returns the compact factor
unsigned int compact_factor() const
{
return m_nCompactFactor + 1;
}
/// Returns number of combining passes for combiner thread
unsigned int combine_pass_count() const
{
return m_nCombinePassCount;
}
public:
/// Publication list iterator
/**
Iterators are intended for batch processing by container's
\p fc_process function.
The iterator allows iterate through active publication list.
*/
class iterator
{
//@cond
friend class kernel;
publication_record_type * m_pRec;
//@endcond
protected:
//@cond
iterator( publication_record_type * pRec )
: m_pRec( pRec )
{
skip_inactive();
}
void skip_inactive()
{
while ( m_pRec && (m_pRec->nState.load( memory_model::memory_order_acquire ) != active
|| m_pRec->op( memory_model::memory_order_relaxed) < req_Operation ))
{
m_pRec = static_cast<publication_record_type*>(m_pRec->pNext.load( memory_model::memory_order_acquire ));
}
}
//@endcond
public:
/// Initializes an empty iterator object
iterator()
: m_pRec( nullptr )
{}
/// Copy ctor
iterator( iterator const& src )
: m_pRec( src.m_pRec )
{}
/// Pre-increment
iterator& operator++()
{
assert( m_pRec );
m_pRec = static_cast<publication_record_type *>( m_pRec->pNext.load( memory_model::memory_order_acquire ));
skip_inactive();
return *this;
}
/// Post-increment
iterator operator++(int)
{
assert( m_pRec );
iterator it(*this);
++(*this);
return it;
}
/// Dereference operator, can return \p nullptr
publication_record_type* operator ->()
{
return m_pRec;
}
/// Dereference operator, the iterator should not be an end iterator
publication_record_type& operator*()
{
assert( m_pRec );
return *m_pRec;
}
/// Iterator equality
friend bool operator==( iterator it1, iterator it2 )
{
return it1.m_pRec == it2.m_pRec;
}
/// Iterator inequality
friend bool operator!=( iterator it1, iterator it2 )
{
return !( it1 == it2 );
}
};
/// Returns an iterator to the first active publication record
iterator begin() { return iterator(m_pHead); }
/// Returns an iterator to the end of publication list. Should not be dereferenced.
iterator end() { return iterator(); }
public:
/// Gets current value of \p rec.nRequest
/**
This function is intended for invoking from a wait strategy
*/
int get_operation( publication_record& rec )
{
return rec.op( memory_model::memory_order_acquire );
}
/// Wakes up any waiting thread
/**
This function is intended for invoking from a wait strategy
*/
void wakeup_any()
{
publication_record* pRec = m_pHead;
while ( pRec ) {
if ( pRec->nState.load( memory_model::memory_order_acquire ) == active
&& pRec->op( memory_model::memory_order_acquire ) >= req_Operation )
{
m_waitStrategy.notify( *this, static_cast<publication_record_type&>( *pRec ));
break;
}
pRec = pRec->pNext.load( memory_model::memory_order_acquire );
}
}
private:
//@cond
static void tls_cleanup( publication_record_type* pRec )
{
// Thread done
// pRec that is TLS data should be excluded from publication list
pRec->nState.store( removed, memory_model::memory_order_release );
}
void free_publication_record( publication_record_type* pRec )
{
cxx11_allocator().Delete( pRec );
m_Stat.onDeletePubRecord();
}
void publish( publication_record_type* pRec )
{
assert( pRec->nState.load( memory_model::memory_order_relaxed ) == inactive );
pRec->nAge.store( m_nCount.load(memory_model::memory_order_relaxed), memory_model::memory_order_relaxed );
pRec->nState.store( active, memory_model::memory_order_relaxed );
// Insert record to publication list
if ( m_pHead != static_cast<publication_record *>(pRec)) {
publication_record * p = m_pHead->pNext.load( memory_model::memory_order_relaxed );
if ( p != static_cast<publication_record *>( pRec )) {
do {
pRec->pNext.store( p, memory_model::memory_order_release );
// Failed CAS changes p
} while ( !m_pHead->pNext.compare_exchange_weak( p, static_cast<publication_record *>(pRec),
memory_model::memory_order_release, atomics::memory_order_acquire ));
m_Stat.onActivatePubRecord();
}
}
}
void republish( publication_record_type* pRec )
{
if ( pRec->nState.load( memory_model::memory_order_relaxed ) != active ) {
// The record has been excluded from publication list. Reinsert it
publish( pRec );
}
}
template <class Container>
void try_combining( Container& owner, publication_record_type* pRec )
{
if ( m_Mutex.try_lock()) {
// The thread becomes a combiner
lock_guard l( m_Mutex, std::adopt_lock_t());
// The record pRec can be excluded from publication list. Re-publish it
republish( pRec );
combining( owner );
assert( pRec->op( memory_model::memory_order_relaxed ) == req_Response );
}
else {
// There is another combiner, wait while it executes our request
if ( !wait_for_combining( pRec )) {
// The thread becomes a combiner
lock_guard l( m_Mutex, std::adopt_lock_t());
// The record pRec can be excluded from publication list. Re-publish it
republish( pRec );
combining( owner );
assert( pRec->op( memory_model::memory_order_relaxed ) == req_Response );
}
}
}
template <class Container>
void try_batch_combining( Container& owner, publication_record_type * pRec )
{
if ( m_Mutex.try_lock()) {
// The thread becomes a combiner
lock_guard l( m_Mutex, std::adopt_lock_t());
// The record pRec can be excluded from publication list. Re-publish it
republish( pRec );
batch_combining( owner );
assert( pRec->op( memory_model::memory_order_relaxed ) == req_Response );
}
else {
// There is another combiner, wait while it executes our request
if ( !wait_for_combining( pRec )) {
// The thread becomes a combiner
lock_guard l( m_Mutex, std::adopt_lock_t());
// The record pRec can be excluded from publication list. Re-publish it
republish( pRec );
batch_combining( owner );
assert( pRec->op( memory_model::memory_order_relaxed ) == req_Response );
}
}
}
template <class Container>
void combining( Container& owner )
{
// The thread is a combiner
assert( !m_Mutex.try_lock());
unsigned int const nCurAge = m_nCount.fetch_add( 1, memory_model::memory_order_relaxed ) + 1;
unsigned int nEmptyPassCount = 0;
unsigned int nUsefulPassCount = 0;
for ( unsigned int nPass = 0; nPass < m_nCombinePassCount; ++nPass ) {
if ( combining_pass( owner, nCurAge ))
++nUsefulPassCount;
else if ( ++nEmptyPassCount > nUsefulPassCount )
break;
}
m_Stat.onCombining();
if ( ( nCurAge & m_nCompactFactor ) == 0 )
compact_list( nCurAge );
}
template <class Container>
bool combining_pass( Container& owner, unsigned int nCurAge )
{
publication_record* p = m_pHead;
bool bOpDone = false;
while ( p ) {
switch ( p->nState.load( memory_model::memory_order_acquire )) {
case active:
if ( p->op( memory_model::memory_order_acquire ) >= req_Operation ) {
p->nAge.store( nCurAge, memory_model::memory_order_relaxed );
owner.fc_apply( static_cast<publication_record_type*>( p ));
operation_done( *p );
bOpDone = true;
}
break;
case inactive:
// Only m_pHead can be inactive in the publication list
assert( p == m_pHead );
break;
case removed:
// Such record will be removed on compacting phase
break;
default:
/// ??? That is impossible
assert( false );
}
p = p->pNext.load( memory_model::memory_order_acquire );
}
return bOpDone;
}
template <class Container>
void batch_combining( Container& owner )
{
// The thread is a combiner
assert( !m_Mutex.try_lock());
unsigned int const nCurAge = m_nCount.fetch_add( 1, memory_model::memory_order_relaxed ) + 1;
for ( unsigned int nPass = 0; nPass < m_nCombinePassCount; ++nPass )
owner.fc_process( begin(), end());
combining_pass( owner, nCurAge );
m_Stat.onCombining();
if ( ( nCurAge & m_nCompactFactor ) == 0 )
compact_list( nCurAge );
}
bool wait_for_combining( publication_record_type* pRec )
{
m_waitStrategy.prepare( *pRec );
m_Stat.onPassiveWait();
while ( pRec->op( memory_model::memory_order_acquire ) != req_Response ) {
// The record can be excluded from publication list. Reinsert it
republish( pRec );
m_Stat.onPassiveWaitIteration();
// Wait while operation processing
if ( m_waitStrategy.wait( *this, *pRec ))
m_Stat.onWakeupByNotifying();
if ( m_Mutex.try_lock()) {
if ( pRec->op( memory_model::memory_order_acquire ) == req_Response ) {
// Operation is done
m_Mutex.unlock();
// Wake up a pending threads
m_waitStrategy.wakeup( *this );
m_Stat.onPassiveWaitWakeup();
break;
}
// The thread becomes a combiner
m_Stat.onPassiveToCombiner();
return false;
}
}
return true;
}
void compact_list( unsigned int nCurAge )
{
// Compacts publication list
// This function is called only by combiner thread
try_again:
publication_record * pPrev = m_pHead;
for ( publication_record * p = pPrev->pNext.load( memory_model::memory_order_acquire ); p; ) {
switch ( p->nState.load( memory_model::memory_order_relaxed )) {
case active:
if ( p->nAge.load( memory_model::memory_order_relaxed ) + m_nCompactFactor < nCurAge )
{
publication_record * pNext = p->pNext.load( memory_model::memory_order_relaxed );
if ( pPrev->pNext.compare_exchange_strong( p, pNext,
memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
{
p->nState.store( inactive, memory_model::memory_order_release );
p = pNext;
m_Stat.onDeactivatePubRecord();
continue;
}
}
break;
case removed:
publication_record * pNext = p->pNext.load( memory_model::memory_order_acquire );
if ( cds_likely( pPrev->pNext.compare_exchange_strong( p, pNext, memory_model::memory_order_acquire, atomics::memory_order_relaxed ))) {
p = pNext;
continue;
}
else {
// CAS can be failed only in beginning of list
assert( pPrev == m_pHead );
goto try_again;
}
}
pPrev = p;
p = p->pNext.load( memory_model::memory_order_acquire );
}
// Iterate over allocated list to find removed records
pPrev = m_pAllocatedHead;
for ( publication_record * p = pPrev->pNextAllocated.load( memory_model::memory_order_acquire ); p; ) {
if ( p->nState.load( memory_model::memory_order_relaxed ) == removed ) {
publication_record * pNext = p->pNextAllocated.load( memory_model::memory_order_relaxed );
if ( pPrev->pNextAllocated.compare_exchange_strong( p, pNext, memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
free_publication_record( static_cast<publication_record_type *>( p ));
p = pNext;
continue;
}
}
pPrev = p;
p = p->pNextAllocated.load( memory_model::memory_order_relaxed );
}
m_Stat.onCompactPublicationList();
}
//@endcond
};
//@cond
class container
{
public:
template <typename PubRecord>
void fc_apply( PubRecord * )
{
assert( false );
}
template <typename Iterator>
void fc_process( Iterator, Iterator )
{
assert( false );
}
};
//@endcond
} // namespace flat_combining
}} // namespace cds::algo
/*
CppMem model (http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/)
// Combiner thread - slave (waiting) thread
int main() {
atomic_int y = 0; // pRec->op
int x = 0; // pRec->data
{{{
{ // slave thread (not combiner)
// Op data
x = 1;
// Annotate request (op)
y.store(1, release);
// Wait while request done
y.load(acquire).readsvalue(2);
// Read result
r2=x;
}
|||
{ // Combiner thread
// Read request (op)
r1=y.load(acquire).readsvalue(1);
// Execute request - change request data
x = 2;
// store "request processed" flag (pRec->op := req_Response)
y.store(2, release);
}
}}};
return 0;
}
*/
#endif // #ifndef CDSLIB_ALGO_FLAT_COMBINING_KERNEL_H

View File

@@ -0,0 +1,442 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_ALGO_FLAT_COMBINING_WAIT_STRATEGY_H
#define CDSLIB_ALGO_FLAT_COMBINING_WAIT_STRATEGY_H
#include <cds/algo/flat_combining/defs.h>
#include <cds/algo/backoff_strategy.h>
#include <mutex>
#include <condition_variable>
#include <boost/thread/tss.hpp> // thread_specific_ptr
namespace cds { namespace opt {
/// Wait strategy option for \p flat_combining::kernel
template <typename Strategy>
struct wait_strategy {
//@cond
template <typename Base> struct pack: public Base
{
typedef Strategy wait_strategy;
};
//@endcond
};
}} // namespace cds::opt
namespace cds { namespace algo { namespace flat_combining {
/// Wait strategies for \p flat_combining technique
/**
Wait strategy specifies how a thread waits until its request is performed by the combiner.
See \p wait_strategy::empty wait strategy to explain the interface.
*/
namespace wait_strategy {
/// Empty wait strategy
/**
Empty wait strategy is just spinning on request field.
All functions are empty.
*/
struct empty
{
/// Metafunction for defining a publication record for flat combining technique
/**
Any wait strategy may expand the publication record for storing
its own private data.
\p PublicationRecord is the type specified by \p flat_combining::kernel.
- If the strategy has no thread-private data, it should typedef \p PublicationRecord
as a return \p type of metafunction.
- Otherwise, if the strategy wants to store anything in thread-local data,
it should expand \p PublicationRecord, for example:
\code
template <typename PublicationRecord>
struct make_publication_record {
struct type: public PublicationRecord
{
int strategy_data;
};
};
\endcode
*/
template <typename PublicationRecord>
struct make_publication_record {
typedef PublicationRecord type; ///< Metafunction result
};
/// Prepares the strategy
/**
This function is called before enter to waiting cycle.
Some strategies need to prepare its thread-local data in \p rec.
\p PublicationRecord is thread's publication record of type \p make_publication_record::type
*/
template <typename PublicationRecord>
void prepare( PublicationRecord& rec )
{
CDS_UNUSED( rec );
}
/// Waits for the combiner
/**
The thread calls this function to wait for the combiner process
the request.
The function returns \p true if the thread was waked up by the combiner,
otherwise it should return \p false.
\p FCKernel is a \p flat_combining::kernel object,
\p PublicationRecord is thread's publication record of type \p make_publication_record::type
*/
template <typename FCKernel, typename PublicationRecord>
bool wait( FCKernel& fc, PublicationRecord& rec )
{
CDS_UNUSED( fc );
CDS_UNUSED( rec );
return false;
}
/// Wakes up the thread
/**
The combiner calls \p %notify() when it has been processed the request.
\p FCKernel is a \p flat_combining::kernel object,
\p PublicationRecord is thread's publication record of type \p make_publication_record::type
*/
template <typename FCKernel, typename PublicationRecord>
void notify( FCKernel& fc, PublicationRecord& rec )
{
CDS_UNUSED( fc );
CDS_UNUSED( rec );
}
/// Moves control to other thread
/**
This function is called when the thread becomes the combiner
but the request of the thread is already processed.
The strategy may call \p fc.wakeup_any() instructs the kernel
to wake up any pending thread.
\p FCKernel is a \p flat_combining::kernel object,
*/
template <typename FCKernel>
void wakeup( FCKernel& fc )
{
CDS_UNUSED( fc );
}
};
/// Back-off wait strategy
/**
Template argument \p Backoff specifies back-off strategy, default is cds::backoff::delay_of<2>
*/
template <typename BackOff = cds::backoff::delay_of<2>>
struct backoff
{
typedef BackOff back_off; ///< Back-off strategy
/// Incorporates back-off strategy into publication record
template <typename PublicationRecord>
struct make_publication_record
{
//@cond
struct type: public PublicationRecord
{
back_off bkoff;
};
//@endcond
};
/// Resets back-off strategy in \p rec
template <typename PublicationRecord>
void prepare( PublicationRecord& rec )
{
rec.bkoff.reset();
}
/// Calls back-off strategy
template <typename FCKernel, typename PublicationRecord>
bool wait( FCKernel& /*fc*/, PublicationRecord& rec )
{
rec.bkoff();
return false;
}
/// Does nothing
template <typename FCKernel, typename PublicationRecord>
void notify( FCKernel& /*fc*/, PublicationRecord& /*rec*/ )
{}
/// Does nothing
template <typename FCKernel>
void wakeup( FCKernel& )
{}
};
/// Wait strategy based on the single mutex and the condition variable
/**
The strategy shares the mutex and conditional variable for all thread.
Template parameter \p Milliseconds specifies waiting duration;
the minimal value is 1.
*/
template <int Milliseconds = 2>
class single_mutex_single_condvar
{
//@cond
std::mutex m_mutex;
std::condition_variable m_condvar;
bool m_wakeup;
typedef std::unique_lock< std::mutex > unique_lock;
//@endcond
public:
enum {
c_nWaitMilliseconds = Milliseconds < 1 ? 1 : Milliseconds ///< Waiting duration
};
/// Empty metafunction
template <typename PublicationRecord>
struct make_publication_record {
typedef PublicationRecord type; ///< publication record type
};
/// Default ctor
single_mutex_single_condvar()
: m_wakeup( false )
{}
/// Does nothing
template <typename PublicationRecord>
void prepare( PublicationRecord& /*rec*/ )
{}
/// Sleeps on condition variable waiting for notification from combiner
template <typename FCKernel, typename PublicationRecord>
bool wait( FCKernel& fc, PublicationRecord& rec )
{
if ( fc.get_operation( rec ) >= req_Operation ) {
unique_lock lock( m_mutex );
if ( fc.get_operation( rec ) >= req_Operation ) {
if ( m_wakeup ) {
m_wakeup = false;
return true;
}
bool ret = m_condvar.wait_for( lock, std::chrono::milliseconds( c_nWaitMilliseconds ) ) == std::cv_status::no_timeout;
m_wakeup = false;
return ret;
}
}
return false;
}
/// Calls condition variable function \p notify_all()
template <typename FCKernel, typename PublicationRecord>
void notify( FCKernel& fc, PublicationRecord& /*rec*/ )
{
wakeup( fc );
}
/// Calls condition variable function \p notify_all()
template <typename FCKernel>
void wakeup( FCKernel& /*fc*/ )
{
unique_lock lock( m_mutex );
m_wakeup = true;
m_condvar.notify_all();
}
};
/// Wait strategy based on the single mutex and thread-local condition variables
/**
The strategy shares the mutex, but each thread has its own conditional variable
Template parameter \p Milliseconds specifies waiting duration;
the minimal value is 1.
*/
template <int Milliseconds = 2>
class single_mutex_multi_condvar
{
//@cond
std::mutex m_mutex;
bool m_wakeup;
typedef std::unique_lock< std::mutex > unique_lock;
//@endcond
public:
enum {
c_nWaitMilliseconds = Milliseconds < 1 ? 1 : Milliseconds ///< Waiting duration
};
/// Incorporates a condition variable into \p PublicationRecord
template <typename PublicationRecord>
struct make_publication_record {
/// Metafunction result
struct type: public PublicationRecord
{
//@cond
std::condition_variable m_condvar;
//@endcond
};
};
/// Default ctor
single_mutex_multi_condvar()
: m_wakeup( false )
{}
/// Does nothing
template <typename PublicationRecord>
void prepare( PublicationRecord& /*rec*/ )
{}
/// Sleeps on condition variable waiting for notification from combiner
template <typename FCKernel, typename PublicationRecord>
bool wait( FCKernel& fc, PublicationRecord& rec )
{
if ( fc.get_operation( rec ) >= req_Operation ) {
unique_lock lock( m_mutex );
if ( fc.get_operation( rec ) >= req_Operation ) {
if ( m_wakeup ) {
m_wakeup = false;
return true;
}
bool ret = rec.m_condvar.wait_for( lock, std::chrono::milliseconds( c_nWaitMilliseconds ) ) == std::cv_status::no_timeout;
m_wakeup = false;
return ret;
}
}
return false;
}
/// Calls condition variable function \p notify_one()
template <typename FCKernel, typename PublicationRecord>
void notify( FCKernel& /*fc*/, PublicationRecord& rec )
{
unique_lock lock( m_mutex );
m_wakeup = true;
rec.m_condvar.notify_one();
}
/// Calls \p fc.wakeup_any() to wake up any pending thread
template <typename FCKernel>
void wakeup( FCKernel& fc )
{
fc.wakeup_any();
}
};
/// Wait strategy where each thread has a mutex and a condition variable
/**
Template parameter \p Milliseconds specifies waiting duration;
the minimal value is 1.
*/
template <int Milliseconds = 2>
class multi_mutex_multi_condvar
{
//@cond
typedef std::unique_lock< std::mutex > unique_lock;
//@endcond
public:
enum {
c_nWaitMilliseconds = Milliseconds < 1 ? 1 : Milliseconds ///< Waiting duration
};
/// Incorporates a condition variable and a mutex into \p PublicationRecord
template <typename PublicationRecord>
struct make_publication_record {
/// Metafunction result
struct type: public PublicationRecord
{
//@cond
std::mutex m_mutex;
std::condition_variable m_condvar;
bool m_wakeup;
type()
: m_wakeup( false )
{}
//@endcond
};
};
/// Does nothing
template <typename PublicationRecord>
void prepare( PublicationRecord& /*rec*/ )
{}
/// Sleeps on condition variable waiting for notification from combiner
template <typename FCKernel, typename PublicationRecord>
bool wait( FCKernel& fc, PublicationRecord& rec )
{
if ( fc.get_operation( rec ) >= req_Operation ) {
unique_lock lock( rec.m_mutex );
if ( fc.get_operation( rec ) >= req_Operation ) {
if ( rec.m_wakeup ) {
rec.m_wakeup = false;
return true;
}
bool ret = rec.m_condvar.wait_for( lock, std::chrono::milliseconds( c_nWaitMilliseconds ) ) == std::cv_status::no_timeout;
rec.m_wakeup = false;
return ret;
}
}
return false;
}
/// Calls condition variable function \p notify_one()
template <typename FCKernel, typename PublicationRecord>
void notify( FCKernel& /*fc*/, PublicationRecord& rec )
{
unique_lock lock( rec.m_mutex );
rec.m_wakeup = true;
rec.m_condvar.notify_one();
}
/// Calls \p fc.wakeup_any() to wake up any pending thread
template <typename FCKernel>
void wakeup( FCKernel& fc )
{
fc.wakeup_any();
}
};
} // namespace wait_strategy
}}} // namespace cds::algo::flat_combining
#endif //CDSLIB_ALGO_FLAT_COMBINING_WAIT_STRATEGY_H

172
dep/cds/cds/algo/int_algo.h Normal file
View File

@@ -0,0 +1,172 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INT_ALGO_H
#define CDSLIB_INT_ALGO_H
#include <cds/algo/bitop.h>
namespace cds { namespace beans {
/// Returns largest previous integer for <tt>log2( n )</tt>
static inline size_t log2floor( size_t n )
{
return n ? cds::bitop::MSBnz( n ) : 0;
}
/// Returns smallest following integer for <tt>log2( n )</tt>
static inline size_t log2ceil( size_t n )
{
size_t i = log2floor( n );
return ( size_t( 1 ) << i ) < n ? i + 1 : i;
}
/// Returns largest previous power of 2 for \p n
/**
Examples:
\code
floor2(0) == 1 // !!!
floor2(1) == 1
floor2(2) == 2
floor2(3) == 2
floor2(4) == 4
floor2(15) == 8
floor2(16) == 16
floor2(17) == 16
\endcode
*/
static inline size_t floor2( size_t n )
{
return size_t(1) << log2floor( n );
}
/// Returns smallest following power of 2 for \p n
/**
Examples:
\code
ceil2(0) == 1 // !!!
ceil2(1) == 1
ceil2(2) == 2
ceil2(3) == 4
ceil2(4) == 4
ceil2(15) == 16
ceil2(16) == 16
ceil2(17) == 32
\endcode
*/
static inline size_t ceil2( size_t n )
{
return size_t(1) << log2ceil( n );
}
/// Checks if \p n is power of 2
CDS_CONSTEXPR static inline bool is_power2( size_t n ) CDS_NOEXCEPT
{
return (n & (n - 1)) == 0 && n;
}
/// Returns binary logarithm of \p n if \p n is power of two, otherwise returns 0
static inline size_t log2( size_t n )
{
return is_power2(n) ? log2floor(n) : 0;
}
#if CDS_BUILD_BITS == 32
//@cond
// 64bit specializations
/// Returns largest previous integer for <tt>log2( n )</tt>
static inline uint64_t log2floor( uint64_t n )
{
return n ? cds::bitop::MSBnz( n ) : 0;
}
/// Returns smallest following integer for <tt>log2( n )</tt>
static inline uint64_t log2ceil( uint64_t n )
{
uint64_t i = log2floor( n );
return (uint64_t( 1 ) << i) < n ? i + 1 : i;
}
/// Returns largest previous power of 2 for \p n
/**
Examples:
\code
floor2(0) == 1 // !!!
floor2(1) == 1
floor2(2) == 2
floor2(3) == 2
floor2(4) == 4
floor2(15) == 8
floor2(16) == 16
floor2(17) == 16
\endcode
*/
static inline uint64_t floor2( uint64_t n )
{
return uint64_t( 1 ) << log2floor( n );
}
/// Returns smallest following power of 2 for \p n
/**
Examples:
\code
ceil2(0) == 1 // !!!
ceil2(1) == 1
ceil2(2) == 2
ceil2(3) == 4
ceil2(4) == 4
ceil2(15) == 16
ceil2(16) == 16
ceil2(17) == 32
\endcode
*/
static inline uint64_t ceil2( uint64_t n )
{
return uint64_t( 1 ) << log2ceil( n );
}
/// Checks if \p n is power of 2
CDS_CONSTEXPR static inline bool is_power2( uint64_t n ) CDS_NOEXCEPT
{
return (n & (n - 1)) == 0 && n;
}
/// Returns binary logarithm of \p n if \p n is power of two, otherwise returns 0
static inline uint64_t log2( uint64_t n )
{
return is_power2( n ) ? log2floor( n ) : 0;
}
//@endcond
#endif //#if CDS_BUILD_BITS == 32
}} // namespace cds::beans
#endif // #ifndef CDSLIB_INT_ALGO_H

View File

@@ -0,0 +1,470 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_ALGO_SPLIT_BITSTRING_H
#define CDSLIB_ALGO_SPLIT_BITSTRING_H
#include <cds/algo/base.h>
namespace cds { namespace algo {
/// Cuts a bit sequence from fixed-size bit-string
/**
The splitter can be used as an iterator over bit-string.
Each call of \p cut() or \p safe_cut() cuts the bit count specified
and keeps the position inside bit-string for the next call.
The splitter stores a const reference to bit-string, not a copy.
The maximum count of bits that can be cut in a single call is <tt> sizeof(UInt) * 8 </tt>
The splitter keeps byte order.
Template parameters:
- \p BitString - a fixed-sized type that interprets as bit string
- \p BitStringSize - the size of \p BitString in bytes, default is <tt>sizeof( BitString )</tt>.
You can specify 0 for default.
- \p UInt - an unsigned integer, return type for \p cut(), default is \p unsigned
There are specialized splitters:
- a simplified \p byte_splitter algorithm that is suitable when count is multiple of 8.
- \p number_splitter algorithm is suitable for a number
*/
template <typename BitString, size_t BitStringSize = sizeof( BitString ), typename UInt = unsigned >
class split_bitstring
{
public:
typedef BitString bitstring; ///< Bit-string type
typedef UInt uint_type; ///< Result type of \p cut() function
static CDS_CONSTEXPR size_t const c_bitstring_size = BitStringSize ? BitStringSize : sizeof( BitString ); ///< size of \p BitString in bytes
//@cond
static CDS_CONSTEXPR unsigned const c_nBitPerByte = 8;
//@endcond
public:
/// Initializises the splitter with reference to \p h and zero start bit offset
explicit split_bitstring( bitstring const& h )
: cur_( reinterpret_cast<uint8_t const*>( &h ) )
, offset_( 0 )
, first_( cur_ )
, last_( cur_ + c_bitstring_size )
{}
/// Initializises the splitter with reference to \p h and start bit offset \p nBitOffset
split_bitstring( bitstring const& h, size_t nBitOffset )
: cur_( reinterpret_cast<uint8_t const*>( &h ) + nBitOffset / c_nBitPerByte )
, offset_( nBitOffset % c_nBitPerByte )
, first_( reinterpret_cast<uint8_t const*>( &h ) )
, last_( first_ + c_bitstring_size )
{}
/// Returns \p true if end-of-string is not reached yet
explicit operator bool() const
{
return !eos();
}
/// Returns \p true if end-of-stream encountered
bool eos() const
{
return cur_ >= last_;
}
/// Cuts next \p count bits from bit-string
/**
For performance reason, the function does not manage out-of-bound condition.
To control that use \p safe_cut().
*/
uint_type cut( unsigned count )
{
assert( !eos() );
uint_type result = 0;
# if defined( CDS_ARCH_LITTLE_ENDIAN )
for ( unsigned done = 0; done < count; ) {
assert( cur_ < last_ );
unsigned bits = count - done;
if ( bits > c_nBitPerByte - offset_ )
bits = c_nBitPerByte - offset_;
result |= static_cast<uint_type>(( *cur_ >> offset_ ) & (( 1 << bits ) - 1 )) << done;
offset_ += bits;
assert( offset_ <= c_nBitPerByte );
if ( offset_ == c_nBitPerByte ) {
offset_ = 0;
++cur_;
}
done += bits;
}
# else
while ( count ) {
assert( cur_ < last_ );
unsigned bits = count <= ( c_nBitPerByte - offset_ ) ? count : c_nBitPerByte - offset_;
result = ( result << bits ) | (( *cur_ >> offset_ ) & ( ( 1 << bits ) - 1 ));
offset_ += bits;
assert( offset_ <= c_nBitPerByte );
if ( offset_ == c_nBitPerByte ) {
offset_ = 0;
++cur_;
}
count -= bits;
}
# endif
return result;
}
/// Cuts up to \p count from the bit-string
/**
Safe analog of \p cut() but if \p count is more than the rest of bit-string,
only the rest is returned.
When \p eos() condition is met the function returns 0.
*/
uint_type safe_cut( unsigned count )
{
if ( eos())
return 0;
unsigned const rest = static_cast<unsigned>( last_ - cur_ - 1 ) * c_nBitPerByte + ( c_nBitPerByte - offset_ );
if ( rest < count )
count = rest;
return count ? cut( count ) : 0;
}
/// Resets the splitter
void reset() CDS_NOEXCEPT
{
cur_ = first_;
offset_ = 0;
}
/// Returns pointer to source bitstring
bitstring const * source() const
{
return reinterpret_cast<bitstring const *>( first_ );
}
/// Returns current bit offset from beginning of bit-string
size_t bit_offset() const
{
return offset_ + (cur_ - first_) * c_nBitPerByte;
}
/// Returns how many bits remain
size_t rest_count() const
{
return c_bitstring_size * c_nBitPerByte - bit_offset();
}
/// Returns \p true for any argument
static CDS_CONSTEXPR bool is_correct( unsigned /*count*/ )
{
return true;
}
private:
//@cond
uint8_t const* cur_;
unsigned offset_;
uint8_t const* const first_;
uint8_t const* const last_;
//@endcond
};
/// Simplified \p split_bitstring algorithm when \p count is multiple of 8
template <typename BitString, size_t BitStringSize = sizeof( BitString ), typename UInt = unsigned >
class byte_splitter
{
public:
typedef BitString bitstring; ///< Bit-string type
typedef UInt uint_type; ///< Result type of \p cut() function
static CDS_CONSTEXPR size_t const c_bitstring_size = BitStringSize ? BitStringSize : sizeof( BitString ); ///< size of \p BitString in bytes
//@cond
static CDS_CONSTEXPR unsigned const c_nBitPerByte = 8;
//@endcond
public:
/// Initializises the splitter with reference to \p h and zero start bit offset
explicit byte_splitter( bitstring const& h )
: cur_( reinterpret_cast<uint8_t const*>( &h ) )
, first_( cur_ )
, last_( cur_ + c_bitstring_size )
{}
/// Initializises the splitter with reference to \p h and start bit offset \p nBitOffset
byte_splitter( bitstring const& h, size_t nBitOffset )
: cur_( reinterpret_cast<uint8_t const*>( &h ) + nBitOffset / c_nBitPerByte )
, first_( reinterpret_cast<uint8_t const*>( &h ) )
, last_( first_ + c_bitstring_size )
{
assert( is_correct( static_cast<unsigned>( nBitOffset )));
assert( !eos());
}
/// Returns \p true if end-of-string is not reached yet
explicit operator bool() const
{
return !eos();
}
/// Returns \p true if end-of-stream encountered
bool eos() const
{
return cur_ >= last_;
}
/// Cuts next \p count bits (must be multiplier of 8) from bit-string
/**
For performance reason, the function does not manage out-of-bound condition.
To control that use \p safe_cut().
*/
uint_type cut( unsigned count )
{
assert( !eos() );
assert( is_correct( count ) );
uint_type result = 0;
# if defined( CDS_ARCH_LITTLE_ENDIAN )
for ( unsigned i = 0; i < count; i += c_nBitPerByte ) {
result |= static_cast<uint_type>( *cur_ ) << i;
++cur_;
}
# else
for ( ; count; count -= c_nBitPerByte ) {
result = ( result << c_nBitPerByte ) | *cur_;
++cur_;
}
# endif
return result;
}
/// Cuts up to \p count from the bit-string
/**
Safe analog of \p cut(): if \p count is more than the rest of bit-string,
only the rest is returned.
When \p eos() condition is met the function returns 0.
*/
uint_type safe_cut( unsigned count )
{
if ( eos())
return 0;
unsigned const rest = static_cast<unsigned>( last_ - cur_ - 1 ) * c_nBitPerByte;
if ( rest < count )
count = rest;
return count ? cut( count ) : 0;
}
/// Resets the splitter
void reset() CDS_NOEXCEPT
{
cur_ = first_;
}
/// Returns pointer to source bitstring
bitstring const* source() const
{
return reinterpret_cast<bitstring const *>( first_ );
}
/// Returns current bit offset from beginning of bit-string
size_t bit_offset() const
{
return (cur_ - first_) * c_nBitPerByte;
}
/// Returns how many bits remain
size_t rest_count() const
{
return c_bitstring_size * c_nBitPerByte - bit_offset();
}
/// Checks if \p count is multiple of 8
static CDS_CONSTEXPR bool is_correct( unsigned count )
{
return count % 8 == 0;
}
private:
//@cond
uint8_t const* cur_;
uint8_t const* const first_;
uint8_t const* const last_;
//@endcond
};
/// Cuts a bit sequence from a number
/**
The splitter can be used as an iterator over bit representation of the number of type \p Int.
Each call of \p cut() or \p safe_cut() cuts the bit count specified
and keeps the position inside the number for the next call.
*/
template <typename Int>
class number_splitter
{
public:
typedef Int int_type; ///< Number type
typedef Int uint_type; ///< Result type of \p cut() function
//@cond
static CDS_CONSTEXPR unsigned const c_nBitPerByte = 8;
//@endcond
public:
/// Initalizes the splitter with nymber \p n and initial bit offset 0
explicit number_splitter( int_type n )
: number_( n )
, shift_( 0 )
{}
/// Initalizes the splitter with nymber \p n and initial bit offset \p initial_offset
number_splitter( int_type n, size_t initial_offset )
: number_( n )
, shift_( static_cast<unsigned>( initial_offset ))
{
assert( initial_offset < sizeof( int_type ) * c_nBitPerByte );
}
/// Returns \p true if end-of-string is not reached yet
explicit operator bool() const
{
return !eos();
}
/// Returns \p true if end-of-stream encountered
bool eos() const
{
return shift_ >= sizeof( int_type ) * c_nBitPerByte;
}
/// Cuts next \p count bits (must be multiplier of 8) from the number
/**
For performance reason, the function does not manage out-of-bound condition.
To control that use \p safe_cut().
*/
int_type cut( unsigned count )
{
assert( !eos() );
assert( is_correct( count ));
int_type result = ( number_ >> shift_ ) & (( 1 << count ) - 1 );
shift_ += count;
return result;
}
/// Cuts up to \p count from the bit-string
/**
Safe analog of \p cut(): if \p count is more than the rest of \p int_type,
only the rest is returned.
When \p eos() condition is met the function returns 0.
*/
int_type safe_cut( unsigned count )
{
if ( eos() )
return 0;
unsigned rest = static_cast<unsigned>( rest_count() );
if ( rest < count )
count = rest;
return count ? cut( count ) : 0;
}
/// Resets the splitter
void reset() CDS_NOEXCEPT
{
shift_ = 0;
}
/// Returns initial number
int_type source() const
{
return number_;
}
/// Returns current bit offset from beginning of the number
size_t bit_offset() const
{
return shift_;
}
/// Returns how many bits remain
size_t rest_count() const
{
return sizeof( int_type ) * c_nBitPerByte - shift_;
}
/// Checks if \p count is multiple of 8
static CDS_CONSTEXPR bool is_correct( unsigned count )
{
return count < sizeof( int_type ) * c_nBitPerByte;
}
private:
//@cond
int_type const number_;
unsigned shift_;
//@endcond
};
/// Metafunctin to select a most suitable splitter for type \p BitString of size \p BitStringSize
template <typename BitString, size_t BitStringSize >
struct select_splitter
{
typedef split_bitstring< BitString, BitStringSize > type; ///< metafunction result
};
//@cond
# define CDS_SELECT_NUMBER_SPLITTER( num_type ) \
template <> struct select_splitter<num_type, sizeof(num_type)> { typedef number_splitter<num_type> type; }
CDS_SELECT_NUMBER_SPLITTER( int );
CDS_SELECT_NUMBER_SPLITTER( unsigned );
CDS_SELECT_NUMBER_SPLITTER( short );
CDS_SELECT_NUMBER_SPLITTER( unsigned short );
CDS_SELECT_NUMBER_SPLITTER( long );
CDS_SELECT_NUMBER_SPLITTER( unsigned long );
CDS_SELECT_NUMBER_SPLITTER( long long );
CDS_SELECT_NUMBER_SPLITTER( unsigned long long );
# undef CDS_SELECT_NUMBER_SPLITTER
//@endcond
}} // namespace cds::algo
#endif // #ifndef CDSLIB_ALGO_SPLIT_BITSTRING_H

View File

@@ -0,0 +1,64 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_COMPILER_BACKOFF_IMPL_H
#define CDSLIB_COMPILER_BACKOFF_IMPL_H
#include <cds/details/defs.h>
#if CDS_COMPILER == CDS_COMPILER_MSVC || (CDS_COMPILER == CDS_COMPILER_INTEL && CDS_OS_INTERFACE == CDS_OSI_WINDOWS)
# if CDS_PROCESSOR_ARCH == CDS_PROCESSOR_X86
# include <cds/compiler/vc/x86/backoff.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_AMD64
# include <cds/compiler/vc/amd64/backoff.h>
# else
# error "MS VC++ compiler: unsupported processor architecture"
# endif
#elif CDS_COMPILER == CDS_COMPILER_GCC || CDS_COMPILER == CDS_COMPILER_CLANG || CDS_COMPILER == CDS_COMPILER_INTEL
# if CDS_PROCESSOR_ARCH == CDS_PROCESSOR_X86
# include <cds/compiler/gcc/x86/backoff.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_AMD64
# include <cds/compiler/gcc/amd64/backoff.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_IA64
# include <cds/compiler/gcc/ia64/backoff.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_SPARC
# include <cds/compiler/gcc/sparc/backoff.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_PPC64
# include <cds/compiler/gcc/ppc64/backoff.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_ARM7
# include <cds/compiler/gcc/arm7/backoff.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_ARM8
# include <cds/compiler/gcc/arm8/backoff.h>
# endif
#else
# error "Undefined compiler"
#endif
#endif // #ifndef CDSLIB_COMPILER_BACKOFF_IMPL_H

View File

@@ -0,0 +1,68 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_COMPILER_BITOP_H
#define CDSLIB_COMPILER_BITOP_H
// Choose appropriate header for current architecture and compiler
#if CDS_COMPILER == CDS_COMPILER_MSVC || (CDS_COMPILER == CDS_COMPILER_INTEL && CDS_OS_INTERFACE == CDS_OSI_WINDOWS)
/************************************************************************/
/* MS Visual C++ */
/************************************************************************/
# if CDS_PROCESSOR_ARCH == CDS_PROCESSOR_X86
# include <cds/compiler/vc/x86/bitop.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_AMD64
# include <cds/compiler/vc/amd64/bitop.h>
# endif
#elif CDS_COMPILER == CDS_COMPILER_GCC || CDS_COMPILER == CDS_COMPILER_CLANG || CDS_COMPILER == CDS_COMPILER_INTEL
/************************************************************************/
/* GCC */
/************************************************************************/
# if CDS_PROCESSOR_ARCH == CDS_PROCESSOR_X86
# include <cds/compiler/gcc/x86/bitop.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_AMD64
# include <cds/compiler/gcc/amd64/bitop.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_SPARC
# include <cds/compiler/gcc/sparc/bitop.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_IA64
# include <cds/compiler/gcc/ia64/bitop.h>
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_PPC64
# include <cds/compiler/gcc/ppc64/bitop.h>
# endif
#endif // Compiler choice
// Generic (C) implementation
#include <cds/details/bitop_generic.h>
#endif // #ifndef CDSLIB_COMPILER_BITOP_H

View File

@@ -0,0 +1,160 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_COMPILER_CLANG_DEFS_H
#define CDSLIB_COMPILER_CLANG_DEFS_H
// Compiler version
#define CDS_COMPILER_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
// Compiler name
#define CDS_COMPILER__NAME ("clang " __clang_version__)
#define CDS_COMPILER__NICK "clang"
#if CDS_COMPILER_VERSION < 30600
# error "Compiler version error. Clang version 3.6.0 and above is supported"
#endif
#if defined(_LIBCPP_VERSION) && !defined(CDS_USE_BOOST_ATOMIC) && CDS_COMPILER_VERSION < 30700
// Note: Clang libc++ atomic leads to program crash.
// So, we use libcds atomic implementation
# define CDS_USE_LIBCDS_ATOMIC
#endif
// clang for Windows
#if defined( _MSC_VER )
# define CDS_OS_INTERFACE CDS_OSI_WINDOWS
# if defined(_WIN64)
# define CDS_OS_TYPE CDS_OS_WIN64
# define CDS_OS__NAME "Win64"
# define CDS_OS__NICK "Win64"
# elif defined(_WIN32)
# define CDS_OS_TYPE CDS_OS_WIN32
# define CDS_OS__NAME "Win32"
# define CDS_OS__NICK "Win32"
# endif
#endif
#include <cds/compiler/gcc/compiler_macro.h>
#define alignof __alignof__
// C++11 inline namespace
#define CDS_CXX11_INLINE_NAMESPACE_SUPPORT
#define CDS_CONSTEXPR constexpr
#define CDS_NOEXCEPT_SUPPORT noexcept
#define CDS_NOEXCEPT_SUPPORT_(expr) noexcept(expr)
// C++11 thread_local keyword
#if !(CDS_OS_TYPE == CDS_OS_OSX && CDS_COMPILER_VERSION < 30600)
// OS X error?
// See http://stackoverflow.com/questions/23791060/c-thread-local-storage-clang-503-0-40-mac-osx
// http://stackoverflow.com/questions/28094794/why-does-apple-clang-disallow-c11-thread-local-when-official-clang-supports
// clang 3.6 ok?..
# define CDS_CXX11_THREAD_LOCAL_SUPPORT
#endif
// Full SFINAE support
#define CDS_CXX11_SFINAE
// Inheriting constructors
#define CDS_CXX11_INHERITING_CTOR
// Attributes
#if CDS_COMPILER_VERSION >= 30400
# if __cplusplus < 201103
# define CDS_DEPRECATED( reason ) __attribute__((deprecated( reason )))
# elif __cplusplus == 201103 // C++11
# define CDS_DEPRECATED( reason ) [[gnu::deprecated(reason)]]
# else // C++14
# define CDS_DEPRECATED( reason ) [[deprecated(reason)]]
# endif
#else
# define CDS_DEPRECATED( reason ) __attribute__((deprecated( reason )))
#endif
#define CDS_NORETURN __attribute__((__noreturn__))
// *************************************************
// Features
#if defined(__has_feature) && __has_feature(thread_sanitizer)
# ifndef CDS_THREAD_SANITIZER_ENABLED
# define CDS_THREAD_SANITIZER_ENABLED
# endif
#endif
#if defined(__has_feature) && __has_feature(address_sanitizer)
# ifndef CDS_ADDRESS_SANITIZER_ENABLED
# define CDS_ADDRESS_SANITIZER_ENABLED
# endif
#endif
// *************************************************
// Alignment macro
#define CDS_TYPE_ALIGNMENT(n) __attribute__ ((aligned (n)))
#define CDS_CLASS_ALIGNMENT(n) __attribute__ ((aligned (n)))
#define CDS_DATA_ALIGNMENT(n) __attribute__ ((aligned (n)))
// likely/unlikely
#define cds_likely( expr ) __builtin_expect( !!( expr ), 1 )
#define cds_unlikely( expr ) __builtin_expect( !!( expr ), 0 )
// Exceptions
#if defined( __EXCEPTIONS ) && __EXCEPTIONS == 1
# define CDS_EXCEPTION_ENABLED
#endif
// double-width CAS support - only for libc++
// You can manually suppress wide-atomic support by defining in compiler command line:
// for 64bit platform: -DCDS_DISABLE_128BIT_ATOMIC
// for 32bit platform: -DCDS_DISABLE_64BIT_ATOMIC
#ifdef _LIBCPP_VERSION
# if CDS_BUILD_BITS == 64
# if !defined( CDS_DISABLE_128BIT_ATOMIC ) && defined( __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 )
# define CDS_DCAS_SUPPORT
# endif
# else
# if !defined( CDS_DISABLE_64BIT_ATOMIC ) && defined( __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 )
# define CDS_DCAS_SUPPORT
# endif
# endif
#endif
#include <cds/compiler/gcc/compiler_barriers.h>
#endif // #ifndef CDSLIB_COMPILER_GCC_DEFS_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_COMPILER_DEFS_H
#define CDSLIB_COMPILER_DEFS_H
/*
Required C++11 features:
- move semantics [CDS_RVALUE_SUPPORT, CDS_MOVE_SEMANTICS_SUPPORT]
- lambda function [CDS_CXX11_LAMBDA_SUPPORT]
- variadic template [CDS_CXX11_VARIADIC_TEMPLATE_SUPPORT]
- template alias [CDS_CXX11_TEMPLATE_ALIAS_SUPPORT]
- explicit conversion operator [CDS_CXX11_EXPLICIT_CONVERSION_OPERATOR_SUPPORT]
- default template argument for function [CDS_CXX11_DEFAULT_FUNCTION_TEMPLATE_ARGS_SUPPORT]
- explicit default functions (=default) [CDS_CXX11_EXPLICITLY_DEFAULTED_FUNCTION_SUPPORT]
- =delete [CDS_CXX11_DELETE_DEFINITION_SUPPORT]
*/
#if CDS_COMPILER == CDS_COMPILER_MSVC
# include <cds/compiler/vc/defs.h>
#elif CDS_COMPILER == CDS_COMPILER_GCC
# include <cds/compiler/gcc/defs.h>
#elif CDS_COMPILER == CDS_COMPILER_INTEL
# include <cds/compiler/icl/defs.h>
#elif CDS_COMPILER == CDS_COMPILER_CLANG
# include <cds/compiler/clang/defs.h>
#elif CDS_COMPILER == CDS_COMPILER_UNKNOWN
# error Unknown compiler. Compilation aborted
#else
# error Unknown value of CDS_COMPILER macro
#endif
#ifndef CDS_EXPORT_API
# define CDS_EXPORT_API
#endif
#ifndef cds_likely
# define cds_likely( expr ) expr
# define cds_unlikely( expr ) expr
#endif
#ifndef static_if
# define static_if if
#endif
// Features
#include <cds/compiler/feature_tsan.h>
#endif // #ifndef CDSLIB_COMPILER_DEFS_H

View File

@@ -0,0 +1,116 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_COMPILER_FEATURE_TSAN_H
#define CDSLIB_COMPILER_FEATURE_TSAN_H
// Thread Sanitizer annotations.
// From http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/annotate_happens_before.cc?view=markup
//@cond
#ifdef CDS_THREAD_SANITIZER_ENABLED
# define CDS_TSAN_ANNOTATE_HAPPENS_BEFORE(addr) AnnotateHappensBefore(__FILE__, __LINE__, reinterpret_cast<void*>(addr))
# define CDS_TSAN_ANNOTATE_HAPPENS_AFTER(addr) AnnotateHappensAfter(__FILE__, __LINE__, reinterpret_cast<void*>(addr))
# define CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN AnnotateIgnoreReadsBegin(__FILE__, __LINE__)
# define CDS_TSAN_ANNOTATE_IGNORE_READS_END AnnotateIgnoreReadsEnd(__FILE__, __LINE__)
# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_END AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
# define CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN \
CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN; \
CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN
# define CDS_TSAN_ANNOTATE_IGNORE_RW_END \
CDS_TSAN_ANNOTATE_IGNORE_WRITES_END;\
CDS_TSAN_ANNOTATE_IGNORE_READS_END
# define CDS_TSAN_ANNOTATE_NEW_MEMORY( addr, sz ) AnnotateNewMemory( __FILE__, __LINE__, reinterpret_cast<void *>(addr), sz )
// Publish/unpublish - DEPRECATED
#if 0
# define CDS_TSAN_ANNOTATE_PUBLISH_MEMORY_RANGE( addr, sz ) AnnotatePublishMemoryRange( __FILE__, __LINE__, reinterpret_cast<void *>(addr), sz )
# define CDS_TSAN_ANNOTATE_UNPUBLISH_MEMORY_RANGE( addr, sz ) AnnotateUnpublishMemoryRange( __FILE__, __LINE__, reinterpret_cast<void *>(addr), sz )
#endif
# define CDS_TSAN_ANNOTATE_MUTEX_CREATE( addr ) AnnotateRWLockCreate( __FILE__, __LINE__, reinterpret_cast<void *>(addr))
# define CDS_TSAN_ANNOTATE_MUTEX_DESTROY( addr ) AnnotateRWLockDestroy( __FILE__, __LINE__, reinterpret_cast<void *>(addr))
// must be called after actual acquire
# define CDS_TSAN_ANNOTATE_MUTEX_ACQUIRED( addr ) AnnotateRWLockAcquired( __FILE__, __LINE__, reinterpret_cast<void *>(addr), 1 )
// must be called before actual release
# define CDS_TSAN_ANNOTATE_MUTEX_RELEASED( addr ) AnnotateRWLockReleased( __FILE__, __LINE__, reinterpret_cast<void *>(addr), 1 )
// provided by TSan
extern "C" {
void AnnotateHappensBefore(const char *f, int l, void *addr);
void AnnotateHappensAfter(const char *f, int l, void *addr);
void AnnotateIgnoreReadsBegin(const char *f, int l);
void AnnotateIgnoreReadsEnd(const char *f, int l);
void AnnotateIgnoreWritesBegin(const char *f, int l);
void AnnotateIgnoreWritesEnd(const char *f, int l);
#if 0
void AnnotatePublishMemoryRange( const char *f, int l, void * mem, size_t size );
void AnnotateUnpublishMemoryRange( const char *f, int l, void * addr, size_t size );
#endif
void AnnotateNewMemory( const char *f, int l, void * mem, size_t size );
void AnnotateRWLockCreate( const char *f, int l, void* m );
void AnnotateRWLockDestroy( const char *f, int l, void* m );
void AnnotateRWLockAcquired( const char *f, int l, void *m, long is_w );
void AnnotateRWLockReleased( const char *f, int l, void *m, long is_w );
}
#else // CDS_THREAD_SANITIZER_ENABLED
# define CDS_TSAN_ANNOTATE_HAPPENS_BEFORE(addr)
# define CDS_TSAN_ANNOTATE_HAPPENS_AFTER(addr)
# define CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN
# define CDS_TSAN_ANNOTATE_IGNORE_READS_END
# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN
# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_END
# define CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN
# define CDS_TSAN_ANNOTATE_IGNORE_RW_END
#if 0
# define CDS_TSAN_ANNOTATE_PUBLISH_MEMORY_RANGE( addr, sz )
# define CDS_TSAN_ANNOTATE_UNPUBLISH_MEMORY_RANGE( addr, sz )
#endif
# define CDS_TSAN_ANNOTATE_NEW_MEMORY( addr, sz )
# define CDS_TSAN_ANNOTATE_MUTEX_CREATE( addr )
# define CDS_TSAN_ANNOTATE_MUTEX_DESTROY( addr )
# define CDS_TSAN_ANNOTATE_MUTEX_ACQUIRED( addr )
# define CDS_TSAN_ANNOTATE_MUTEX_RELEASED( addr )
#endif
//@endcond
#endif // #ifndef CDSLIB_COMPILER_FEATURE_TSAN_H

View File

@@ -0,0 +1,60 @@
/*
This file is a part of libcds - Concurrent Data Structures library
(C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
Source code repo: http://github.com/khizmax/libcds/
Download: http://sourceforge.net/projects/libcds/files/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_COMPILER_GCC_AMD64_BACKOFF_H
#define CDSLIB_COMPILER_GCC_AMD64_BACKOFF_H
//@cond none
namespace cds { namespace backoff {
namespace gcc { namespace amd64 {
# define CDS_backoff_nop_defined
static inline void backoff_nop()
{
asm volatile ( "nop;" );
}
# define CDS_backoff_hint_defined
static inline void backoff_hint()
{
asm volatile ( "pause;" );
}
}} // namespace gcc::amd64
namespace platform {
using namespace gcc::amd64;
}
}} // namespace cds::backoff
//@endcond
#endif // #ifndef CDSLIB_COMPILER_GCC_AMD64_BACKOFF_H

Some files were not shown because too many files have changed in this diff Show More