📄 datatype.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
* @(#)DataType.cpp 1.0 6/11/98
*
*/
#include <windows.h>
#include <ctype.h>
#include "assert.h"
#include "datatype.hxx"
#define TRY
#define CATCH if(0)
#define ENDTRY
#define ERESULT_NOINFO E_FAIL
// SkipWhiteSpace
const WCHAR *
SkipWhiteSpace(const WCHAR * pS, int cch)
{
while (cch-- && iswspace(*pS))
pS++;
return pS;
}
// ParseDecimal
static
const WCHAR *
ParseDecimal(const WCHAR * pS, int cch, DWORD * pdw)
{
WCHAR c;
DWORD dw = 0;
while (cch-- && iswdigit(c = *pS))
{
dw = dw * 10 + (c - _T('0'));
pS++;
if (dw >= ((0xffffffff) / 10 - 9)) // Check for overflow
break;
}
*pdw = dw;
return pS;
}
// ParseBinHex
HRESULT
ParseBinHex( const WCHAR * pS, long lLen,
BYTE * abData, int * pcbSize,
const WCHAR ** ppwcNext)
{
WCHAR wc;
bool fLow = false;
const WCHAR * pwc = pS;
BYTE bByte;
byte result;
// fake a leading zero
if ( lLen % 2 != 0)
{
bByte = 0;
fLow = true;
}
*pcbSize = (lLen + 1) >> 1; // divide in 1/2 with round up
// walk hex digits pairing them up and shoving the value of each pair into a byte
while ( lLen-- > 0)
{
wc = *pwc++;
if (wc >= L'a' && wc <= L'f')
{
result = 10 + (wc - L'a');
}
else if (wc >= L'A' && wc <= L'F')
{
result = 10 + (wc - L'A');
}
else if (wc >= L'0' && wc <= L'9')
{
result = wc - L'0';
}
else if (iswspace(wc))
{
continue; // skip whitespace
}
else
{
goto Error;
}
assert((0 <= result) && (result < 16));
if ( fLow)
{
bByte += (BYTE)result;
*abData++ = bByte;
fLow = false;
}
else
{
// shift nibble into top half of byte
bByte = (BYTE)(result << 4);
fLow = true;
}
}
//Cleanup:
if (ppwcNext)
*ppwcNext = pwc;
return S_OK;
Error:
return E_FAIL;
}
// ParseISO8601
HRESULT
ParseISO8601(const WCHAR * pS, int cch,
DataType dt, DATE * pdate,
const WCHAR ** ppwcNext)
{
HRESULT hr = S_OK;
UDATE udate;
const WCHAR * pN;
union { // enforce 64-bit alignment of ftTime
FILETIME ftTime;
__int64 __unused000;
};
__int64 i64Offset;
int iSign = 0;
DWORD dw;
const WCHAR * pSStart = pS;
// make sure the enums are ordered according to logic below
assert(DT_DATE_ISO8601 < DT_DATETIME_ISO8601 &&
DT_DATETIME_ISO8601 < DT_DATETIME_ISO8601TZ &&
DT_DATETIME_ISO8601TZ < DT_TIME_ISO8601 &&
DT_TIME_ISO8601 < DT_TIME_ISO8601TZ);
memset(&udate, 0, sizeof(udate));
udate.st.wMonth = 1;
udate.st.wDay = 1;
pS = SkipWhiteSpace(pS, cch);
cch -= (int)(pS - pSStart);
// parse date if allowed
if (dt < DT_TIME_ISO8601)
{
pN = ParseDecimal(pS, cch, &dw);
if (pN - pS != 4) // 4 digits
goto Error;
// HACK: VarDateFromUdate treats 2digit years specially, for y2k compliance
if (dw < 100)
goto Error;
udate.st.wYear = (WORD) dw;
cch -= 4;
pS = pN;
if (*pS == _T('-'))
{
pN = ParseDecimal(pS + 1, --cch, &dw);
if (pN - pS != 3 || 0 == dw || dw > 12) // 2 digits + '-'
goto Error;
udate.st.wMonth = (WORD) dw;
cch -= 2;
pS = pN;
if (*pS == _T('-'))
{
pN = ParseDecimal(pS + 1, --cch, &dw);
if (pN - pS != 3 || 0 == dw || dw > 31) // 2 digits + '-'
goto Error;
udate.st.wDay = (WORD) dw;
cch -= 2;
pS = pN;
}
}
if (cch && dt >= DT_DATETIME_ISO8601)
{
// swallow T
// Assume starts with T ?
if (*pS != _T('T'))
goto Error;
pS++;
cch--;
}
}
else
{
udate.st.wYear = 1899;
udate.st.wMonth = 12;
udate.st.wDay = 30;
}
// parse time if allowed
if (cch && dt >= DT_DATETIME_ISO8601)
{
pN = ParseDecimal(pS, cch, &dw);
if (pN - pS != 2 || dw > 24) // 2 digits + 'T'
goto Error;
udate.st.wHour = (WORD) dw;
cch -= 2;
pS = pN;
if (*pS == _T(':'))
{
pN = ParseDecimal(pS + 1, --cch, &dw);
if (pN - pS != 3 || dw > 59) // 2 digits + ':'
goto Error;
udate.st.wMinute = (WORD) dw;
cch -= 2;
pS = pN;
if (*pS == _T(':'))
{
pN = ParseDecimal(pS + 1, --cch, &dw);
if (pN - pS != 3 || dw > 59) // 2 digits + ':'
goto Error;
udate.st.wSecond = (WORD) dw;
cch -= 2;
pS = pN;
if (*pS == _T('.'))
{
pN = ParseDecimal(pS + 1, --cch, &dw);
int d = (int)(3 - (pN - (pS + 1)));
if (d > 2 || dw > 999999999) // at least 1 digit, not more than 9 digits
goto Error;
cch -= (int)(pN - pS - 1);
pS = pN;
while (d > 0)
{
dw *= 10;
d--;
}
while (d < 0)
{
dw /= 10;
d++;
}
udate.st.wMilliseconds = (WORD) dw;
}
}
}
// watch for 24:01... etc
if (udate.st.wHour == 24 && (udate.st.wMinute > 0 || udate.st.wSecond > 0 || udate.st.wMilliseconds > 0))
goto Error;
// parse timezone if allowed
if (cch && (dt == DT_DATETIME_ISO8601TZ || dt == DT_TIME_ISO8601TZ))
{
if (*pS == _T('+'))
iSign = 1;
else if (*pS == _T('-'))
iSign = -1;
else if (*pS == _T('Z'))
{
pS++;
cch--;
}
if (iSign)
{
if (!SystemTimeToFileTime(&udate.st, &ftTime))
goto Error;
pN = ParseDecimal(pS + 1, --cch, &dw);
if (pN - pS != 3) // 2 digits + '+' or '-'
goto Error;
i64Offset = (__int64)dw;
cch -= 2;
pS = pN;
if (*pS != ':')
goto Error;
pN = ParseDecimal(pS + 1, --cch, &dw);
if (pN - pS != 3) // 2 digits + ':'
goto Error;
cch -= 2;
pS = pN;
// convert to 100 nanoseconds
i64Offset = 10000000 * 60 * ((__int64)dw + 60 * i64Offset);
*(__int64 *)&ftTime = *(__int64 *)&ftTime + iSign * i64Offset;
if (!FileTimeToSystemTime(&ftTime, &udate.st))
goto Error;
}
}
}
hr = VarDateFromUdate(&udate, 0, pdate);
if (FAILED(hr))
goto Cleanup;
Cleanup:
if (ppwcNext)
*ppwcNext = pS;
return hr;
Error:
hr = E_FAIL;
goto Cleanup;
}
HRESULT
UnparseDecimal( ce::wstring * pSBuffer, WORD num, long digits)
{
HRESULT hr = S_OK;
unsigned short digit;
unsigned short place = 1;
// since num is WORD == 16bits, we are better off useing ushort-s above...
if ( digits > 5)
{
hr = E_INVALIDARG;
goto Cleanup;
}
// start with the most significant digit
while( --digits) place *= 10;
// for each digit, pull the digit out of num and store it in the string buffer
while ( place > 0)
{
digit = num/place;
if (digit > 9)
{
hr = E_INVALIDARG;
goto Cleanup;
}
pSBuffer->append(_T('0') + digit);
num -= digit*place;
place /= 10;
}
Cleanup:
return hr;
}
HRESULT
UnparseISO8601( ce::wstring * pReturn, DataType dt, const DATE * pdate)
{
HRESULT hr = S_OK;
UDATE udate;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -