357 lines
6.9 KiB
C++
357 lines
6.9 KiB
C++
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: serial.cpp
|
|
//
|
|
// Contents: serial number string encode/decode implementation
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
#pragma hdrstop
|
|
|
|
|
|
HRESULT
|
|
ObsoleteMultiByteIntegerToWszBuf(
|
|
IN BOOL fOctetString,
|
|
IN DWORD cbIn,
|
|
IN BYTE const *pbIn,
|
|
IN OUT DWORD *pcbOut,
|
|
OPTIONAL OUT WCHAR *pwszOut)
|
|
{
|
|
return MultiByteIntegerToWszBuf(
|
|
fOctetString,
|
|
cbIn,
|
|
pbIn,
|
|
pcbOut,
|
|
pwszOut);
|
|
}
|
|
|
|
HRESULT
|
|
ObsoleteMultiByteIntegerToBstr(
|
|
IN BOOL fOctetString,
|
|
IN DWORD cbIn,
|
|
IN BYTE const *pbIn,
|
|
OUT BSTR *pstrOut)
|
|
{
|
|
return MultiByteIntegerToBstr(
|
|
fOctetString,
|
|
cbIn,
|
|
pbIn,
|
|
pstrOut);
|
|
}
|
|
|
|
BOOL
|
|
AsciiToNibble(
|
|
IN WCHAR wc,
|
|
BYTE *pb)
|
|
{
|
|
BOOL fOk = TRUE;
|
|
|
|
do
|
|
{
|
|
wc -= L'0';
|
|
if (wc <= 9)
|
|
{
|
|
break;
|
|
}
|
|
wc += (WCHAR) (L'0' - L'a' + 10);
|
|
if (wc <= 15)
|
|
{
|
|
break;
|
|
}
|
|
wc += L'a' - L'A';
|
|
if (wc <= 15)
|
|
{
|
|
break;
|
|
}
|
|
fOk = FALSE;
|
|
} while (FALSE);
|
|
|
|
*pb = (BYTE) wc;
|
|
return(fOk);
|
|
}
|
|
|
|
|
|
__inline BOOL
|
|
IsMultiByteSkipChar(
|
|
IN WCHAR wc)
|
|
{
|
|
return(L' ' == wc || L'\t' == wc);
|
|
}
|
|
|
|
|
|
// WszToMultiByteIntegerBuf - convert a big endian null-terminated ascii-hex
|
|
// encoded WCHAR string of even length to a little-endian integer blob.
|
|
// If fOctetString is TRUE, preserve endian order, as in a hex dump
|
|
|
|
HRESULT
|
|
WszToMultiByteIntegerBuf(
|
|
IN BOOL fOctetString,
|
|
IN WCHAR const *pwszIn,
|
|
IN OUT DWORD *pcbOut,
|
|
OPTIONAL OUT BYTE *pbOut)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR const *pwsz;
|
|
DWORD cbOut;
|
|
|
|
cbOut = 0;
|
|
hr = E_INVALIDARG;
|
|
|
|
if (fOctetString)
|
|
{
|
|
for (pwsz = pwszIn; L'\0' != *pwsz; )
|
|
{
|
|
BYTE blo, bhi;
|
|
|
|
while (IsMultiByteSkipChar(*pwsz))
|
|
{
|
|
pwsz++;
|
|
}
|
|
if (!AsciiToNibble(*pwsz, &bhi))
|
|
{
|
|
_JumpError2(
|
|
hr,
|
|
error,
|
|
"WszToMultiByteInteger: bad string",
|
|
E_INVALIDARG);
|
|
}
|
|
pwsz++;
|
|
|
|
while (IsMultiByteSkipChar(*pwsz))
|
|
{
|
|
pwsz++;
|
|
}
|
|
if (!AsciiToNibble(*pwsz, &blo))
|
|
{
|
|
_JumpError(hr, error, "WszToMultiByteInteger: bad string");
|
|
}
|
|
pwsz++;
|
|
|
|
cbOut++;
|
|
if (NULL != pbOut)
|
|
{
|
|
if (cbOut > *pcbOut)
|
|
{
|
|
hr = TYPE_E_BUFFERTOOSMALL;
|
|
_JumpError(hr, error, "WszToMultiByteInteger: overflow");
|
|
}
|
|
*pbOut++ = blo | (bhi << 4);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (pwsz = &pwszIn[wcslen(pwszIn) - 1]; pwsz >= pwszIn; )
|
|
{
|
|
BYTE blo, bhi;
|
|
|
|
while (pwsz >= pwszIn && IsMultiByteSkipChar(*pwsz))
|
|
{
|
|
pwsz--;
|
|
}
|
|
if (pwsz < pwszIn)
|
|
{
|
|
break;
|
|
}
|
|
if (!AsciiToNibble(*pwsz, &blo))
|
|
{
|
|
_JumpError(hr, error, "WszToMultiByteInteger: bad string");
|
|
}
|
|
pwsz--;
|
|
|
|
while (pwsz >= pwszIn && IsMultiByteSkipChar(*pwsz))
|
|
{
|
|
pwsz--;
|
|
}
|
|
if (pwsz < pwszIn || !AsciiToNibble(*pwsz, &bhi))
|
|
{
|
|
_JumpError(hr, error, "WszToMultiByteInteger: bad string");
|
|
}
|
|
pwsz--;
|
|
|
|
cbOut++;
|
|
if (NULL != pbOut)
|
|
{
|
|
if (cbOut > *pcbOut)
|
|
{
|
|
hr = TYPE_E_BUFFERTOOSMALL;
|
|
_JumpError(hr, error, "WszToMultiByteInteger: overflow");
|
|
}
|
|
*pbOut++ = blo | (bhi << 4);
|
|
}
|
|
}
|
|
}
|
|
*pcbOut = cbOut;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// WszToMultiByteInteger - convert a big endian null-terminated ascii-hex
|
|
// encoded WCHAR string of even length to a little-endian integer blob.
|
|
// If fOctetString is TRUE, preserve endian order, as in a hex dump
|
|
|
|
HRESULT
|
|
WszToMultiByteInteger(
|
|
IN BOOL fOctetString,
|
|
IN WCHAR const *pwszIn,
|
|
OUT DWORD *pcbOut,
|
|
OUT BYTE **ppbOut)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
*pcbOut = 0;
|
|
*ppbOut = NULL;
|
|
|
|
while (TRUE)
|
|
{
|
|
hr = WszToMultiByteIntegerBuf(fOctetString, pwszIn, pcbOut, *ppbOut);
|
|
if (S_OK != hr)
|
|
{
|
|
if (NULL != *ppbOut)
|
|
{
|
|
LocalFree(*ppbOut);
|
|
*ppbOut = NULL;
|
|
}
|
|
_JumpError2(hr, error, "WszToMultiByteIntegerBuf", E_INVALIDARG);
|
|
}
|
|
if (NULL != *ppbOut)
|
|
{
|
|
break;
|
|
}
|
|
*ppbOut = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbOut);
|
|
if (NULL == *ppbOut)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
}
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
caTranslateFileTimePeriodToPeriodUnits(
|
|
IN FILETIME const *pftGMT,
|
|
IN BOOL fExact,
|
|
OUT DWORD *pcPeriodUnits,
|
|
OUT PERIODUNITS **prgPeriodUnits)
|
|
{
|
|
HRESULT hr;
|
|
LLFILETIME llft;
|
|
LONGLONG llRemain;
|
|
DWORD i;
|
|
DWORD cPeriodUnits;
|
|
PERIODUNITS *rgPeriodUnits;
|
|
#define IC_YEARS 0
|
|
#define IC_MONTHS 1
|
|
#define IC_WEEKS 2
|
|
#define IC_DAYS 3
|
|
#define IC_HOURS 4
|
|
#define IC_MINUTES 5
|
|
#define IC_SECONDS 6
|
|
#define IC_MAX 7
|
|
LONG alCount[IC_MAX];
|
|
static const enum ENUM_PERIOD s_aenumPeriod[] =
|
|
{
|
|
ENUM_PERIOD_YEARS,
|
|
ENUM_PERIOD_MONTHS,
|
|
ENUM_PERIOD_WEEKS,
|
|
ENUM_PERIOD_DAYS,
|
|
ENUM_PERIOD_HOURS,
|
|
ENUM_PERIOD_MINUTES,
|
|
ENUM_PERIOD_SECONDS,
|
|
};
|
|
|
|
llft.ft = *pftGMT;
|
|
if (0 <= llft.ll)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Not a time period");
|
|
}
|
|
llft.ll = -llft.ll;
|
|
llft.ll /= CVT_BASE; // now in seconds
|
|
|
|
ZeroMemory(alCount, sizeof(alCount));
|
|
alCount[IC_DAYS] = (LONG) (llft.ll / (60 * 60 * 24));
|
|
|
|
llRemain = llft.ll - (LONGLONG) alCount[IC_DAYS] * (60 * 60 * 24);
|
|
if (fExact || 4 > alCount[IC_DAYS]) // if less than 96 hrs
|
|
{
|
|
alCount[IC_HOURS] = (LONG) llRemain / (60 * 60);
|
|
if (fExact || 2 > alCount[IC_HOURS]) // if less than 120 mins
|
|
{
|
|
alCount[IC_MINUTES] = ((LONG) llRemain / 60) % 60;
|
|
if (fExact || 2 > alCount[IC_MINUTES]) // if less than 120 secs
|
|
{
|
|
alCount[IC_SECONDS] = (LONG) llRemain % 60;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 != alCount[IC_DAYS])
|
|
{
|
|
if (0 == (alCount[IC_DAYS] % 365))
|
|
{
|
|
alCount[IC_YEARS] = alCount[IC_DAYS] / 365;
|
|
alCount[IC_DAYS] = 0;
|
|
}
|
|
else if (0 == (alCount[IC_DAYS] % 30))
|
|
{
|
|
alCount[IC_MONTHS] = alCount[IC_DAYS] / 30;
|
|
alCount[IC_DAYS] = 0;
|
|
}
|
|
else if (0 == (alCount[IC_DAYS] % 7))
|
|
{
|
|
alCount[IC_WEEKS] = alCount[IC_DAYS] / 7;
|
|
alCount[IC_DAYS] = 0;
|
|
}
|
|
}
|
|
cPeriodUnits = 0;
|
|
for (i = 0; i < IC_MAX; i++)
|
|
{
|
|
if (0 != alCount[i])
|
|
{
|
|
cPeriodUnits++;
|
|
}
|
|
}
|
|
if (0 == cPeriodUnits)
|
|
{
|
|
cPeriodUnits++;
|
|
}
|
|
rgPeriodUnits = (PERIODUNITS *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
cPeriodUnits * sizeof(rgPeriodUnits[0]));
|
|
if (NULL == rgPeriodUnits)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
*pcPeriodUnits = cPeriodUnits;
|
|
*prgPeriodUnits = rgPeriodUnits;
|
|
|
|
cPeriodUnits = 0;
|
|
for (i = 0; i < IC_MAX; i++)
|
|
{
|
|
if (0 != alCount[i] || (0 == cPeriodUnits && i + 1 == IC_MAX))
|
|
{
|
|
rgPeriodUnits[cPeriodUnits].lCount = alCount[i];
|
|
rgPeriodUnits[cPeriodUnits].enumPeriod = s_aenumPeriod[i];
|
|
cPeriodUnits++;
|
|
}
|
|
}
|
|
CSASSERT(cPeriodUnits == *pcPeriodUnits);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|