/*++

Copyright (c) 1996 Microsoft Corporation

Module Name:

    memdbp.h

Abstract:

    internal functions for memdb operations

Author:

    Matthew Vanderzee (mvander) 13-Aug-1999

Revision History:


--*/


//
// Constants
//

#define INVALID_OFFSET      (~((UINT)0))


//
// database types
//
#define DB_NOTHING          0x00
#define DB_PERMANENT        0x01
#define DB_TEMPORARY        0x02

#ifdef DEBUG

#define PTR_WAS_INVALIDATED(x)          (x=NULL)

#else

#define PTR_WAS_INVALIDATED(x)

#endif

//
// signatures for different memory structures.
//
#define KEYSTRUCT_SIGNATURE         ('K'+('E'<<8)+('E'<<16)+('Y'<<24))
#define DATABLOCK_SIGNATURE         ('B'+('L'<<8)+('O'<<16)+('K'<<24))
#define NODESTRUCT_SIGNATURE        ('N'+('O'<<8)+('D'<<16)+('E'<<24))
#define BINTREE_SIGNATURE           ('T'+('R'<<8)+('E'<<16)+('E'<<24))
#define LISTELEM_SIGNATURE          ('L'+('I'<<8)+('S'<<16)+('T'<<24))


#define MEMDB_VERBOSE   0


//
// KEYSTRUCT flags
//

#define KSF_ENDPOINT        0x01
#define KSF_DATABLOCK       0x02

//
// we only need this flag for easier checking
// of keys, in FindKeyStructInDatabase()
//
#ifdef DEBUG
#define KSF_DELETED         0x04
#endif






//
// database allocation parameters
//

#define ALLOC_TOLERANCE 32

#define MAX_HIVE_NAME       64


//
// Typedefs
//

typedef struct {
    UINT Size;
    UINT End;
    UINT FreeHead;
    PBYTE Buf;
} MEMDBHASH, *PMEMDBHASH;



//
//
// The DATABASE structure holds all pieces of information necessary
// to maintain a portion of the overall memory database.  There are
// two DATABASE structures, a permanent and a temporary one.
//

typedef struct {
    UINT AllocSize;
    UINT End;
    UINT FirstLevelTree;
    UINT FirstKeyDeleted;          // this stores the Offset of the key, not the Index
    UINT FirstBinTreeDeleted;
    UINT FirstBinTreeNodeDeleted;
    UINT FirstBinTreeListElemDeleted;
    BOOL AllocFailed;
    PMEMDBHASH HashTable;
    GROWBUFFER OffsetBuffer;
    UINT OffsetBufferFirstDeletedIndex;
    BYTE Buf[];
} DATABASE, *PDATABASE;



//
// Globals - defined in database.c
//

extern PDATABASE g_CurrentDatabase;
extern BYTE g_CurrentDatabaseIndex;
extern CRITICAL_SECTION g_MemDbCs;

#ifdef DEBUG
extern BOOL g_UseDebugStructs;
#endif




#define OFFSET_TO_PTR(Offset)   (g_CurrentDatabase->Buf+(Offset))
#define PTR_TO_OFFSET(Ptr)      (UINT)((UBINT)(Ptr)-(UBINT)(g_CurrentDatabase->Buf))



//
// GET_EXTERNAL_INDEX converts an internal index and converts it to a key or data handle (has database number as top byte).
// GET_DATABASE takes a key or data handle and returns the database number byte
// GET_INDEX takes a key or data handle and returns the index without the database number
//
#define GET_EXTERNAL_INDEX(Index) ((Index) | ((UINT)(g_CurrentDatabaseIndex) << (8*sizeof(UINT)-8)))
#define GET_DATABASE(Index) ((BYTE)((Index) >> (8*sizeof(UINT)-8)))
#define GET_INDEX(Index) ((Index) & (INVALID_OFFSET>>8))




//
// a KEYSTRUCT holds each piece of a memdb entry.  A single KEYSTRUCT
// holds a portion of a key (delimited by a backslash), and the
// KEYSTRUCTs are organized into a binary tree.  Each KEYSTRUCT
// can also contain additional binary trees.  This is what makes
// memdb so versatile--many relationships can be established by
// formatting key strings in various ways.
//
// when changing offset of KeyName in KEYSTRUCT (by adding new members
// or resizing or reordering, etc) be sure to change constant in
// GetDataStr macro below (currently (3*sizeof(UINT)+4)).


