windows-nt/Source/XPSP1/NT/ds/security/services/ca/certclib/serial.cpp
2020-09-26 16:20:57 +08:00

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);
}