How to: Parse a Stream from a Binary Property to Read the TZDEFINITION Structure

How to: Parse a Stream from a Binary Property to Read the TZDEFINITION Structure

This topic shows how to read the TZDEFINITION structure from the persisted format stored in a binary property.

  TZDEFINITION* BinToTZDEFINITION(ULONG cbDef, LPBYTE lpbDef)
{
    if (!lpbDef) return NULL;
// Update this if parsing code is changed.
// This checks the size up to the flag member.
if (cbDef < 2*sizeof(BYTE) + 2*sizeof(WORD)) return NULL;

TZDEFINITION tzDef = {0};
TZRULE* lpRules = NULL;
LPBYTE lpPtr = lpbDef;
WORD cchKeyName = NULL;
WCHAR* szKeyName = NULL;
WORD i = 0;

BYTE bMajorVersion = *((BYTE*)lpPtr);
lpPtr += sizeof(BYTE);
BYTE bMinorVersion = *((BYTE*)lpPtr);
lpPtr += sizeof(BYTE);

// We only understand TZ_BIN_VERSION_MAJOR
if (TZ_BIN_VERSION_MAJOR != bMajorVersion) return NULL;

// We only understand if >= TZ_BIN_VERSION_MINOR
if (TZ_BIN_VERSION_MINOR > bMinorVersion) return NULL;

lpPtr += sizeof(WORD);

tzDef.wFlags = *((WORD*)lpPtr);
lpPtr += sizeof(WORD);

if (TZDEFINITION_FLAG_VALID_GUID & tzDef.wFlags)
{
    if (lpbDef + cbDef - lpPtr < sizeof(GUID)) return NULL;
    tzDef.guidTZID = *((GUID*)lpPtr);
    lpPtr += sizeof(GUID);
}

if (TZDEFINITION_FLAG_VALID_KEYNAME & tzDef.wFlags)
{
    if (lpbDef + cbDef - lpPtr < sizeof(WORD)) return NULL;
    cchKeyName = *((WORD*)lpPtr);
    lpPtr += sizeof(WORD);
    if (cchKeyName)
    {
        if (lpbDef + cbDef - lpPtr < (BYTE)sizeof(WORD)*cchKeyName) return NULL;
        szKeyName = (WCHAR*)lpPtr;
        lpPtr += cchKeyName*sizeof(WORD);
    }
}

if (lpbDef+ cbDef - lpPtr < sizeof(WORD)) return NULL;
tzDef.cRules = *((WORD*)lpPtr);
lpPtr += sizeof(WORD);
if (tzDef.cRules)
{
    lpRules = new TZRULE[tzDef.cRules];
    if (!lpRules) return NULL;

    LPBYTE lpNextRule = lpPtr;
    BOOL bRuleOK = false;
	
    for (i = 0;i < tzDef.cRules;i++)
    {
        bRuleOK = false;
        lpPtr = lpNextRule;
		
        if (lpbDef + cbDef - lpPtr < 
            2*sizeof(BYTE) + 2*sizeof(WORD) + 3*sizeof(long) + 2*sizeof(SYSTEMTIME)) return NULL;
        bRuleOK = true;
        BYTE bRuleMajorVersion = *((BYTE*)lpPtr);
        lpPtr += sizeof(BYTE);
        BYTE bRuleMinorVersion = *((BYTE*)lpPtr);
        lpPtr += sizeof(BYTE);
		
        // We only understand TZ_BIN_VERSION_MAJOR
        if (TZ_BIN_VERSION_MAJOR != bRuleMajorVersion) return NULL;
		
        // We only understand if >= TZ_BIN_VERSION_MINOR
        if (TZ_BIN_VERSION_MINOR > bRuleMinorVersion) return NULL;
		
        WORD cbRule = *((WORD*)lpPtr);
        lpPtr += sizeof(WORD);
		
        lpNextRule = lpPtr + cbRule;
		
        lpRules[i].wFlags = *((WORD*)lpPtr);
        lpPtr += sizeof(WORD);
		
        lpRules[i].stStart = *((SYSTEMTIME*)lpPtr);
        lpPtr += sizeof(SYSTEMTIME);
		
        lpRules[i].TZReg.lBias = *((long*)lpPtr);
        lpPtr += sizeof(long);
        lpRules[i].TZReg.lStandardBias = *((long*)lpPtr);
        lpPtr += sizeof(long);
        lpRules[i].TZReg.lDaylightBias = *((long*)lpPtr);
        lpPtr += sizeof(long);
		
        lpRules[i].TZReg.stStandardDate = *((SYSTEMTIME*)lpPtr);
        lpPtr += sizeof(SYSTEMTIME);
        lpRules[i].TZReg.stDaylightDate = *((SYSTEMTIME*)lpPtr);
        lpPtr += sizeof(SYSTEMTIME);
    }
    if (!bRuleOK)
    {
        delete[] lpRules;
        return NULL;			
    }
}

// After everything is read, allocate a structure and copy it in
size_t cbTZDef = sizeof(TZDEFINITION) +
    sizeof(WCHAR)*(cchKeyName+1) +
    sizeof(TZRULE)*tzDef.cRules;

TZDEFINITION* ptzDef = (TZDEFINITION*) new BYTE[cbTZDef];

if (ptzDef)
{
    // Copy main struct over
    *ptzDef = tzDef;
    lpPtr = (LPBYTE) ptzDef;
    lpPtr += sizeof(TZDEFINITION);

    if (szKeyName)
    {
        ptzDef->pwszKeyName = (WCHAR*)lpPtr;
        memcpy(lpPtr,szKeyName,cchKeyName*sizeof(WCHAR));
        ptzDef->pwszKeyName[cchKeyName] = 0;

        lpPtr += (cchKeyName+1)*sizeof(WCHAR);
    }

    if (ptzDef -> cRules && lpRules)
    {
        ptzDef -> rgRules = (TZRULE*)lpPtr;
        for (i = 0;i < ptzdef -> cRules;i++)
        {
            ptzDef -> rgRules[i] = lpRules[i];
        }
    }
}

// Clean up lpRules
delete[] lpRules;

return ptzDef;

}

See Also

About Persisting TZDEFINITION to a Stream to Commit to a Binary Property

How to: Read Time Zone Properties from an Appointment