typedef struct {
#ifdef DEBUG
    DWORD Signature;
#endif

    union {
        UINT Value;                // value of key
        UINT DataSize;             // size of the actual data (if this is a data structure
        UINT NextDeleted;          // for deleted items, we keep a list of free blocks
    };

    UINT Flags;                    // key flags

    UINT DataStructIndex;          // offset of Data structure holding the binary data
    UINT NextLevelTree;            // offset of bintree holding next level keystructs
    UINT PrevLevelIndex;           // index of previous level keystruct

    UINT Size;                     // size of block (maybe not all of it is used)
    BYTE KeyFlags;
    BYTE DataFlags;

    union {
        WCHAR KeyName[];           // name of key (just this level, not full key)
        BYTE Data[];               // Binary data stored in this keystruct
    };
} KEYSTRUCT, *PKEYSTRUCT;

#define KEYSTRUCT_SIZE_MAIN ((WORD)(5*sizeof(UINT) + sizeof(UINT) + 2*sizeof(BYTE)))

#ifdef DEBUG
#define KEYSTRUCT_HEADER_SIZE   sizeof(DWORD)
#define KEYSTRUCT_SIZE      (KEYSTRUCT_SIZE_MAIN + \
                            (WORD)(g_UseDebugStructs ? KEYSTRUCT_HEADER_SIZE : 0))
#else
#define KEYSTRUCT_SIZE      KEYSTRUCT_SIZE_MAIN
#endif

//
// GetDataStr is used by the bintree.c functions to get
// the data string inside a data element, to be used for
// ordering in the tree.  For us, the data type is
// a KeyStruct.
//
#define GetDataStr(DataIndex) ((PWSTR)(OFFSET_TO_PTR(KeyIndexToOffset(DataIndex)+KEYSTRUCT_SIZE)))












//
// hash.c routines
//

PMEMDBHASH
CreateHashBlock (
    VOID
    );

VOID
FreeHashBlock (
    IN      PMEMDBHASH pHashTable
    );

BOOL
ReadHashBlock (
    IN      PMEMDBHASH pHashTable,
    IN OUT  PBYTE *Buf
    );

BOOL
WriteHashBlock (
    IN      PMEMDBHASH pHashTable,
    IN OUT  PBYTE *Buf
    );

UINT
GetHashTableBlockSize (
    IN      PMEMDBHASH pHashTable
    );

BOOL
AddHashTableEntry (
    IN      PMEMDBHASH pHashTable,
    IN      PCWSTR FullString,
    IN      UINT Offset
    );

UINT
FindStringInHashTable (
    IN      PMEMDBHASH pHashTable,
    IN      PCWSTR FullString
    );

BOOL
RemoveHashTableEntry (
    IN      PMEMDBHASH pHashTable,
    IN      PCWSTR FullString
    );



//
// memdbfile.c
//



BOOL
SetSizeOfFile (
    HANDLE hFile,
    LONGLONG Size
    );

PBYTE
MapFileFromHandle (
    HANDLE hFile,
    PHANDLE hMap
    );

#define UnmapFileFromHandle(Buf, hMap) UnmapFile(Buf, hMap, INVALID_HANDLE_VALUE)





//
// database.c
//


BOOL
DatabasesInitializeA (
    IN      PCSTR DatabasePath  OPTIONAL
    );

BOOL
DatabasesInitializeW (
    IN      PCWSTR DatabasePath  OPTIONAL
    );

PCSTR
DatabasesGetBasePath (
    VOID
    );

VOID
DatabasesTerminate (
    IN      BOOL EraseDatabasePath
    );

BOOL
SizeDatabaseBuffer (
    IN      BYTE DatabaseIndex,
    IN      UINT NewSize
    );

UINT
DatabaseAllocBlock (
    IN      UINT Size
    );

BOOL
SelectDatabase (
    IN      BYTE DatabaseIndex
    );

PCWSTR
SelectHiveW (
    IN      PCWSTR FullKeyStr
    );

BYTE
GetCurrentDatabaseIndex (
    VOID
    );

#ifdef DEBUG

