carb/tokens/TokensUtils.h

File members: carb/tokens/TokensUtils.h

// Copyright (c) 2019-2022, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//

#pragma once

#include "../InterfaceUtils.h"
#include "../logging/Log.h"
#include "ITokens.h"

#include <string>
#include <algorithm>

namespace carb
{
namespace tokens
{

inline std::string resolveString(const ITokens* tokens,
                                 const char* str,
                                 ResolveFlags resolveFlags = kResolveFlagNone,
                                 ResolveResult* resolveResult = nullptr)
{
    // Defaulting to an error result thus it's possible to just log an error message and return an empty string if
    // anything goes wrong
    if (resolveResult)
    {
        *resolveResult = ResolveResult::eFailure;
    }

    if (!tokens)
    {
        CARB_LOG_ERROR("Couldn't acquire ITokens interface.");
        return std::string();
    }
    if (!str)
    {
        CARB_LOG_ERROR("Can't resolve a null token string.");
        return std::string();
    }

    const size_t strLen = std::strlen(str);

    ResolveResult resResult;
    size_t resolvedStringSize = tokens->calculateDestinationBufferSize(
        str, strLen, StringEndingMode::eNoNullTerminator, resolveFlags, &resResult);

    if (resResult == ResolveResult::eFailure)
    {
        CARB_LOG_ERROR("Couldn't calculate required buffer size for token resolution of string: %s", str);
        return std::string();
    }

    // Successful resolution to an empty string
    if (resolvedStringSize == 0)
    {
        if (resolveResult)
        {
            *resolveResult = ResolveResult::eSuccess;
        }
        return std::string();
    }

    // C++11 guarantees that strings are continuous in memory
    std::string resolvedString;
    resolvedString.resize(resolvedStringSize);

    const ResolveResult resolveResultLocal =
        tokens->resolveString(str, strLen, &resolvedString.front(), resolvedString.size(),
                              StringEndingMode::eNoNullTerminator, resolveFlags, nullptr);

    if (resolveResultLocal != ResolveResult::eSuccess)
    {
        CARB_LOG_ERROR("Couldn't successfully resolve provided string: %s", str);
        return std::string();
    }

    if (resolveResult)
    {
        *resolveResult = ResolveResult::eSuccess;
    }

    return resolvedString;
}

inline std::string escapeString(const std::string& str)
{
    constexpr char kSpecialChar = '$';
    const size_t countSpecials = std::count(str.begin(), str.end(), kSpecialChar);
    if (!countSpecials)
    {
        return str;
    }

    std::string result;
    result.reserve(str.length() + countSpecials);

    for (char curChar : str)
    {
        result.push_back(curChar);
        if (curChar == kSpecialChar)
        {
            result.push_back(kSpecialChar);
        }
    }
    return result;
}

} // namespace tokens
} // namespace carb