terrafx / terrafx.interop.windows

Interop bindings for Windows.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add safe string methods (StringCch*)

rickbrew opened this issue · comments

I think this is a header-only lib, so it would need to be implemented manually?

I'm not currently using these from managed code, but would still be useful for converting some native code at some point. Not a high priority for me at this time.

For reference, here's what I'm using in my codebase, ported from strafe.h:

public const int STRSAFE_MAX_CCH = 2147483647; // same as INT_MAX
public const int STRSAFE_MAX_LENGTH = STRSAFE_MAX_CCH - 1; // max buffer length, in characters, that we support
public const int STRSAFE_E_INVALID_PARAMETER = unchecked((int)0x80070057); // HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
public const int STRSAFE_E_INSUFFICIENT_BUFFER = unchecked((int)0x8007007A); // HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)

public static HRESULT StringCchCopyW(
    ushort* pszDest,
    nuint cchDest,
    ushort* pszSrc)
{
    HRESULT hr;

    hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);

    if (hr.SUCCEEDED)
    {
        hr = StringCopyWorkerW(
            pszDest,
            cchDest,
            out nuint cchNewDestLength,
            pszSrc,
            STRSAFE_MAX_LENGTH);
    }
    else if (cchDest > 0)
    {
        *pszDest = 0;
    }

    return hr;
}

public static HRESULT StringValidateDestW(
    ushort* pszDest,
    nuint cchDest,
    nuint cchMax)
{
    HRESULT hr = S_OK;

    if ((cchDest == 0) || (cchDest > cchMax))
    {
        hr = STRSAFE_E_INVALID_PARAMETER;
    }

    return hr;
}

public static HRESULT StringCopyWorkerW(
    ushort* pszDest,
    nuint cchDest,
    out nuint cchNewDestLength,
    ushort* pszSrc,
    nuint cchToCopy)
{
    HRESULT hr = S_OK;

    cchNewDestLength = 0;

    while ((cchDest > 0) && (cchToCopy > 0) && (*pszSrc != 0))
    {
        *pszDest = *pszSrc;
        ++pszDest;
        ++pszSrc;
        --cchDest;
        --cchToCopy;
        ++cchNewDestLength;
    }

    if (cchDest == 0)
    {
        // we are going to truncate pszDest
        --pszDest;
        --cchNewDestLength;
        hr = STRSAFE_E_INSUFFICIENT_BUFFER;
    }

    *pszDest = 0;

    return hr;
}