BOOL
CheckDatabase (
    IN      UINT Level
    );

#endif


//
// offsetbuf.c
//

VOID
RedirectKeyIndex (
    IN      UINT Index,
    IN      UINT TargetIndex
    );

UINT
KeyIndexToOffset (
    IN  UINT Index
    );

UINT
AddKeyOffsetToBuffer(
    IN  UINT Offset
    );

VOID
RemoveKeyOffsetFromBuffer(
    IN  UINT Index
    );

VOID
MarkIndexList (
    PUINT IndexList,
    UINT IndexListSize
    );

BOOL
ReadOffsetBlock (
    OUT     PGROWBUFFER pOffsetBuffer,
    IN OUT  PBYTE *Buf
    );

BOOL
WriteOffsetBlock (
    IN      PGROWBUFFER pOffsetBuffer,
    IN OUT  PBYTE *Buf
    );

UINT GetOffsetBufferBlockSize (
    IN      PGROWBUFFER pOffsetBuffer
    );



//
// pastring.c
// Pascal-style string: wide characters, first char
//      is number of characters, no null-termination
//

typedef WCHAR * PPASTR;
typedef WCHAR const * PCPASTR;

//
// these convert a WSTR in place from null-terminated
// to Pascal-style strings
//
PPASTR StringPasConvertTo (PWSTR str);
PWSTR StringPasConvertFrom (PPASTR str);

//
// these convert a WSTR from null-terminated
// to Pascal-style strings in new string buffer
//
PPASTR StringPasCopyConvertTo (PPASTR str1, PCWSTR str2);
PWSTR StringPasCopyConvertFrom (PWSTR str1, PCPASTR str2);

PPASTR StringPasCopy (PPASTR str1, PCPASTR str2);
UINT StringPasCharCount (PCPASTR str);

INT  StringPasCompare (PCPASTR str1, PCPASTR str2);
BOOL StringPasMatch (PCPASTR str1, PCPASTR str2);
INT  StringPasICompare (PCPASTR str1, PCPASTR str2);
BOOL StringPasIMatch (PCPASTR str1, PCPASTR str2);


//
// keystrct.c
//

#ifdef DEBUG

PKEYSTRUCT
GetKeyStructFromOffset (
    UINT Offset
    );

PKEYSTRUCT
GetKeyStruct (
    UINT Index
    );

#else

#define GetKeyStructFromOffset(Offset) ((Offset==INVALID_OFFSET) ?          \
                                        NULL :                              \
                                        (PKEYSTRUCT)OFFSET_TO_PTR(Offset))
#define GetKeyStruct(Index)            ((Index==INVALID_OFFSET) ?           \
                                        NULL :                              \
                                        GetKeyStructFromOffset(KeyIndexToOffset(Index)))
#endif



UINT
GetFirstIndex (
    IN      UINT TreeOffset,
    OUT     PUINT pTreeEnum
    );

UINT
GetNextIndex (
    IN OUT      PUINT pTreeEnum
    );

UINT
NewKey (
    IN  PCWSTR KeyStr
    );

UINT
NewEmptyKey (
    IN  PCWSTR KeyStr
    );


BOOL
PrivateDeleteKeyByIndex (
    IN      UINT Index
    );

BOOL
DeleteKey (
    IN      PCWSTR KeyStr,
    IN      UINT TreeOffset,
    IN      BOOL MustMatch
    );

BOOL
PrivateBuildKeyFromIndex (
    IN      UINT StartLevel,               // zero-based
    IN      UINT TailIndex,
    OUT     PWSTR Buffer,                   OPTIONAL
    OUT     PUINT ValPtr,                   OPTIONAL
    OUT     PUINT UserFlagsPtr,             OPTIONAL
    OUT     PUINT SizeInChars               OPTIONAL
    );


BOOL
KeyStructSetInsertionOrdered (
    IN      PKEYSTRUCT Key
    );


UINT KeyStructGetChildCount (
    IN      PKEYSTRUCT pKey
    );

UINT
FindKeyStructInTree (
    IN UINT TreeOffset,
    IN PWSTR KeyName,
    IN BOOL IsPascalString
    );




#ifdef DEBUG
BOOL
CheckLevel(UINT TreeOffset,
            UINT PrevLevelIndex
            );
#endif



//
// keyfind.c
//


