// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//*****************************************************************************
// NamespaceUtil.cpp
//
//
// Helpers for converting namespace separators.
//
//*****************************************************************************
#include "stdafx.h"
#include "corhdr.h"
#include "corhlpr.h"
#include "sstring.h"
#include "utilcode.h"
#ifndef _ASSERTE
#define _ASSERTE(foo)
#endif
#include "nsutilpriv.h"
//*****************************************************************************
// Determine how many chars large a fully qualified name would be given the
// two parts of the name. The return value includes room for every character
// in both names, as well as room for the separator and a final terminator.
//*****************************************************************************
int ns::GetFullLength( // Number of chars in full name.
const WCHAR *szNameSpace, // Namspace for value.
const WCHAR *szName) // Name of value.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
int iLen = 1; // Null terminator.
if (szNameSpace)
iLen += (int)wcslen(szNameSpace);
if (szName)
iLen += (int)wcslen(szName);
if (szNameSpace && *szNameSpace && szName && *szName)
++iLen;
return iLen;
} //int ns::GetFullLength()
int ns::GetFullLength( // Number of chars in full name.
LPCUTF8 szNameSpace, // Namspace for value.
LPCUTF8 szName) // Name of value.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
int iLen = 1;
if (szNameSpace)
iLen += (int)strlen(szNameSpace);
if (szName)
iLen += (int)strlen(szName);
if (szNameSpace && *szNameSpace && szName && *szName)
++iLen;
return iLen;
} //int ns::GetFullLength()
//*****************************************************************************
// Scan the string from the rear looking for the first valid separator. If
// found, return a pointer to it. Else return null. This code is smart enough
// to skip over special sequences, such as:
// a.b..ctor
// ^
// |
// The ".ctor" is considered one token.
//*****************************************************************************
WCHAR *ns::FindSep( // Pointer to separator or null.
const WCHAR *szPath) // The path to look in.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
_ASSERTE(szPath);
WCHAR *ptr = (WCHAR*)wcsrchr(szPath, NAMESPACE_SEPARATOR_WCHAR);
if((ptr == NULL) || (ptr == szPath)) return NULL;
if(*(ptr - 1) == NAMESPACE_SEPARATOR_WCHAR) // here ptr is at least szPath+1
--ptr;
return ptr;
} //WCHAR *ns::FindSep()
//@todo: this isn't dbcs safe if this were ansi, but this is utf8. Still an issue?
LPUTF8 ns::FindSep( // Pointer to separator or null.
LPCUTF8 szPath) // The path to look in.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
STATIC_CONTRACT_SUPPORTS_DAC;
_ASSERTE(szPath);
LPUTF8 ptr = const_cast(strrchr(szPath, NAMESPACE_SEPARATOR_CHAR));
if((ptr == NULL) || (ptr == szPath)) return NULL;
if(*(ptr - 1) == NAMESPACE_SEPARATOR_CHAR) // here ptr is at least szPath+1
--ptr;
return ptr;
} //LPUTF8 ns::FindSep()
//*****************************************************************************
// Take a path and find the last separator (nsFindSep), and then replace the
// separator with a '\0' and return a pointer to the name. So for example:
// a.b.c
// becomes two strings "a.b" and "c" and the return value points to "c".
//*****************************************************************************
WCHAR *ns::SplitInline( // Pointer to name portion.
__inout __inout_z WCHAR *szPath) // The path to split.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
WCHAR *ptr = ns::FindSep(szPath);
if (ptr)
{
*ptr = 0;
++ptr;
}
return ptr;
} // WCHAR *ns::SplitInline()
LPUTF8 ns::SplitInline( // Pointer to name portion.
__inout __inout_z LPUTF8 szPath) // The path to split.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
LPUTF8 ptr = ns::FindSep(szPath);
if (ptr)
{
*ptr = 0;
++ptr;
}
return ptr;
} // LPUTF8 ns::SplitInline()
void ns::SplitInline(
__inout __inout_z LPWSTR szPath, // Path to split.
LPCWSTR &szNameSpace, // Return pointer to namespace.
LPCWSTR &szName) // Return pointer to name.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
WCHAR *ptr = SplitInline(szPath);
if (ptr)
{
szNameSpace = szPath;
szName = ptr;
}
else
{
szNameSpace = 0;
szName = szPath;
}
} // void ns::SplitInline()
void ns::SplitInline(
__inout __inout_z LPUTF8 szPath, // Path to split.
LPCUTF8 &szNameSpace, // Return pointer to namespace.
LPCUTF8 &szName) // Return pointer to name.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
LPUTF8 ptr = SplitInline(szPath);
if (ptr)
{
szNameSpace = szPath;
szName = ptr;
}
else
{
szNameSpace = 0;
szName = szPath;
}
} // void ns::SplitInline()
//*****************************************************************************
// Split the last parsable element from the end of the string as the name,
// the first part as the namespace.
//*****************************************************************************
int ns::SplitPath( // true ok, false trunction.
const WCHAR *szPath, // Path to split.
__out_ecount(cchNameSpace) WCHAR *szNameSpace, // Output for namespace value.
int cchNameSpace, // Max chars for output.
__out_ecount(cchName) WCHAR *szName, // Output for name.
int cchName) // Max chars for output.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
const WCHAR *ptr = ns::FindSep(szPath);
size_t iLen = (ptr) ? ptr - szPath : 0;
size_t iCopyMax;
int brtn = true;
if (szNameSpace && cchNameSpace)
{
_ASSERTE(cchNameSpace > 1);
iCopyMax = cchNameSpace - 1;
iCopyMax = min(iCopyMax, iLen);
wcsncpy_s(szNameSpace, cchNameSpace, szPath, iCopyMax);
szNameSpace[iCopyMax] = 0;
if (iLen >= (size_t)cchNameSpace)
brtn = false;
}
if (szName && cchName)
{
_ASSERTE(cchName > 1);
iCopyMax = cchName - 1;
if (ptr)
++ptr;
else
ptr = szPath;
iLen = (int)wcslen(ptr);
iCopyMax = min(iCopyMax, iLen);
wcsncpy_s(szName, cchName, ptr, iCopyMax);
szName[iCopyMax] = 0;
if (iLen >= (size_t)cchName)
brtn = false;
}
return brtn;
} // int ns::SplitPath()
int ns::SplitPath( // true ok, false trunction.
LPCUTF8 szPath, // Path to split.
__out_ecount_opt (cchNameSpace) LPUTF8 szNameSpace, // Output for namespace value.
int cchNameSpace, // Max chars for output.
__out_ecount_opt (cchName) LPUTF8 szName, // Output for name.
int cchName) // Max chars for output.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
LPCUTF8 ptr = ns::FindSep(szPath);
size_t iLen = (ptr) ? ptr - szPath : 0;
size_t iCopyMax;
int brtn = true;
if (szNameSpace && cchNameSpace)
{
_ASSERTE(cchNameSpace > 1);
iCopyMax = cchNameSpace-1;
iCopyMax = min(iCopyMax, iLen);
strncpy_s(szNameSpace, cchNameSpace, szPath, iCopyMax);
szNameSpace[iCopyMax] = 0;
if (iLen >= (size_t)cchNameSpace)
brtn = false;
}
if (szName && cchName)
{
_ASSERTE(cchName > 1);
iCopyMax = cchName-1;
if (ptr)
++ptr;
else
ptr = szPath;
iLen = (int)strlen(ptr);
iCopyMax = min(iCopyMax, iLen);
strncpy_s(szName, cchName, ptr, iCopyMax);
szName[iCopyMax] = 0;
if (iLen >= (size_t)cchName)
brtn = false;
}
return brtn;
} // int ns::SplitPath()
//*****************************************************************************
// Take two values and put them together in a fully qualified path using the
// correct separator.
//*****************************************************************************
int ns::MakePath( // true ok, false truncation.
__out_ecount(cchChars) WCHAR *szOut, // output path for name.
int cchChars, // max chars for output path.
const WCHAR *szNameSpace, // Namespace.
const WCHAR *szName) // Name.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
if (cchChars < 1)
return false;
if (szOut)
*szOut = 0;
else
return false;
if (szNameSpace && *szNameSpace != W('\0'))
{
if (wcsncpy_s(szOut, cchChars, szNameSpace, _TRUNCATE) == STRUNCATE)
return false;
// Add namespace separator if a non-empty name was supplied
if (szName && *szName != W('\0'))
{
if (wcsncat_s(szOut, cchChars, NAMESPACE_SEPARATOR_WSTR, _TRUNCATE) == STRUNCATE)
{
return false;
}
}
}
if (szName && *szName)
{
if (wcsncat_s(szOut, cchChars, szName, _TRUNCATE) == STRUNCATE)
return false;
}
return true;
} // int ns::MakePath()
int ns::MakePath( // true ok, false truncation.
__out_ecount(cchChars) LPUTF8 szOut, // output path for name.
int cchChars, // max chars for output path.
LPCUTF8 szNameSpace, // Namespace.
LPCUTF8 szName) // Name.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
if (cchChars < 1)
return false;
if (szOut)
*szOut = 0;
else
return false;
if (szNameSpace && *szNameSpace != W('\0'))
{
if (strncpy_s(szOut, cchChars, szNameSpace, _TRUNCATE) == STRUNCATE)
return false;
// Add namespace separator if a non-empty name was supplied
if (szName && *szName != W('\0'))
{
if (strncat_s(szOut, cchChars, NAMESPACE_SEPARATOR_STR, _TRUNCATE) == STRUNCATE)
{
return false;
}
}
}
if (szName && *szName)
{
if (strncat_s(szOut, cchChars, szName, _TRUNCATE) == STRUNCATE)
return false;
}
return true;
} // int ns::MakePath()
int ns::MakePath( // true ok, false truncation.
__out_ecount(cchChars) WCHAR *szOut, // output path for name.
int cchChars, // max chars for output path.
LPCUTF8 szNamespace, // Namespace.
LPCUTF8 szName) // Name.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
if (cchChars < 1)
return false;
if (szOut)
*szOut = 0;
else
return false;
if (szNamespace != NULL && *szNamespace != '\0')
{
if (cchChars < 2)
return false;
int count;
// We use cBuffer - 2 to account for the '.' and at least a 1 character name below.
count = WszMultiByteToWideChar(CP_UTF8, 0, szNamespace, -1, szOut, cchChars-2);
if (count == 0)
return false; // Supply a bigger buffer!
// buffer access is bounded: WszMultiByteToWideChar returns 0 if access doesn't fit in range
#ifdef _PREFAST_
#pragma warning( suppress: 26015 )
#endif
szOut[count-1] = NAMESPACE_SEPARATOR_WCHAR;
szOut += count;
cchChars -= count;
}
if (((cchChars == 0) && (szName != NULL) && (*szName != '\0')) ||
(WszMultiByteToWideChar(CP_UTF8, 0, szName, -1, szOut, cchChars) == 0))
return false; // supply a bigger buffer!
return true;
} // int ns::MakePath()
int ns::MakePath( // true ok, false out of memory
CQuickBytes &qb, // Where to put results.
LPCUTF8 szNameSpace, // Namespace for name.
LPCUTF8 szName) // Final part of name.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FAULT;
int iLen = 2;
if (szNameSpace)
iLen += (int)strlen(szNameSpace);
if (szName)
iLen += (int)strlen(szName);
LPUTF8 szOut = (LPUTF8) qb.AllocNoThrow(iLen);
if (!szOut)
return false;
return ns::MakePath(szOut, iLen, szNameSpace, szName);
} // int ns::MakePath()
int ns::MakePath( // true ok, false out of memory
CQuickArray &qa, // Where to put results.
LPCUTF8 szNameSpace, // Namespace for name.
LPCUTF8 szName) // Final part of name.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FAULT;
int iLen = 2;
if (szNameSpace)
iLen += (int)strlen(szNameSpace);
if (szName)
iLen += (int)strlen(szName);
WCHAR *szOut = (WCHAR *) qa.AllocNoThrow(iLen);
if (!szOut)
return false;
return ns::MakePath(szOut, iLen, szNameSpace, szName);
} // int ns::MakePath()
int ns::MakePath( // true ok, false out of memory
CQuickBytes &qb, // Where to put results.
const WCHAR *szNameSpace, // Namespace for name.
const WCHAR *szName) // Final part of name.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FAULT;
int iLen = 2;
if (szNameSpace)
iLen += (int)wcslen(szNameSpace);
if (szName)
iLen += (int)wcslen(szName);
WCHAR *szOut = (WCHAR *) qb.AllocNoThrow(iLen * sizeof(WCHAR));
if (!szOut)
return false;
return ns::MakePath(szOut, iLen, szNameSpace, szName);
} // int ns::MakePath()
void ns::MakePath( // throws on out of memory
SString &ssBuf, // Where to put results.
const SString &ssNameSpace, // Namespace for name.
const SString &ssName) // Final part of name.
{
STATIC_CONTRACT_THROWS;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FAULT;
ssBuf.Clear();
if (!ssNameSpace.IsEmpty())
{
if (ssName.IsEmpty())
{
ssBuf.Set(ssNameSpace);
}
else
{
SString s(SString::Literal, NAMESPACE_SEPARATOR_WSTR);
ssBuf.Set(ssNameSpace, s);
}
}
if (!ssName.IsEmpty())
{
ssBuf.Append(ssName);
}
}
bool ns::MakeAssemblyQualifiedName( // true ok, false truncation
__out_ecount(dwBuffer) WCHAR* pBuffer, // Buffer to recieve the results
int dwBuffer, // Number of characters total in buffer
const WCHAR *szTypeName, // Namespace for name.
int dwTypeName, // Number of characters (not including null)
const WCHAR *szAssemblyName, // Final part of name.
int dwAssemblyName) // Number of characters (not including null)
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
if (dwBuffer < 2)
return false;
int iCopyMax = 0;
_ASSERTE(pBuffer);
*pBuffer = NULL;
if (szTypeName && *szTypeName != W('\0'))
{
_ASSERTE(dwTypeName > 0);
iCopyMax = min(dwBuffer-1, dwTypeName);
wcsncpy_s(pBuffer, dwBuffer, szTypeName, iCopyMax);
dwBuffer -= iCopyMax;
}
if (szAssemblyName && *szAssemblyName != W('\0'))
{
if(dwBuffer < ASSEMBLY_SEPARATOR_LEN)
return false;
for(DWORD i = 0; i < ASSEMBLY_SEPARATOR_LEN; i++)
pBuffer[iCopyMax+i] = ASSEMBLY_SEPARATOR_WSTR[i];
dwBuffer -= ASSEMBLY_SEPARATOR_LEN;
if(dwBuffer == 0)
return false;
int iCur = iCopyMax + ASSEMBLY_SEPARATOR_LEN;
_ASSERTE(dwAssemblyName > 0);
iCopyMax = min(dwBuffer-1, dwAssemblyName);
wcsncpy_s(pBuffer + iCur, dwBuffer, szAssemblyName, iCopyMax);
pBuffer[iCur + iCopyMax] = W('\0');
if (iCopyMax < dwAssemblyName)
return false;
}
else {
if(dwBuffer == 0) {
PREFIX_ASSUME(iCopyMax > 0);
pBuffer[iCopyMax-1] = W('\0');
return false;
}
else
pBuffer[iCopyMax] = W('\0');
}
return true;
} // int ns::MakePath()
bool ns::MakeAssemblyQualifiedName( // true ok, false out of memory
CQuickBytes &qb, // Where to put results.
const WCHAR *szTypeName, // Namespace for name.
const WCHAR *szAssemblyName) // Final part of name.
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FAULT;
int iTypeName = 0;
int iAssemblyName = 0;
if (szTypeName)
iTypeName = (int)wcslen(szTypeName);
if (szAssemblyName)
iAssemblyName = (int)wcslen(szAssemblyName);
int iLen = ASSEMBLY_SEPARATOR_LEN + iTypeName + iAssemblyName + 1; // Space for null terminator
WCHAR *szOut = (WCHAR *) qb.AllocNoThrow(iLen * sizeof(WCHAR));
if (!szOut)
return false;
bool ret;
ret = ns::MakeAssemblyQualifiedName(szOut, iLen, szTypeName, iTypeName, szAssemblyName, iAssemblyName);
_ASSERTE(ret);
return true;
}
int ns::MakeNestedTypeName( // true ok, false out of memory
CQuickBytes &qb, // Where to put results.
LPCUTF8 szEnclosingName, // Full name for enclosing type
LPCUTF8 szNestedName) // Full name for nested type
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FAULT;
_ASSERTE(szEnclosingName && szNestedName);
int iLen = 2;
iLen += (int)strlen(szEnclosingName);
iLen += (int)strlen(szNestedName);
LPUTF8 szOut = (LPUTF8) qb.AllocNoThrow(iLen);
if (!szOut)
return false;
return ns::MakeNestedTypeName(szOut, iLen, szEnclosingName, szNestedName);
} // int ns::MakeNestedTypeName()
int ns::MakeNestedTypeName( // true ok, false truncation.
__out_ecount (cchChars) LPUTF8 szOut, // output path for name.
int cchChars, // max chars for output path.
LPCUTF8 szEnclosingName, // Full name for enclosing type
LPCUTF8 szNestedName) // Full name for nested type
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
STATIC_CONTRACT_FORBID_FAULT;
if (cchChars < 1)
return false;
int iCopyMax = 0, iLen;
int brtn = true;
*szOut = 0;
iLen = (int)strlen(szEnclosingName);
iCopyMax = min(cchChars-1, iLen);
strncpy_s(szOut, cchChars, szEnclosingName, iCopyMax);
if (iLen >= cchChars)
brtn = false;
szOut[iCopyMax] = NESTED_SEPARATOR_CHAR;
int iCur = iCopyMax+1; // iCopyMax characters + nested_separator_char
cchChars -= iCur;
if(cchChars == 0)
return false;
iLen = (int)strlen(szNestedName);
iCopyMax = min(cchChars-1, iLen);
strncpy_s(&szOut[iCur], cchChars, szNestedName, iCopyMax);
szOut[iCur + iCopyMax] = 0;
if (iLen >= cchChars)
brtn = false;
return brtn;
} // int ns::MakeNestedTypeName()
void ns::MakeNestedTypeName( // throws on out of memory
SString &ssBuf, // output path for name.
const SString &ssEnclosingName, // Full name for enclosing type
const SString &ssNestedName) // Full name for nested type
{
STATIC_CONTRACT_THROWS;
STATIC_CONTRACT_GC_NOTRIGGER;
ssBuf.Clear();
ssBuf.Append(ssEnclosingName);
ssBuf.Append(NESTED_SEPARATOR_WCHAR);
ssBuf.Append(ssNestedName);
}