HRESULT VersionRange::ParseVersionString()

in src/vswhere.lib/VersionRange.cpp [192:262]


HRESULT VersionRange::ParseVersionString(
    _In_ const LPCWSTR pwszVersionBegin,
    _In_ const LPCWSTR pwszVersionEnd,
    _Out_ PULONGLONG pullVersion
)
{
    _ASSERT(pwszVersionBegin);
    _ASSERT(pwszVersionEnd);
    _ASSERT(pullVersion);

    HRESULT hr = S_OK;
    LPWSTR pwszFieldBegin = const_cast<LPWSTR>(pwszVersionBegin);
    LPWSTR pwszFieldEnd = const_cast<LPWSTR>(pwszVersionBegin);
    WORD cFields = 0;
    ULONG ulField = 0;
    ULONGLONG ullVersion = 0;

    *pullVersion = 0;

    for (;;)
    {
        if (4 <= cFields)
        {
            ExitOnFailure(hr = E_INVALIDARG, "Too many version fields.");
        }

        while (pwszFieldEnd < pwszVersionEnd && L'.' != *pwszFieldEnd)
        {
            if (isspace(*pwszFieldEnd, neutral_locale))
            {
                ExitOnFailure(hr = E_INVALIDARG, "Space in version field.");
            }

            ++pwszFieldEnd;
        }

        if (pwszFieldBegin == pwszFieldEnd)
        {
            ExitOnFailure(hr = E_INVALIDARG, "Empty version field.");
        }

        LPWSTR pwszEnd = NULL;
        ulField = ::wcstoul(pwszFieldBegin, &pwszEnd, 10);

        if (USHRT_MAX < ulField)
        {
            ExitOnFailure(hr = E_INVALIDARG, "Version field too large.");
        }
        else if (0 == ulField && pwszEnd != pwszFieldEnd)
        {
            ExitOnFailure(hr = E_INVALIDARG, "NaN");
        }

        pwszFieldEnd = pwszEnd;

        ullVersion |= (ULONGLONG)ulField << ((3 - cFields) * 16);
        ++cFields;

        if (pwszFieldEnd >= pwszVersionEnd)
        {
            break;
        }

        pwszFieldBegin = ++pwszFieldEnd;
    }

    *pullVersion = ullVersion;

Exit:
    return hr;
}