UINT
FindKeyStruct(
    IN PCWSTR Key
    );

UINT
FindKey (
    IN  PCWSTR FullKeyPath
    );

UINT
FindKeyStructUsingTreeOffset (
    IN      UINT TreeOffset,
    IN OUT  PUINT pTreeEnum,
    IN      PCWSTR KeyStr
    );

#ifdef DEBUG
BOOL
FindKeyStructInDatabase(
    UINT KeyOffset
    );
#endif


//
// keydata.c
//


BOOL
KeyStructSetValue (
    IN      UINT KeyIndex,
    IN      UINT Value
    );

BOOL
KeyStructSetFlags (
    IN      UINT KeyIndex,
    IN      BOOL ReplaceFlags,
    IN      UINT SetFlags,
    IN      UINT ClearFlags
    );

UINT
KeyStructAddBinaryData (
    IN      UINT KeyIndex,
    IN      BYTE Type,
    IN      BYTE Instance,
    IN      PCBYTE Data,
    IN      UINT DataSize
    );

UINT
KeyStructGrowBinaryData (
    IN      UINT KeyIndex,
    IN      BYTE Type,
    IN      BYTE Instance,
    IN      PCBYTE Data,
    IN      UINT DataSize
    );

UINT
KeyStructGrowBinaryDataByIndex (
    IN      UINT OldIndex,
    IN      PCBYTE Data,
    IN      UINT DataSize
    );

BOOL
KeyStructDeleteBinaryData (
    IN      UINT KeyIndex,
    IN      BYTE Type,
    IN      BYTE Instance
    );

BOOL
KeyStructDeleteBinaryDataByIndex (
    IN      UINT DataIndex
    );

UINT
KeyStructReplaceBinaryDataByIndex (
    IN      UINT OldIndex,
    IN      PCBYTE Data,
    IN      UINT DataSize
    );

PBYTE
KeyStructGetBinaryData (
    IN      UINT KeyIndex,
    IN      BYTE Type,
    IN      BYTE Instance,
    OUT     PUINT DataSize,
    OUT     PUINT DataIndex     //OPTIONAL
    );

PBYTE
KeyStructGetBinaryDataByIndex (
    IN      UINT DataIndex,
    OUT     PUINT DataSize
    );

UINT
KeyStructGetDataIndex (
    IN      UINT KeyIndex,
    IN      BYTE Type,
    IN      BYTE Instance
    );

DATAHANDLE
KeyStructAddLinkage (
    IN      UINT KeyIndex,
    IN      BYTE Type,
    IN      BYTE Instance,
    IN      UINT Linkage,
    IN      BOOL AllowDuplicates
    );

DATAHANDLE
KeyStructAddLinkageByIndex (
    IN      UINT DataIndex,
    IN      UINT Linkage,
    IN      BOOL AllowDuplicates
    );

BOOL
KeyStructDeleteLinkage (
    IN      UINT KeyIndex,
    IN      BYTE Type,
    IN      BYTE Instance,
    IN      UINT Linkage,
    IN      BOOL FirstOnly
    );

BOOL
KeyStructDeleteLinkageByIndex (
    IN      UINT DataIndex,
    IN      UINT Linkage,
    IN      BOOL FirstOnly
    );

BOOL
KeyStructTestLinkage (
    IN      UINT KeyIndex,
    IN      BYTE Type,
    IN      BYTE Instance,
    IN      KEYHANDLE Linkage
    );

BOOL
KeyStructTestLinkageByIndex (
    IN      UINT DataIndex,
    IN      UINT Linkage
    );

BOOL
KeyStructGetValue (
    IN  PKEYSTRUCT KeyStruct,
    OUT PUINT Value
    );

BOOL
KeyStructGetFlags (
    IN  PKEYSTRUCT KeyStruct,
    OUT PUINT Flags
    );

VOID
KeyStructFreeAllData (
    PKEYSTRUCT KeyStruct
    );







//
// bintree.c
//

#ifdef DEBUG

//
// violating code hiding for easier debugging.
// (only database.c should see bintree functions)
//

UINT
BinTreeGetSizeOfStruct(
    DWORD Signature
    );

BOOL
BinTreeFindStructInDatabase(
    DWORD Sig,
    UINT Offset
    );

#endif