|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
persist.c
Abstract:
General structure persistence functions.
Author:
Aghajanyan Souren 27-Mar-2001
Revision History:
--*/
#include "pch.h"
#include "migutilp.h"
#include "persist.h"
BOOL MayExtraMemRequire ( IN PFIELD_DESCRIPTION FieldsDescription ) { FIELD_DESCRIPTION * FieldPtr;
for(FieldPtr = FieldsDescription; FieldPtr->Offset != END_OF_STRUCT; FieldPtr++){ if(!FieldPtr->FieldDescription && FieldPtr->ArraySizeFieldOffset && FieldPtr->byValue){ return TRUE; } }
return FALSE; }
SIZE_T GetExtraMemRequirements( IN BYTE * StructurePtr, IN PFIELD_DESCRIPTION FieldsDescription ) /*
This function provide additional memory requirements, only in case when structure has variable size. And have to be declared by PERSIST_FIELD_BY_VALUE_NESTED_TYPE_CYCLE For example: struct VariableSizeStruct{ ...... UINT uiNumberOfItem; ITEM items[1]; }; PERSIST_FIELD_BY_VALUE_NESTED_TYPE_CYCLE(VariableSizeStruct, ITEM, items, uiNumberOfItem) */ { UINT Len; FIELD_DESCRIPTION * FieldPtr; SIZE_T ExtraBytes = 0; UINT uiItemCount;
MYASSERT(StructurePtr);
for(FieldPtr = FieldsDescription; FieldPtr->Offset != END_OF_STRUCT; FieldPtr++){ if(!FieldPtr->FieldDescription && FieldPtr->ArraySizeFieldOffset && FieldPtr->byValue && FieldPtr->Size){ uiItemCount = *(GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT*, StructurePtr, FieldPtr->ArraySizeFieldOffset)); ExtraBytes += uiItemCount? FieldPtr->Size * (uiItemCount - FieldPtr->InitialNumberOfItem): 0; } }
return ExtraBytes; }
BOOL SerializeStore( IN OUT BYTE * BufferMain, IN BYTE * StructurePtr, IN PFIELD_DESCRIPTION FieldsDescription, IN OUT SIZE_T * uiHowUsed ) { UINT i; UINT iLen; SIZE_T Size = 0; BYTE * SubStruct; FIELD_DESCRIPTION * FieldPtr;
if(!uiHowUsed){ uiHowUsed = &Size; }
MYASSERT(StructurePtr);
for(FieldPtr = FieldsDescription; FieldPtr->Offset != END_OF_STRUCT; FieldPtr++){ if(FieldPtr->FieldDescription) { iLen = FieldPtr->ArraySizeFieldOffset? *(GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT*, StructurePtr, FieldPtr->ArraySizeFieldOffset)): 1;
if(FieldPtr->byValue){ SubStruct = GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(BYTE*, StructurePtr, FieldPtr->Offset); MYASSERT(SubStruct); } else{ SubStruct = GET_STRUCT_MEMBER_BYREF_FROM_OFFSET(BYTE*, StructurePtr, FieldPtr->Offset); if(BufferMain){ *(BufferMain + *uiHowUsed) = (SubStruct && iLen); } ++*uiHowUsed; if(!SubStruct || !iLen){ continue; } }
for(i = 0; i < iLen; i++, SubStruct += FieldPtr->Size + GetExtraMemRequirements(SubStruct, FieldPtr->FieldDescription)) { if(!SerializeStore(BufferMain, SubStruct, FieldPtr->FieldDescription, uiHowUsed)){ MYASSERT(FALSE); return FALSE; } } } else{ if(FieldPtr->IsString != NoStr) { SubStruct = GET_STRUCT_MEMBER_BYREF_FROM_OFFSET(BYTE*, StructurePtr, FieldPtr->Offset); if(!SubStruct){ SubStruct = (BYTE*)(FieldPtr->IsString == AnsiStr? "": (char*)L""); }
if(FieldPtr->IsString == AnsiStr){ iLen = (strlen((PCSTR)SubStruct) + 1) * sizeof(CHAR); } else{ iLen = (wcslen((PWSTR)SubStruct) + 1) * sizeof(WCHAR); }
if(BufferMain){ memcpy((BYTE *)(BufferMain + *uiHowUsed), SubStruct, iLen); }
*uiHowUsed += iLen; } else { if(FieldPtr->Size) { iLen = FieldPtr->ArraySizeFieldOffset? *(GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT*, StructurePtr, FieldPtr->ArraySizeFieldOffset)): 1; if(BufferMain){ memcpy((char *)(BufferMain + *uiHowUsed), GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(BYTE*, StructurePtr, FieldPtr->Offset), iLen * FieldPtr->Size); } *uiHowUsed += iLen * FieldPtr->Size; } } } }
return TRUE; }
UINT CalcSignature( IN BYTE * BufferPtr, IN SIZE_T Length ) { UINT i; SIZE_T iLen = Length >> 2; SIZE_T iRest = Length & 3; UINT uiSignature = 0;
for(i = 0; i < iLen; i++){ uiSignature ^= ((PUINT)BufferPtr)[i]; }
if(iRest){ uiSignature ^= (((PUINT)BufferPtr)[iLen]) & (0xffffffff >> ((sizeof(UINT) - iRest) << 3)); }
return uiSignature; }
PERSISTRESULTSENUM PersistStore( OUT BYTE ** BufferPtr, OUT SIZE_T *Size, IN BYTE * StructurePtr, IN PSTRUCT_DEFINITION StructDefinitionPtr ) { BYTE * buffer = NULL; BYTE * memBlock = NULL; SIZE_T uiBufferSize = 0; PPERSIST_HEADER pPersistHeader; PFIELD_DESCRIPTION FieldsDescription; PERSISTRESULTSENUM result = Persist_Success;
if(!BufferPtr || !Size || !StructurePtr || !StructDefinitionPtr){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return Persist_BadParameters; }
FieldsDescription = StructDefinitionPtr->FieldDescriptions; if(!FieldsDescription){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return Persist_BadParameters; }
__try{ uiBufferSize = sizeof(PERSIST_HEADER); if(!SerializeStore(NULL, StructurePtr, FieldsDescription, &uiBufferSize)){ SetLastError(ERROR_ACCESS_DENIED); return Persist_Fail; }
memBlock = (BYTE *)MemAllocUninit(uiBufferSize);
if(!memBlock){ SetLastError(ERROR_NOT_ENOUGH_MEMORY); MYASSERT(FALSE); return Persist_Fail; }
buffer = memBlock; *BufferPtr = memBlock; *Size = uiBufferSize;
pPersistHeader = (PPERSIST_HEADER)memBlock; buffer += sizeof(PERSIST_HEADER);
pPersistHeader->dwVersion = StructDefinitionPtr->dwVersion; pPersistHeader->dwReserved = 0;
uiBufferSize = 0; if(!SerializeStore(buffer, StructurePtr, FieldsDescription, &uiBufferSize)){ FreeMem(memBlock); SetLastError(ERROR_ACCESS_DENIED); return Persist_Fail; }
pPersistHeader->dwSignature = CalcSignature(buffer, uiBufferSize);
SetLastError(ERROR_SUCCESS); } __except(EXCEPTION_EXECUTE_HANDLER){ if(memBlock){ FreeMem(memBlock); } result = Persist_Fail; SetLastError(ERROR_ACCESS_DENIED); }
return result; }
BOOL SerializeLoad( IN BYTE * BufferMain, IN OUT BYTE * StructurePtr, IN PFIELD_DESCRIPTION FieldsDescription, IN OUT SIZE_T * uiHowUsed, IN BOOL bRestoreOnlyByValue ) { FIELD_DESCRIPTION * FieldPtr; UINT i; UINT iLen; SIZE_T Size = 0; BYTE * SubStruct; BYTE * OriginalBuffer; SIZE_T sizeValue; SIZE_T uiPrevValue;
if(!uiHowUsed){ uiHowUsed = &Size; }
MYASSERT(StructurePtr);
for(FieldPtr = FieldsDescription; FieldPtr->Offset != END_OF_STRUCT; FieldPtr++){ if(FieldPtr->FieldDescription) { iLen = FieldPtr->ArraySizeFieldOffset? *(GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT*, StructurePtr, FieldPtr->ArraySizeFieldOffset)): 1;
if(FieldPtr->byValue){ SubStruct = GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(BYTE*, StructurePtr, FieldPtr->Offset); } else{ if(bRestoreOnlyByValue){ continue; }
if(!*(BufferMain + (*uiHowUsed)++)){ *GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT_PTR *, StructurePtr, FieldPtr->Offset) = (UINT_PTR)NULL; continue; }
MYASSERT(FieldPtr->Size && iLen);
sizeValue = FieldPtr->Size * iLen;
SubStruct = (BYTE *)MemAllocUninit(sizeValue); if(!SubStruct){ return FALSE; }
if(MayExtraMemRequire(FieldPtr->FieldDescription)){ OriginalBuffer = SubStruct; uiPrevValue = *uiHowUsed; for(i = 0; i < iLen; i++, SubStruct += FieldPtr->Size) { if(!SerializeLoad(BufferMain, SubStruct, FieldPtr->FieldDescription, &uiPrevValue, TRUE)){ return FALSE; } sizeValue += GetExtraMemRequirements(SubStruct, FieldPtr->FieldDescription); } FreeMem(OriginalBuffer);
SubStruct = (BYTE *)MemAllocZeroed(sizeValue); if(!SubStruct){ return FALSE; } }
*GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT_PTR *, StructurePtr, FieldPtr->Offset) = (UINT_PTR)SubStruct; }
for(i = 0; i < iLen; i++, SubStruct += FieldPtr->Size + GetExtraMemRequirements(SubStruct, FieldPtr->FieldDescription)) { if(!SerializeLoad(BufferMain, SubStruct, FieldPtr->FieldDescription, uiHowUsed, FALSE)){ return FALSE; } } } else{ if(FieldPtr->IsString != NoStr){ if(bRestoreOnlyByValue){ continue; }
if(FieldPtr->IsString == AnsiStr){ iLen = strlen((char *)(BufferMain + *uiHowUsed)) + sizeof(CHAR); } else{ iLen = (wcslen((WCHAR *)(BufferMain + *uiHowUsed)) + 1) * sizeof(WCHAR); } MYASSERT(iLen);
if(iLen != (FieldPtr->IsString == AnsiStr? sizeof(CHAR): sizeof(WCHAR))) { SubStruct = (BYTE *)MemAllocUninit(iLen); if(!SubStruct){ return FALSE; } memcpy((BYTE *)SubStruct, (BYTE *)(BufferMain + *uiHowUsed), iLen); } else{ SubStruct = NULL; }
*GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT_PTR *, StructurePtr, FieldPtr->Offset) = (UINT_PTR)SubStruct;
*uiHowUsed += iLen; } else { if(FieldPtr->Size) { iLen = FieldPtr->ArraySizeFieldOffset? *(GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT*, StructurePtr, FieldPtr->ArraySizeFieldOffset)): 1; sizeValue = iLen * FieldPtr->Size; if(iLen > 1 && bRestoreOnlyByValue){ continue; }
memcpy(GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(BYTE*, StructurePtr, FieldPtr->Offset), (char *)(BufferMain + *uiHowUsed), sizeValue); *uiHowUsed += sizeValue; } } } }
return TRUE; }
PERSISTRESULTSENUM PersistLoad( IN BYTE * BufferPtr, IN SIZE_T Size, OUT BYTE * StructurePtr, IN PSTRUCT_DEFINITION StructDefinitionPtr ) { SIZE_T uiBufferSize = 0; PPERSIST_HEADER pPersistHeader; PFIELD_DESCRIPTION FieldsDescription; PERSISTRESULTSENUM result = Persist_Success;
if(!BufferPtr || !Size || !StructurePtr || !StructDefinitionPtr){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return Persist_BadParameters; }
FieldsDescription = StructDefinitionPtr->FieldDescriptions; if(!FieldsDescription){ SetLastError(ERROR_INVALID_PARAMETER); MYASSERT(FALSE); return Persist_BadParameters; }
__try{ pPersistHeader = (PPERSIST_HEADER)BufferPtr;
if(pPersistHeader->dwVersion != StructDefinitionPtr->dwVersion){ SetLastError(ERROR_ACCESS_DENIED); MYASSERT(FALSE); return Persist_WrongVersion; }
BufferPtr += sizeof(PERSIST_HEADER); Size -= sizeof(PERSIST_HEADER); if(pPersistHeader->dwSignature != CalcSignature(BufferPtr, Size)){ SetLastError(ERROR_CRC); return Persist_WrongSignature; }
uiBufferSize = 0; //Top structure cannot be variable size
if(!SerializeLoad(BufferPtr, StructurePtr, FieldsDescription, &uiBufferSize, FALSE)){ SetLastError(ERROR_ACCESS_DENIED); return Persist_Fail; }
SetLastError(ERROR_SUCCESS); } __except(EXCEPTION_EXECUTE_HANDLER){ result = Persist_Fail; SetLastError(ERROR_ACCESS_DENIED); }
return result; }
VOID PersistReleaseMemory( IN BYTE * StructurePtr, IN PFIELD_DESCRIPTION FieldsDescription ) { UINT i; UINT iLen; FIELD_DESCRIPTION * FieldPtr; BYTE * SubStruct;
if(!StructurePtr || !FieldsDescription){ return; }
for(FieldPtr = FieldsDescription; FieldPtr->Offset != END_OF_STRUCT; FieldPtr++){ if(FieldPtr->FieldDescription){ iLen = FieldPtr->ArraySizeFieldOffset? *(GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT*, StructurePtr, FieldPtr->ArraySizeFieldOffset)): 1;
if(!iLen){ continue; }
if(FieldPtr->byValue){ SubStruct = GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(BYTE*, StructurePtr, FieldPtr->Offset); } else{ SubStruct = GET_STRUCT_MEMBER_BYREF_FROM_OFFSET(BYTE*, StructurePtr, FieldPtr->Offset); }
if(!SubStruct){ continue; }
for(i = 0; i < iLen; i++, SubStruct += FieldPtr->Size){ PersistReleaseMemory(SubStruct, FieldPtr->FieldDescription); }
if(!FieldPtr->byValue){ FreeMem(GET_STRUCT_MEMBER_BYREF_FROM_OFFSET(BYTE*, StructurePtr, FieldPtr->Offset)); } } else{ if(FieldPtr->IsString != NoStr){ SubStruct = (BYTE *)GET_STRUCT_MEMBER_BYREF_FROM_OFFSET(PCSTR, StructurePtr, FieldPtr->Offset); if(SubStruct){ FreeMem(SubStruct); } } } } }
BOOL CompareStructures( IN BYTE * pStructure1, IN BYTE * pStructure2, IN PFIELD_DESCRIPTION FieldsDescription ) { UINT i; UINT iLen1; UINT iLen2; FIELD_DESCRIPTION * FieldPtr; BYTE * pSubStruct1; BYTE * pSubStruct2;
if(!pStructure1 || !pStructure2 || !FieldsDescription){ return FALSE; }
for(FieldPtr = FieldsDescription; FieldPtr->Offset != END_OF_STRUCT; FieldPtr++){ if(FieldPtr->FieldDescription){ iLen1 = FieldPtr->ArraySizeFieldOffset? *(GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT*, pStructure1, FieldPtr->ArraySizeFieldOffset)): 1;
iLen2 = FieldPtr->ArraySizeFieldOffset? *(GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT*, pStructure2, FieldPtr->ArraySizeFieldOffset)): 1;
if(iLen1 != iLen2){ MYASSERT(FALSE); return FALSE; }
if(!iLen1){ continue; }
if(FieldPtr->byValue){ pSubStruct1 = GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(BYTE*, pStructure1, FieldPtr->Offset); pSubStruct2 = GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(BYTE*, pStructure2, FieldPtr->Offset); } else{ pSubStruct1 = GET_STRUCT_MEMBER_BYREF_FROM_OFFSET(BYTE*, pStructure1, FieldPtr->Offset); pSubStruct2 = GET_STRUCT_MEMBER_BYREF_FROM_OFFSET(BYTE*, pStructure2, FieldPtr->Offset); }
if(!pSubStruct1 || !pSubStruct2){ if(pSubStruct1 != pSubStruct2){ MYASSERT(FALSE); return FALSE; } continue; }
for(i = 0; i < iLen1; i++, pSubStruct1 += FieldPtr->Size + GetExtraMemRequirements(pSubStruct1, FieldPtr->FieldDescription), pSubStruct2 += FieldPtr->Size + GetExtraMemRequirements(pSubStruct2, FieldPtr->FieldDescription)){ if(!CompareStructures(pSubStruct1, pSubStruct2, FieldPtr->FieldDescription)){ return FALSE; } } } else{ if(FieldPtr->IsString != NoStr) { pSubStruct1 = GET_STRUCT_MEMBER_BYREF_FROM_OFFSET(BYTE*, pStructure1, FieldPtr->Offset); pSubStruct2 = GET_STRUCT_MEMBER_BYREF_FROM_OFFSET(BYTE*, pStructure2, FieldPtr->Offset); if(!pSubStruct1 || !pSubStruct2){ if(pSubStruct1 != pSubStruct2){ MYASSERT(FALSE); return FALSE; } continue; }
if(FieldPtr->IsString == AnsiStr){ if(strcmp((LPCSTR)pSubStruct1, (LPCSTR)pSubStruct1)){ MYASSERT(FALSE); return FALSE; } } else{ if(wcscmp((LPCWSTR)pSubStruct1, (LPCWSTR)pSubStruct1)){ MYASSERT(FALSE); return FALSE; } } } else{ iLen1 = FieldPtr->ArraySizeFieldOffset? *(GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT*, pStructure1, FieldPtr->ArraySizeFieldOffset)): 1; iLen2 = FieldPtr->ArraySizeFieldOffset? *(GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(UINT*, pStructure2, FieldPtr->ArraySizeFieldOffset)): 1;
if(iLen1 != iLen2){ MYASSERT(FALSE); return FALSE; }
pSubStruct1 = GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(BYTE*, pStructure1, FieldPtr->Offset); pSubStruct2 = GET_STRUCT_MEMBER_BYVALUE_FROM_OFFSET(BYTE*, pStructure2, FieldPtr->Offset); if(memcmp(pSubStruct1, pSubStruct2, iLen1 * FieldPtr->Size)){ MYASSERT(FALSE); return FALSE; } } } } return TRUE; }
|