1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
9 // Helpers for converting namespace separators.
11 //*****************************************************************************
22 #include "nsutilpriv.h"
25 //*****************************************************************************
26 // Determine how many chars large a fully qualified name would be given the
27 // two parts of the name. The return value includes room for every character
28 // in both names, as well as room for the separator and a final terminator.
29 //*****************************************************************************
30 int ns::GetFullLength( // Number of chars in full name.
31 const WCHAR *szNameSpace, // Namspace for value.
32 const WCHAR *szName) // Name of value.
34 STATIC_CONTRACT_NOTHROW;
35 STATIC_CONTRACT_GC_NOTRIGGER;
36 STATIC_CONTRACT_FORBID_FAULT;
38 int iLen = 1; // Null terminator.
40 iLen += (int)wcslen(szNameSpace);
42 iLen += (int)wcslen(szName);
43 if (szNameSpace && *szNameSpace && szName && *szName)
46 } //int ns::GetFullLength()
48 int ns::GetFullLength( // Number of chars in full name.
49 LPCUTF8 szNameSpace, // Namspace for value.
50 LPCUTF8 szName) // Name of value.
52 STATIC_CONTRACT_NOTHROW;
53 STATIC_CONTRACT_GC_NOTRIGGER;
54 STATIC_CONTRACT_FORBID_FAULT;
59 iLen += (int)strlen(szNameSpace);
61 iLen += (int)strlen(szName);
62 if (szNameSpace && *szNameSpace && szName && *szName)
65 } //int ns::GetFullLength()
68 //*****************************************************************************
69 // Scan the string from the rear looking for the first valid separator. If
70 // found, return a pointer to it. Else return null. This code is smart enough
71 // to skip over special sequences, such as:
75 // The ".ctor" is considered one token.
76 //*****************************************************************************
77 WCHAR *ns::FindSep( // Pointer to separator or null.
78 const WCHAR *szPath) // The path to look in.
80 STATIC_CONTRACT_NOTHROW;
81 STATIC_CONTRACT_GC_NOTRIGGER;
82 STATIC_CONTRACT_FORBID_FAULT;
85 WCHAR *ptr = (WCHAR*)wcsrchr(szPath, NAMESPACE_SEPARATOR_WCHAR);
86 if((ptr == NULL) || (ptr == szPath)) return NULL;
87 if(*(ptr - 1) == NAMESPACE_SEPARATOR_WCHAR) // here ptr is at least szPath+1
90 } //WCHAR *ns::FindSep()
92 //<TODO>@todo: this isn't dbcs safe if this were ansi, but this is utf8. Still an issue?</TODO>
93 LPUTF8 ns::FindSep( // Pointer to separator or null.
94 LPCUTF8 szPath) // The path to look in.
96 STATIC_CONTRACT_NOTHROW;
97 STATIC_CONTRACT_GC_NOTRIGGER;
98 STATIC_CONTRACT_FORBID_FAULT;
99 STATIC_CONTRACT_SUPPORTS_DAC;
102 LPUTF8 ptr = const_cast<LPUTF8>(strrchr(szPath, NAMESPACE_SEPARATOR_CHAR));
103 if((ptr == NULL) || (ptr == szPath)) return NULL;
104 if(*(ptr - 1) == NAMESPACE_SEPARATOR_CHAR) // here ptr is at least szPath+1
107 } //LPUTF8 ns::FindSep()
111 //*****************************************************************************
112 // Take a path and find the last separator (nsFindSep), and then replace the
113 // separator with a '\0' and return a pointer to the name. So for example:
115 // becomes two strings "a.b" and "c" and the return value points to "c".
116 //*****************************************************************************
117 WCHAR *ns::SplitInline( // Pointer to name portion.
118 __inout __inout_z WCHAR *szPath) // The path to split.
120 STATIC_CONTRACT_NOTHROW;
121 STATIC_CONTRACT_GC_NOTRIGGER;
122 STATIC_CONTRACT_FORBID_FAULT;
124 WCHAR *ptr = ns::FindSep(szPath);
131 } // WCHAR *ns::SplitInline()
133 LPUTF8 ns::SplitInline( // Pointer to name portion.
134 __inout __inout_z LPUTF8 szPath) // The path to split.
136 STATIC_CONTRACT_NOTHROW;
137 STATIC_CONTRACT_GC_NOTRIGGER;
138 STATIC_CONTRACT_FORBID_FAULT;
140 LPUTF8 ptr = ns::FindSep(szPath);
147 } // LPUTF8 ns::SplitInline()
149 void ns::SplitInline(
150 __inout __inout_z LPWSTR szPath, // Path to split.
151 LPCWSTR &szNameSpace, // Return pointer to namespace.
152 LPCWSTR &szName) // Return pointer to name.
154 STATIC_CONTRACT_NOTHROW;
155 STATIC_CONTRACT_GC_NOTRIGGER;
156 STATIC_CONTRACT_FORBID_FAULT;
158 WCHAR *ptr = SplitInline(szPath);
161 szNameSpace = szPath;
169 } // void ns::SplitInline()
171 void ns::SplitInline(
172 __inout __inout_z LPUTF8 szPath, // Path to split.
173 LPCUTF8 &szNameSpace, // Return pointer to namespace.
174 LPCUTF8 &szName) // Return pointer to name.
176 STATIC_CONTRACT_NOTHROW;
177 STATIC_CONTRACT_GC_NOTRIGGER;
178 STATIC_CONTRACT_FORBID_FAULT;
180 LPUTF8 ptr = SplitInline(szPath);
183 szNameSpace = szPath;
191 } // void ns::SplitInline()
194 //*****************************************************************************
195 // Split the last parsable element from the end of the string as the name,
196 // the first part as the namespace.
197 //*****************************************************************************
198 int ns::SplitPath( // true ok, false trunction.
199 const WCHAR *szPath, // Path to split.
200 __out_ecount(cchNameSpace) WCHAR *szNameSpace, // Output for namespace value.
201 int cchNameSpace, // Max chars for output.
202 __out_ecount(cchName) WCHAR *szName, // Output for name.
203 int cchName) // Max chars for output.
205 STATIC_CONTRACT_NOTHROW;
206 STATIC_CONTRACT_GC_NOTRIGGER;
207 STATIC_CONTRACT_FORBID_FAULT;
209 const WCHAR *ptr = ns::FindSep(szPath);
210 size_t iLen = (ptr) ? ptr - szPath : 0;
213 if (szNameSpace && cchNameSpace)
215 _ASSERTE(cchNameSpace > 1);
216 iCopyMax = cchNameSpace - 1;
217 iCopyMax = min(iCopyMax, iLen);
218 wcsncpy_s(szNameSpace, cchNameSpace, szPath, iCopyMax);
219 szNameSpace[iCopyMax] = 0;
221 if (iLen >= (size_t)cchNameSpace)
225 if (szName && cchName)
227 _ASSERTE(cchName > 1);
228 iCopyMax = cchName - 1;
233 iLen = (int)wcslen(ptr);
234 iCopyMax = min(iCopyMax, iLen);
235 wcsncpy_s(szName, cchName, ptr, iCopyMax);
236 szName[iCopyMax] = 0;
238 if (iLen >= (size_t)cchName)
242 } // int ns::SplitPath()
245 int ns::SplitPath( // true ok, false trunction.
246 LPCUTF8 szPath, // Path to split.
247 __out_ecount_opt (cchNameSpace) LPUTF8 szNameSpace, // Output for namespace value.
248 int cchNameSpace, // Max chars for output.
249 __out_ecount_opt (cchName) LPUTF8 szName, // Output for name.
250 int cchName) // Max chars for output.
252 STATIC_CONTRACT_NOTHROW;
253 STATIC_CONTRACT_GC_NOTRIGGER;
254 STATIC_CONTRACT_FORBID_FAULT;
256 LPCUTF8 ptr = ns::FindSep(szPath);
257 size_t iLen = (ptr) ? ptr - szPath : 0;
260 if (szNameSpace && cchNameSpace)
262 _ASSERTE(cchNameSpace > 1);
263 iCopyMax = cchNameSpace-1;
264 iCopyMax = min(iCopyMax, iLen);
265 strncpy_s(szNameSpace, cchNameSpace, szPath, iCopyMax);
266 szNameSpace[iCopyMax] = 0;
268 if (iLen >= (size_t)cchNameSpace)
272 if (szName && cchName)
274 _ASSERTE(cchName > 1);
275 iCopyMax = cchName-1;
280 iLen = (int)strlen(ptr);
281 iCopyMax = min(iCopyMax, iLen);
282 strncpy_s(szName, cchName, ptr, iCopyMax);
283 szName[iCopyMax] = 0;
285 if (iLen >= (size_t)cchName)
289 } // int ns::SplitPath()
292 //*****************************************************************************
293 // Take two values and put them together in a fully qualified path using the
294 // correct separator.
295 //*****************************************************************************
296 int ns::MakePath( // true ok, false truncation.
297 __out_ecount(cchChars) WCHAR *szOut, // output path for name.
298 int cchChars, // max chars for output path.
299 const WCHAR *szNameSpace, // Namespace.
300 const WCHAR *szName) // Name.
302 STATIC_CONTRACT_NOTHROW;
303 STATIC_CONTRACT_GC_NOTRIGGER;
304 STATIC_CONTRACT_FORBID_FAULT;
314 if (szNameSpace && *szNameSpace != W('\0'))
316 if (wcsncpy_s(szOut, cchChars, szNameSpace, _TRUNCATE) == STRUNCATE)
319 // Add namespace separator if a non-empty name was supplied
320 if (szName && *szName != W('\0'))
322 if (wcsncat_s(szOut, cchChars, NAMESPACE_SEPARATOR_WSTR, _TRUNCATE) == STRUNCATE)
329 if (szName && *szName)
331 if (wcsncat_s(szOut, cchChars, szName, _TRUNCATE) == STRUNCATE)
336 } // int ns::MakePath()
338 int ns::MakePath( // true ok, false truncation.
339 __out_ecount(cchChars) LPUTF8 szOut, // output path for name.
340 int cchChars, // max chars for output path.
341 LPCUTF8 szNameSpace, // Namespace.
342 LPCUTF8 szName) // Name.
344 STATIC_CONTRACT_NOTHROW;
345 STATIC_CONTRACT_GC_NOTRIGGER;
346 STATIC_CONTRACT_FORBID_FAULT;
356 if (szNameSpace && *szNameSpace != W('\0'))
358 if (strncpy_s(szOut, cchChars, szNameSpace, _TRUNCATE) == STRUNCATE)
361 // Add namespace separator if a non-empty name was supplied
362 if (szName && *szName != W('\0'))
364 if (strncat_s(szOut, cchChars, NAMESPACE_SEPARATOR_STR, _TRUNCATE) == STRUNCATE)
371 if (szName && *szName)
373 if (strncat_s(szOut, cchChars, szName, _TRUNCATE) == STRUNCATE)
379 } // int ns::MakePath()
381 int ns::MakePath( // true ok, false truncation.
382 __out_ecount(cchChars) WCHAR *szOut, // output path for name.
383 int cchChars, // max chars for output path.
384 LPCUTF8 szNamespace, // Namespace.
385 LPCUTF8 szName) // Name.
387 STATIC_CONTRACT_NOTHROW;
388 STATIC_CONTRACT_GC_NOTRIGGER;
389 STATIC_CONTRACT_FORBID_FAULT;
399 if (szNamespace != NULL && *szNamespace != '\0')
406 // We use cBuffer - 2 to account for the '.' and at least a 1 character name below.
407 count = WszMultiByteToWideChar(CP_UTF8, 0, szNamespace, -1, szOut, cchChars-2);
409 return false; // Supply a bigger buffer!
411 // buffer access is bounded: WszMultiByteToWideChar returns 0 if access doesn't fit in range
413 #pragma warning( suppress: 26015 )
415 szOut[count-1] = NAMESPACE_SEPARATOR_WCHAR;
420 if (((cchChars == 0) && (szName != NULL) && (*szName != '\0')) ||
421 (WszMultiByteToWideChar(CP_UTF8, 0, szName, -1, szOut, cchChars) == 0))
422 return false; // supply a bigger buffer!
424 } // int ns::MakePath()
426 int ns::MakePath( // true ok, false out of memory
427 CQuickBytes &qb, // Where to put results.
428 LPCUTF8 szNameSpace, // Namespace for name.
429 LPCUTF8 szName) // Final part of name.
431 STATIC_CONTRACT_NOTHROW;
432 STATIC_CONTRACT_GC_NOTRIGGER;
433 STATIC_CONTRACT_FAULT;
437 iLen += (int)strlen(szNameSpace);
439 iLen += (int)strlen(szName);
440 LPUTF8 szOut = (LPUTF8) qb.AllocNoThrow(iLen);
443 return ns::MakePath(szOut, iLen, szNameSpace, szName);
444 } // int ns::MakePath()
446 int ns::MakePath( // true ok, false out of memory
447 CQuickArray<WCHAR> &qa, // Where to put results.
448 LPCUTF8 szNameSpace, // Namespace for name.
449 LPCUTF8 szName) // Final part of name.
451 STATIC_CONTRACT_NOTHROW;
452 STATIC_CONTRACT_GC_NOTRIGGER;
453 STATIC_CONTRACT_FAULT;
457 iLen += (int)strlen(szNameSpace);
459 iLen += (int)strlen(szName);
460 WCHAR *szOut = (WCHAR *) qa.AllocNoThrow(iLen);
463 return ns::MakePath(szOut, iLen, szNameSpace, szName);
464 } // int ns::MakePath()
466 int ns::MakePath( // true ok, false out of memory
467 CQuickBytes &qb, // Where to put results.
468 const WCHAR *szNameSpace, // Namespace for name.
469 const WCHAR *szName) // Final part of name.
471 STATIC_CONTRACT_NOTHROW;
472 STATIC_CONTRACT_GC_NOTRIGGER;
473 STATIC_CONTRACT_FAULT;
477 iLen += (int)wcslen(szNameSpace);
479 iLen += (int)wcslen(szName);
480 WCHAR *szOut = (WCHAR *) qb.AllocNoThrow(iLen * sizeof(WCHAR));
483 return ns::MakePath(szOut, iLen, szNameSpace, szName);
484 } // int ns::MakePath()
486 void ns::MakePath( // throws on out of memory
487 SString &ssBuf, // Where to put results.
488 const SString &ssNameSpace, // Namespace for name.
489 const SString &ssName) // Final part of name.
491 STATIC_CONTRACT_THROWS;
492 STATIC_CONTRACT_GC_NOTRIGGER;
493 STATIC_CONTRACT_FAULT;
497 if (!ssNameSpace.IsEmpty())
499 if (ssName.IsEmpty())
501 ssBuf.Set(ssNameSpace);
505 SString s(SString::Literal, NAMESPACE_SEPARATOR_WSTR);
506 ssBuf.Set(ssNameSpace, s);
510 if (!ssName.IsEmpty())
512 ssBuf.Append(ssName);
516 bool ns::MakeAssemblyQualifiedName( // true ok, false truncation
517 __out_ecount(dwBuffer) WCHAR* pBuffer, // Buffer to recieve the results
518 int dwBuffer, // Number of characters total in buffer
519 const WCHAR *szTypeName, // Namespace for name.
520 int dwTypeName, // Number of characters (not including null)
521 const WCHAR *szAssemblyName, // Final part of name.
522 int dwAssemblyName) // Number of characters (not including null)
524 STATIC_CONTRACT_NOTHROW;
525 STATIC_CONTRACT_GC_NOTRIGGER;
526 STATIC_CONTRACT_FORBID_FAULT;
535 if (szTypeName && *szTypeName != W('\0'))
537 _ASSERTE(dwTypeName > 0);
538 iCopyMax = min(dwBuffer-1, dwTypeName);
539 wcsncpy_s(pBuffer, dwBuffer, szTypeName, iCopyMax);
540 dwBuffer -= iCopyMax;
543 if (szAssemblyName && *szAssemblyName != W('\0'))
546 if(dwBuffer < ASSEMBLY_SEPARATOR_LEN)
549 for(DWORD i = 0; i < ASSEMBLY_SEPARATOR_LEN; i++)
550 pBuffer[iCopyMax+i] = ASSEMBLY_SEPARATOR_WSTR[i];
552 dwBuffer -= ASSEMBLY_SEPARATOR_LEN;
556 int iCur = iCopyMax + ASSEMBLY_SEPARATOR_LEN;
557 _ASSERTE(dwAssemblyName > 0);
558 iCopyMax = min(dwBuffer-1, dwAssemblyName);
559 wcsncpy_s(pBuffer + iCur, dwBuffer, szAssemblyName, iCopyMax);
560 pBuffer[iCur + iCopyMax] = W('\0');
562 if (iCopyMax < dwAssemblyName)
567 PREFIX_ASSUME(iCopyMax > 0);
568 pBuffer[iCopyMax-1] = W('\0');
572 pBuffer[iCopyMax] = W('\0');
576 } // int ns::MakePath()
578 bool ns::MakeAssemblyQualifiedName( // true ok, false out of memory
579 CQuickBytes &qb, // Where to put results.
580 const WCHAR *szTypeName, // Namespace for name.
581 const WCHAR *szAssemblyName) // Final part of name.
583 STATIC_CONTRACT_NOTHROW;
584 STATIC_CONTRACT_GC_NOTRIGGER;
585 STATIC_CONTRACT_FAULT;
588 int iAssemblyName = 0;
590 iTypeName = (int)wcslen(szTypeName);
592 iAssemblyName = (int)wcslen(szAssemblyName);
594 int iLen = ASSEMBLY_SEPARATOR_LEN + iTypeName + iAssemblyName + 1; // Space for null terminator
595 WCHAR *szOut = (WCHAR *) qb.AllocNoThrow(iLen * sizeof(WCHAR));
600 ret = ns::MakeAssemblyQualifiedName(szOut, iLen, szTypeName, iTypeName, szAssemblyName, iAssemblyName);
605 int ns::MakeNestedTypeName( // true ok, false out of memory
606 CQuickBytes &qb, // Where to put results.
607 LPCUTF8 szEnclosingName, // Full name for enclosing type
608 LPCUTF8 szNestedName) // Full name for nested type
610 STATIC_CONTRACT_NOTHROW;
611 STATIC_CONTRACT_GC_NOTRIGGER;
612 STATIC_CONTRACT_FAULT;
614 _ASSERTE(szEnclosingName && szNestedName);
616 iLen += (int)strlen(szEnclosingName);
617 iLen += (int)strlen(szNestedName);
618 LPUTF8 szOut = (LPUTF8) qb.AllocNoThrow(iLen);
621 return ns::MakeNestedTypeName(szOut, iLen, szEnclosingName, szNestedName);
622 } // int ns::MakeNestedTypeName()
624 int ns::MakeNestedTypeName( // true ok, false truncation.
625 __out_ecount (cchChars) LPUTF8 szOut, // output path for name.
626 int cchChars, // max chars for output path.
627 LPCUTF8 szEnclosingName, // Full name for enclosing type
628 LPCUTF8 szNestedName) // Full name for nested type
630 STATIC_CONTRACT_NOTHROW;
631 STATIC_CONTRACT_GC_NOTRIGGER;
632 STATIC_CONTRACT_FORBID_FAULT;
637 int iCopyMax = 0, iLen;
641 iLen = (int)strlen(szEnclosingName);
642 iCopyMax = min(cchChars-1, iLen);
643 strncpy_s(szOut, cchChars, szEnclosingName, iCopyMax);
645 if (iLen >= cchChars)
648 szOut[iCopyMax] = NESTED_SEPARATOR_CHAR;
649 int iCur = iCopyMax+1; // iCopyMax characters + nested_separator_char
654 iLen = (int)strlen(szNestedName);
655 iCopyMax = min(cchChars-1, iLen);
656 strncpy_s(&szOut[iCur], cchChars, szNestedName, iCopyMax);
657 szOut[iCur + iCopyMax] = 0;
659 if (iLen >= cchChars)
663 } // int ns::MakeNestedTypeName()
665 void ns::MakeNestedTypeName( // throws on out of memory
666 SString &ssBuf, // output path for name.
667 const SString &ssEnclosingName, // Full name for enclosing type
668 const SString &ssNestedName) // Full name for nested type
670 STATIC_CONTRACT_THROWS;
671 STATIC_CONTRACT_GC_NOTRIGGER;
675 ssBuf.Append(ssEnclosingName);
676 ssBuf.Append(NESTED_SEPARATOR_WCHAR);
677 ssBuf.Append(ssNestedName);