uLib  User mode C/C++ extended API library for Win32 programmers.
StrFunc.cpp
Go to the documentation of this file.
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 // Project: uLib - User mode library.
3 // Module: String functions.
4 // Author: Copyright (c) Love Nystrom
5 // License: NNOSL (BSD descendant, see NNOSL.txt in the base directory).
6 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 
8 #include <uLib/StrFunc.h>
9 #include <uLib/UtilFunc.h>
10 #include <uLib/RegFunc.h>
11 #include <uLib/Debug.h>
12 #include <uLib/_Internal.h>
13 
14 //==----------------------------------------------------------------------------
15 // CharIndex - C version(s)
16 //==----------------------------------------------------------------------------
17 
18 INT_PTR CharIndexA( const char* Buffer, const char* Inside )
19 {
20  INT_PTR ix = (Inside - Buffer);
21  _ASSERTE( ix >= 0 ); // In case caller messed up...
22  return ix;
23 }
24 
25 INT_PTR CharIndexW( const wchar_t* Buffer, const wchar_t* Inside )
26 {
27  INT_PTR ix = (Inside - Buffer); // Note, C typed ptr arithmetic!
28  _ASSERTE( ix >= 0 ); // In case caller messed up...
29  return ix;
30 }
31 
32 //==----------------------------------------------------------------------------
33 // strecpy -- Copy and return a pointer to the terminating null in Dst.
34 // For concatenation strecpy beats strcat by a mile and a half..
35 //==----------------------------------------------------------------------------
36 
37 char* __fastcall strecpy( register char* Dst, register const char* Src )
38 {
39  while( *Src ) *Dst++ = *Src++;
40  *Dst = 0;
41  return Dst;
42  /* Variant 1: String ops, longer prolog/epilog, faster loop
43  push esi
44  push edi
45  mov esi, edx
46  mov edi, ecx
47  L1: lodsb
48  or al, al
49  stosb
50  jnz L1
51  mov eax, edi
52  dec eax
53  pop edi
54  pop esi
55  */
56  /* Variant 2: Reg index, shorter prolog/epilog, slower loop
57  L1: mov al, [edx]
58  inc edx
59  mov [ecx], al
60  inc ecx
61  or al, al
62  jnz L1
63  mov eax, ecx
64  dec eax
65  */
66 }
67 
68 wchar_t* __fastcall wcsecpy( register wchar_t* Dst, register const wchar_t* Src )
69 {
70  while( *Src ) *Dst++ = *Src++;
71  *Dst = 0;
72  return Dst;
73 }
74 
75 // Run-length limited variants
76 
77 char* __fastcall strnecpy( register char* Dst, register const char* Src, size_t n )
78 {
79  if ( n ) while( *Src && n-- ) *Dst++ = *Src++;
80  *Dst = 0; // 'n' was pre-decremented to make sure we can emit this _NUL.
81  return Dst;
82 }
83 
84 wchar_t* __fastcall wcsnecpy( register wchar_t* Dst, register const wchar_t* Src, size_t n )
85 {
86  if ( n ) while( *Src && n-- ) *Dst++ = *Src++;
87  *Dst = 0;
88  return Dst;
89 }
90 
91 //==----------------------------------------------------------------------------
92 // stristr - Case insensitive strstr.
93 // Credits to LefterisE@stackoverflow.com for the neat algorithm !
94 //==----------------------------------------------------------------------------
95 
96 char* stristr( const char* str, const char* pattern )
97 {
98  if ( !*pattern ) return (char*) str;
99  char* curr = (char*) str;
100  while( *curr )
101  {
102  register char* s = curr;
103  register char* pat = (char*) pattern;
104  while( *s && *pat && (0 == (tolower(*s)-tolower(*pat))) ) { // Loop while equal
105  ++s; ++pat;
106  }
107  if (!*pat) return curr; // If the whole pattern was consumed, it was found
108  ++curr;
109  }
110  return NULL;
111 }
112 
113 wchar_t* wcsistr( const wchar_t* str, const wchar_t* pattern )
114 {
115  if ( !*pattern ) return (wchar_t*) str;
116  wchar_t* curr = (wchar_t*) str;
117  while( *curr )
118  {
119  register wchar_t* s = curr;
120  register wchar_t* pat = (wchar_t*) pattern;
121  while( *s && *pat && (0 == (towlower(*s)-towlower(*pat))) ) { // Loop while equal
122  ++s; ++pat;
123  }
124  if (!*pat) return curr; // If the whole pattern was consumed, it was found
125  ++curr;
126  }
127  return NULL;
128 }
129 
130 //==----------------------------------------------------------------------------
131 // strncpyz - Strncpy with guaranteed nul termination.
132 //==----------------------------------------------------------------------------
133 
134 char* __fastcall strncpyz( register char* Dst, register const char* Src, size_t Count )
135 {
136  char* result = Dst;
137  while( *Src && --Count ) *Dst++ = *Src++;
138  *Dst = 0;
139  return result;
140 }
141 
142 wchar_t* __fastcall wcsncpyz( register wchar_t* Dst, register const wchar_t* Src, size_t Count )
143 {
144  wchar_t* result = Dst;
145  while( *Src && --Count ) *Dst++ = *Src++;
146  *Dst = 0;
147  return result;
148 }
149 
150 //==----------------------------------------------------------------------------
151 // Nr of bytes (incl.NUL) in wide string.
152 //==----------------------------------------------------------------------------
153 
154 size_t wcsbytes( const wchar_t* Src )
155 {
156  return Src ? (1 + wcslen( Src )) * sizeof(WCHAR) : 0;
157 }
158 
159 //==----------------------------------------------------------------------------
160 // String duplicates
161 //==----------------------------------------------------------------------------
162 
164 
165 // Note: These set ERROR_OUTOFMEMORY so (internal) callers don't have to..
166 
167 CSTR newStr( CSTR Src ) // String 'new' duplicate
168 {
169  // Note: Adding space for /two/ NUL terminator TCHARs.
170  // The 2nd is so the string can be used as a multi-sz.
171 
172  UINT Len = (UINT)_tcslen( Src );
173  TSTR Dup = new TCHAR[ Len + 2 ]; // +2 --> 2 NUL chars
174  if (!Dup) SetLastError( ERROR_OUTOFMEMORY );
175  else
176  {
177  _tcscpy( Dup, Src );
178  Dup[ Len + 1 ] = 0; // The extra NUL
179  }
180  return Dup;
181 }
182 
183 TSTR newStrBuf( WORD nChar ) // 'new' buffer
184 {
185  TSTR pBuf = new TCHAR[ nChar + 2 ]; // +2 --> 2 NUL chars
186  if (pBuf) memset( pBuf, 0, (nChar+2)*TCHAR_SIZE );
187  else SetLastError( ERROR_OUTOFMEMORY );
188  return pBuf;
189 }
190 
191 CSTR deleteStr( CSTR Dup ) // Delete 'new' duplicate
192 {
193  #ifndef HAVE_STRUCTURED_EH
194  DELETE_ARRAY( Dup );
195  #else
196  __try { DELETE_ARRAY( Dup ); }
198  DWORD xCode = GetExceptionCode();
199  TRACE( DP_ERROR, _F("Exception %#x.\r\n"), xCode );
200  }
201  __end_except; // gcc kludge
202  #endif
203  return Dup; // NULL after successful delete[]
204 }
205 
207 {
208  UINT Len = (UINT) wcslen( Src );
209  LPWSTR Dup = new WCHAR[ Len + 2 ];
210  if (!Dup) SetLastError( ERROR_OUTOFMEMORY );
211  else
212  {
213  memcpy( Dup, Src, (Len + 1) * WCHAR_SIZE );
214  Dup[ Len + 1 ] = 0; // The extra NUL
215  }
216  return Dup;
217 }
218 
220 {
221  #ifndef HAVE_STRUCTURED_EH
222  DELETE_ARRAY( Dup );
223  #else
224  __try { DELETE_ARRAY( Dup ); }
226  DWORD xCode = GetExceptionCode();
227  TRACE( DP_ERROR, _F("Exception %#x in operator delete[].\r\n"), xCode );
228  }
229  __end_except; // gcc kludge
230  #endif
231  return Dup; // NULL after successful delete[]
232 }
233 
234 // Guarantee use of mem_Alloc/mem_Free
235 // E.g. to satisfy DynArray's default DeleteItem.
236 
237 ASTR mem_DupAStr( ACSTR Src ) // String 'mem_Alloc' duplicate
238 {
239  UINT Len = (UINT) strlen( Src );
240  ASTR Dup = mem_AllocAStr( Len ); // Sets ERROR_OUTOFMEMORY on failure
241  if (Dup) strcpy( Dup, Src );
242 
243  // Note: Visavi newStr, setting the 2nd NUL here is superfluous,
244  // because mem_Alloc zero-fills the allocated memory, and strcpy
245  // doesn't touch anything beyond it's NUL terminator.
246 
247  return Dup;
248 }
249 
250 WSTR mem_DupWStr( WCSTR Src ) // String 'mem_Alloc' duplicate
251 {
252  UINT Len = (UINT) wcslen( Src );
253  WSTR Dup = mem_AllocWStr( Len );
254  if (Dup) wcscpy( Dup, Src );
255  return Dup;
256 }
257 
259 {
260  UINT size = nChar + 2; // +2 --> 2 NUL chars
261  return (ASTR) mem_Alloc( size );
262 }
263 
265 {
266  UINT size = (nChar + 2) * WCHAR_SIZE; // +2 --> 2 NUL chars
267  return (WSTR) mem_Alloc( size );
268 }
269 
270 CSTR mem_FreeStr( CSTR Dup ) // Delete 'mem_Alloc' duplicate
271 {
272  return (CSTR) mem_Free( PVOID( Dup ));
273 }
274 
276 
277 //==----------------------------------------------------------------------------
278 // Unicode to multibyte hand-me-on-the-fly translate (e.g for DPrint()).
279 //==----------------------------------------------------------------------------
280 
282 {
283  static CHAR szBuf[ MAX_PATH ];
284  WideCharToMultiByte( CP_ACP,0, pwStr,-1, szBuf,MAX_PATH, NULL, NULL );
285  return szBuf;
286 }
287 
288 // Allocate an ANSI string and translate from wide string, and vice versa.
289 
290 ASTR mem_ADupWStr( WCSTR pWStr, UINT CodePg, UINT ccExtra )
291 {
292  int len = WideCharToMultiByte( CodePg, 0, pWStr, -1, NULL, 0, NULL, NULL );
293  ASTR pDup = mem_AllocAStr( len + ccExtra );
294  if (pDup) WideCharToMultiByte( CodePg, 0, pWStr, -1, pDup, len, NULL, NULL );
295  return pDup;
296 }
297 
298 WSTR mem_WDupAStr( ACSTR pAStr, UINT CodePg, UINT ccExtra )
299 {
300  int len = MultiByteToWideChar( CodePg, MB_PRECOMPOSED, pAStr, -1, NULL, 0 );
301  WSTR pDup = mem_AllocWStr( len + ccExtra );
302  if (pDup) MultiByteToWideChar( CodePg, MB_PRECOMPOSED, pAStr, -1, pDup, len );
303  return pDup;
304 }
305 
306 //==----------------------------------------------------------------------------
307 // LoadStr - Simplified use of LoadString (uses static buffer if none provided)
308 //==----------------------------------------------------------------------------
309 
310 CSTR LoadStr( HMODULE hModule, UINT Id, TSTR Buf, UINT Count )
311 {
312  static TCHAR sbuf[ MAX_PATH ];
313  if (!Buf)
314  {
315  Buf = sbuf;
316  Count = dimof( sbuf );
317  }
318  if (!LoadString( hModule, Id, Buf, Count )) Buf[0] = 0;
319  return (CSTR) Buf;
320 }
321 
322 // Return a read-only pointer directly to the string resource.
323 
324 WCSTR GetResourceStr( HMODULE hModule, UINT Id, PWORD pCount )
325 {
326  WSTR pwzStr = NULL; // Ptr to string resource.
327 
328  // Setting cchBufferMax to zero gives us a pointer to the resource itself.
329  // LoadStringW returns zero and an empty string for a nonexistent resource.
330 
331  WORD count = LoadStringW( hModule, Id, (WSTR)&pwzStr, 0 );
332  if (!count) pwzStr = NULL; // Change empty str to NULL.
333  if (pCount) *pCount = count;
334  return pwzStr;
335 }
336 
337 // FindResourceStrEx - Adapted from (slightly flawed) code by Raymond Chen. Thank You.
338 
339 WCSTR FindResourceStrEx( HMODULE hModule, UINT Id, LANGID Lang, PWORD pCount )
340 {
341  UINT bundleNr = Id / 16 + 1; // Convert the string ID into a bundle number
342  UINT strNr = Id & 15, cbRes; // and string number.
343  WCSTR pwzStr = (WCSTR) LoadCustomResourceEx(
344  hModule, (CSTR)(UINT_PTR) bundleNr, RT_STRING, Lang, &cbRes
345  );
346  if (pwzStr) // If we found it, then walk the string table..
347  {
348  for( UINT i = 0; i < strNr; i++ )
349  {
350  pwzStr += (1 + (WORD)*pwzStr); // WORD Raymond, not DWORD.
351  }
352  }
353  WORD ccStr = (WORD) *pwzStr++;
354  if (pCount) *pCount = ccStr;
355  return pwzStr;
356 }
357 
358 // Load, allocate, translate, and null terminate a resource string.
359 
360 CSTR DupResourceStrEx( HMODULE hModule, UINT Id, LANGID Lang, PWORD pCount )
361 {
362  TSTR pzStr = NULL;
363  WORD count;
364  WCSTR rcStr = FindResourceStrEx( hModule, Id, Lang, &count );
365  if (rcStr)
366  {
367  pzStr = mem_AllocStr( count ); // Transmutable
368  if (pzStr)
369  {
370  #ifdef _UNICODE
372  wcsncpy( pzStr, rcStr, count );
374  #else // Translate to multibyte
375  WideCharToMultiByte( CP_ACP, 0, rcStr, count, pzStr, count, NULL, NULL );
376  #endif
377  pzStr[ count ] = 0;
378  }
379  }
380  return (CSTR)pzStr;
381 }
382 
384 {
385  return (CSTR) mem_FreeStr( (TSTR)pzRcDupStr );
386 }
387 
388 //==----------------------------------------------------------------------------
389 // Multi-string functions.
390 //==----------------------------------------------------------------------------
391 
392 UINT EnumerateMultiSzA( ASTR MultiSz, PFnEnumMultiStringA Action, PVOID Context )
393 {
394  ASTR pStr = MultiSz;
395  UINT nStr = 0;
396  while( *pStr )
397  {
398  ++nStr;
399  // Prescan for next NUL, in case Action inserts extra NUL chars.
400  ASTR pEnd = strchr( pStr, 0 );
401  if (!Action( pStr, Context )) break; // Invoke caller's function
402  pStr = pEnd + 1;
403  }
404  return nStr;
405 }
406 
407 UINT EnumerateMultiSzW( WSTR MultiSz, PFnEnumMultiStringW Action, PVOID Context )
408 {
409  PWSTR pStr = MultiSz;
410  UINT nStr = 0;
411  while( *pStr )
412  {
413  ++nStr;
414  PWSTR pEnd = wcschr( pStr, 0 ); // Prescan for next NUL.
415  if (!Action( pStr, Context )) break; // Invoke caller's function.
416  pStr = pEnd + 1;
417  }
418  return nStr;
419 }
420 
421 // Return length of multi-string, in TCHARs, incl final NUL.
422 
423 UINT MultiSzLengthA( ACSTR MultiSz )
424 {
425  register ACSTR pStr = MultiSz;
426  while( *pStr ) pStr = strchr( pStr, 0 ) + 1;
427  return UINT( 1 + UINT_PTR( pStr - MultiSz ));
428 }
429 
430 UINT MultiSzLengthW( WCSTR MultiSz )
431 {
432  register WCSTR pStr = MultiSz;
433  while( *pStr ) pStr = wcschr( pStr, 0 ) + 1;
434  return UINT( 1 + UINT_PTR( pStr - MultiSz ));
435 }
436 
437 // Return nr of strings in multi-string.
438 
439 UINT MultiSzCountA( ACSTR MultiSz )
440 {
441  UINT count = 0;
442  register ACSTR pStr = MultiSz;
443  while( *pStr )
444  {
445  count++;
446  pStr = strchr( pStr, 0 ) + 1;
447  }
448  return count;
449 }
450 
451 UINT MultiSzCountW( WCSTR MultiSz )
452 {
453  UINT count = 0;
454  register WCSTR pStr = MultiSz;
455  while( *pStr )
456  {
457  count++;
458  pStr = wcschr( pStr, 0 ) + 1;
459  }
460  return count;
461 }
462 
463 // Compact the string by changing CRLF into single LF delimiters.
464 // The presence of CRLF is assumed already detected.
465 // Note: This does *not* deal with (God forbid) Mac style CR only.
466 
468 {
469  register TSTR pSrc = pText;
470  register TSTR pDst = pText;
471 
472  while( *pSrc && *pSrc != CR ) {
473  pSrc++; // Fast forward past initial text
474  }
475  pDst = pSrc;
476  *pDst++ = LF; // Replace CR with LF
477  pSrc += 2; // Skip past CRLF
478 
479  while( *pSrc )
480  {
481  while( *pSrc && *pSrc != CR )
482  *pDst++ = *pSrc++;
483  *pDst++ = LF;
484  pSrc += 2;
485  }
486  *pDst = 0;
487  return pText;
488 }
489 
490 // Replace LFs with NUL in preparation for writing to registry or ini section.
491 // Optionally return length of multi-string in chars, incl final NUL.
492 
493 TSTR LinesToMultiSz( TSTR pText, UINT* ccSz )
494 {
495  TSTR pEnd = pText;
496  while( *pEnd )
497  {
498  TSTR pBegin = pEnd; // Preserve ptr in case no LF found
499  pEnd = _tcschr( pBegin, LF );
500  if (pEnd) *pEnd++ = 0;
501  else
502  {
503  pEnd = _tcschr( pBegin, 0 );
504  *++pEnd = 0; // 2nd NUL if last line *don't* have LF end.
505  }
506  }
507  *pEnd++ = 0; // 2nd NUL if last line have LF end.
508  if (ccSz) *ccSz = (UINT) CharIndex( pText, pEnd );
509  return pText;
510 }
511 
512 // Replace NUL delimiters with LF (in multi-sz from e.g. registry or ini section).
513 
515 {
516  TSTR pEnd = pText;
517  while( *pEnd )
518  {
519  pEnd = _tcschr( pEnd,0 );
520  *pEnd++ = LF;
521  }
522  return pText;
523 }
524 
525 // Duplicate a multi-string
526 
528 {
529  UINT Len = MultiSzLength( pzMulti );
530  TSTR pDup = newStrBuf( Len ); // Comply with newStr().
531  #ifdef _UNICODE
532  Len *= WCHAR_SIZE;
533  #endif
534  if (pDup) memcpy( pDup, pzMulti, Len );
535  return pDup;
536 }
537 
539 {
540  return (TSTR) deleteStr( pzMulti );
541 }
542 
543 //==----------------------------------------------------------------------------
544 
545 CSTR __cdecl StrFmt( TSTR Buf, UINT ccBuf, CSTR Fmt, ... )
546 {
547  static TCHAR szBuf[ MAX_PATH ];
548  va_list va;
549 
550  if (!Buf)
551  {
552  if (ccBuf) Buf = newStrBuf( ccBuf );
553  else
554  {
555  Buf = szBuf;
556  ccBuf = dimof(szBuf);
557  }
558  }
559  va_start( va, Fmt );
560  _vstprintf_s( Buf, ccBuf, Fmt, va );
561  va_end( va );
562 
563  return Buf;
564 }
565 
566 //++ SplitUncPath ++------------------------------------------------------------
567 
568 bool SplitUncPath( CSTR UncPath,
569  TSTR Svr, UINT ccSvr, TSTR Share, UINT ccShare, TSTR Path, UINT ccPath )
570 {
571  #define _INVALPARM ERROR_INVALID_PARAMETER // shorthand
572 
573  // The UNC path must have at least server and share components.
574  // The path component is optional.
575 
576  BOOL ok = __ChkOkSetErr( IsString( UncPath ), _INVALPARM );
577  if (ok) ok = __ChkOkSetErr( _tcschr( UncPath, COLON ) == NULL, _INVALPARM ); // Exclude DOS paths.
578  if (ok) ok = __ChkOkSetErr( !PathIsRelative( UncPath ), _INVALPARM ); // UNC can't be relative.
579  if (ok) ok = __ChkOkSetErr( Svr && Share && ccSvr && ccShare, _INVALPARM );
580  // There may be more to exclude but that should take care of the brunt of goofs.
581  if (ok)
582  {
583  TCHAR szUncPath[ 80+80+MAX_PATH ]; // cch = 420
584  _tcsncpyz( szUncPath, UncPath, dimof(szUncPath) );
585 
586  // Find the first char past any prefix (like \\.\).
587  size_t offs = _tcsspn( szUncPath, _T("\\?.") );
588  CSTR pzServer = &szUncPath[ offs ];
589  ok = __ChkOkSetErr( *pzServer, _INVALPARM );
590  if (ok)
591  {
592  ok = (0 != _tcsnicmp( pzServer, _T("UNC\\"), 4 ));
593  if (!ok)
594  {
595  pzServer += 4; // Skip the UNC\ prefix
596  ok = __ChkOkSetErr( *pzServer, _INVALPARM );
597  }
598  if (ok)
599  {
600  TSTR pzShare = (TSTR)_tcschr( pzServer, BSLASH );
601  ok = __ChkOkSetErr( pzShare && *pzShare && *(pzShare+1), _INVALPARM );
602  if (ok)
603  {
604  *pzShare++ = 0;
605  // Locate an optional path component
606  TSTR pzPath = (TSTR)_tcschr( pzShare, BSLASH );
607  if (pzPath) *pzPath++ = 0;
608 
609  // Validate reciever buffer sizes.
610 
611  size_t svrLen = _tcslen( pzServer );
612  size_t shrLen = _tcslen( pzShare );
613  // Use > since there must be space for terminating NUL as well.
614  ok = (ccSvr > svrLen) && (ccShare > shrLen);
615  bool havePath = (Path && pzPath);
616  if (ok && havePath) ok = (ccPath > _tcslen( pzPath ));
617 
618  if (!ok) SetLastError( ERROR_INSUFFICIENT_BUFFER );
619  else
620  {
621  _tcsncpyz( Svr, pzServer, ccSvr );
622  _tcsncpyz( Share, pzShare, ccShare );
623  if (havePath) _tcsncpyz( Path, pzPath, ccPath );
624  }
625  }
626  }
627  }
628  }
629  return bool_cast( ok );
630  #undef _INVALPARM
631 }
632 //++ SplitNetShareName ++------------------------------------------------------------
633 
635  IN CSTR ShareName, OUT WSTR Server, UINT ccServer, OUT WSTR Share, UINT ccShare )
636 {
637  TCHAR pzServer[80], pzShare[80];
638 
639  // Get Server and Share names suitable for e.g. NetShareGetInfo.
640 
641  BOOL ok = SplitUncPath( ShareName, pzServer,80, pzShare,80, NULL,0 );
642  if (ok)
643  {
644  #ifdef _UNICODE
645  wcsncpyz( Server, pzServer, ccServer );
646  wcsncpyz( Share, pzShare, ccShare );
647  #else
648  MultiByteToWideChar( CP_ACP, 0, pzServer,-1, Server, ccServer );
649  MultiByteToWideChar( CP_ACP, 0, pzShare,-1, Share, ccShare );
650  #endif
651  }
652  return bool_cast( ok );
653 }
654 
655 
656 //==----------------------------------------------------------------------------
657 // Return the root component of a filepath.
658 // Use the internal __GetRoot but change the param order
659 // to comply logically with the different id, GetRootOf.
660 
661 bool GetRootOf( IN CSTR PathName, OUT TSTR Root, UINT ccRoot )
662 {
663  return __GetRoot( Root, ccRoot, PathName );
664 }
665 
666 //==----------------------------------------------------------------------------
667 
669 {
670  static __thread_local TCHAR szPath[ MAX_PATH ];
671 
672  CSTR pEnd = _tcschr( PathName, 0 ) - 1;
673  if (*pEnd == BSLASH)
674  {
675  _tcscpy_s( szPath, dimof(szPath), PathName );
676  szPath[ pEnd-PathName ] = 0;
677  PathName = szPath;
678  }
679  return PathName;
680 }
681 
683 {
684  static __thread_local TCHAR szPath[ MAX_PATH ];
685 
686  TSTR pEnd = _tcschr( (TSTR)PathName, 0 ) - 1;
687  if (*pEnd != BSLASH)
688  {
689  _tcscpy_s( szPath, dimof(szPath), PathName );
690  pEnd = &szPath[ pEnd-PathName+1 ];
691  *pEnd++ = BSLASH; *pEnd = 0;
692  PathName = szPath;
693  }
694  return PathName;
695 }
696 
697 //==----------------------------------------------------------------------------
698 
699 TSTR ReplaceStrChar( TSTR Str, TCHAR From, TCHAR To, OPTOUT UINT* pCount )
700 {
701  UINT count = 0;
702  TSTR pzEnd = Str;
703  TSTR pzItem = _tcschr( Str, From );
704  while( pzItem )
705  {
706  count++;
707  *pzItem++ = To;
708  TSTR pzNext = _tcschr( pzItem, From );
709  if (!pzNext) pzEnd = _tcschr( pzItem, 0 );
710  pzItem = pzNext;
711  }
712  if (pCount) *pCount = count;
713  return pzEnd; // Return ptr to terminating null
714 }
715 
716 //UINT strToInt( TSTR pStr )
717 //{
718 // TSTR end;
719 // int radix;
720 // if (_tcsnicmp( pStr, _T("0x"), 2 ) == 0) {
721 // radix = 16; pStr += 2;
722 // } else radix = 10;
723 // return strtoul( pStr, &end, radix );
724 //}
725 
726 // Wildcard pattern match, including char set matching (i.e [aex-z]).
727 // MatchPattern is based on an Microsoft SDK sample that I improved.
728 
729 static const TCHAR _STARTBRACK = _T('[');
730 static const TCHAR _ENDBRACK = _T(']');
731 static const TCHAR _ASTERISK = _T('*');
732 static const TCHAR _QUESTMARK = _T('?');
733 static const TCHAR _DASH =_T('-');
734 
735 static int __cdecl as_is( int ch ) { return ch; }
736 
742 
743 bool MatchPattern( CSTR String, CSTR Pattern, bool CaseSens )
744 {
745  TCHAR c, p, l;
746  int (__cdecl *_getcase)( int ch ) = CaseSens ? as_is : toupper;
747 
748  for (;;)
749  {
750  switch( p = _getcase( *Pattern++ ))
751  {
752  case 0: // end of pattern
753  return *String ? false : true; // if end of string TRUE
754 
755  case _ASTERISK:
756  while( *String ) // match zero or more char
757  {
758  if (MatchPattern( String++, Pattern, CaseSens ))
759  return true;
760  }
761  return MatchPattern( String, Pattern, CaseSens );
762 
763  case _QUESTMARK:
764  if (*String++ == 0) // match any one char
765  return false; // except end of string
766  break;
767 
768  case _STARTBRACK:
769  if ( (c = *String++) == 0) // match char set
770  return false; // syntax
771 
772  c = _getcase( c );
773  l = 0;
774  while( p = _getcase( *Pattern++ ))
775  {
776  if (p == _ENDBRACK) // if end of char set, then
777  return false; // no match found
778 
779  if (p == _DASH) // check a range of chars?
780  {
781  p = _getcase( *Pattern ); // get high limit of range
782  if (p == 0 || p == _ENDBRACK)
783  return false; // syntax
784 
785  if (c >= l && c <= p)
786  break; // if in range, move on
787  }
788 
789  l = p;
790  if (c == p) // if char matches this element
791  break; // move on
792  }
793 
794  while( p && p != _ENDBRACK ) // got a match in char set
795  p = *Pattern++; // skip to end of set
796  break;
797 
798  default:
799  c = _getcase( *String++ );
800  if (c != p) // check for exact char
801  return false; // not a match
802  break;
803  }
804  }
805 }
806 
807 //==----------------------------------------------------------------------------
808 // DeduplicateCharSeparatedText
809 //==----------------------------------------------------------------------------
810 
811 #ifndef _UNICODE
812 // class WordList, which is used as the deduplicator,
813 // doesn't have a Unicode implementation. At least not yet..
814 
815 namespace { // internal
816 struct __textDedupData // internal data..
817 {
818  PWordList list;
819  bool caseSens;
820  TCHAR *pzText, Sep;
821  UINT nParts, nEmitted;
822 };
823 } // end internal
824 
825 static bool __stdcall __addtoWordList( TSTR Str, PVOID pData )
826 {
827  __textDedupData* pdd = (__textDedupData*) pData;
828 
829  bool added = pdd->list->AddString( Str, pdd->caseSens );
830  UNUSED( added );
831  return true;
832 }
833 
834 static bool __stdcall __emitTextPart( TSTR partStr, PVOID pData )
835 {
836  __textDedupData* pdd = (__textDedupData*) pData;
837 
838  pdd->pzText = _tcsecpy( pdd->pzText, partStr );
839  if (++pdd->nEmitted < pdd->nParts) *pdd->pzText++ = pdd->Sep;
840  return true;
841 }
842 
843 // PONDER: Rewrite DeduplicateCharSepText to /not/ use WordList,
844 // so as to make it available in Unicode as well,
845 // or make WordList available in UNICODE too.
846 
848  ASTR Text, CHAR Separator, bool caseSens, bool emitSorted )
849 {
850  UINT Len = (UINT)_tcslen( Text );
851  bool endSep = (Text[Len-1] == Separator);
852  // (#1) Must have room for a second _NUL char at the end..
853  if (!endSep && IsBadWritePtr( &Text[Len+1], TCHAR_SIZE )) // Try to prevent GPF..
854  {
855  SetLastError( ERROR_INSUFFICIENT_BUFFER );
856  Len = 0; // Not really.. Just used as error indicator.
857  }
858  else
859  {
860  UINT Count; // Convert text in-place into a multi-sz..
861  TSTR pzEnd = ReplaceStrChar( Text, Separator, 0, &Count );
862  if (!endSep) // If Text did not end with Separator..
863  {
864  // Note: There's a minute risk that pzEnd might still clobber
865  // an innocent char if the caller was careless about the buffer.
866  *++pzEnd = 0; // (#1) Add a second null char..
867  Count++; // Count the last part.
868  }
869 
870  WordList partList( Count, Len, 4, 16 ); // Use a WordList as deduplicator.
871  __textDedupData dd = { 0,0,0,0,0,0 }; // Passed to EnumerateMultiSz callbacks.
872 
873  dd.list = &partList;
874  dd.caseSens = caseSens;
875  EnumerateMultiSz( Text, __addtoWordList, &dd );
876  TRACE( DP_INFO, _F("%lu duplicates removed.\n"), Count - partList.Count );
877 
878  if (emitSorted)
879  {
880  TSTR pzPart = Text;
881  for( UINT ix = 0, last = partList.Count-1; ix < partList.Count; ++ix )
882  {
883  pzPart = _tcsecpy( pzPart, partList.Strings[ ix ]);
884  if (ix < last) *pzPart++ = Separator;
885  }
886  }
887  else // Emit in original order by enumerating Storage..
888  {
889  dd.pzText = Text;
890  dd.Sep = Separator;
891  dd.nParts = partList.Count;
892  EnumerateMultiSz( partList.Storage, __emitTextPart, &dd );
893  }
894  Len = (UINT)_tcslen( Text );
895  }
896  return Len;
897 }
898 #endif//ndef _UNICODE
899 
900 //==----------------------------------------------------------------------------
901 // Prepend or append a string in-place..
902 //==----------------------------------------------------------------------------
903 
904 UINT PrependString( TSTR String, UINT ccBuf, TCHAR Sep, CSTR Prolog )
905 {
906  UINT newLen = 0;
907  UINT strLen = (UINT)_tcslen( String );
908  UINT addLen = (UINT)_tcslen( Prolog );
909  UINT sepLen = Sep ? 1 : 0;
910 
911  if (strLen + addLen + sepLen + 1 > ccBuf)
912  SetLastError( ERROR_INSUFFICIENT_BUFFER );
913  else
914  {
915  UINT cbMove = (strLen + 1) * TCHAR_SIZE;
916  memmove( &String[ addLen + sepLen ], String, cbMove );
917  if (Sep) String[ addLen ] = Sep;
918  memcpy( String, Prolog, addLen * TCHAR_SIZE );
919  newLen = strLen + addLen + sepLen;
920  }
921  return newLen;
922 }
923 
924 UINT AppendString( TSTR String, UINT ccBuf, TCHAR Sep, CSTR Epilog )
925 {
926  UINT newLen = 0;
927  UINT strLen = (UINT)_tcslen( String );
928  UINT addLen = (UINT)_tcslen( Epilog );
929  UINT sepLen = Sep ? 1 : 0;
930 
931  if (strLen + addLen + sepLen + 1 > ccBuf)
932  SetLastError( ERROR_INSUFFICIENT_BUFFER );
933  else
934  {
935  memcpy( &String[ strLen + sepLen ], Epilog, addLen * TCHAR_SIZE );
936  if (Sep) String[ strLen ] = Sep;
937  newLen = strLen + addLen + sepLen;
938  }
939  return newLen;
940 }
941 
942 //==----------------------------------------------------------------------------
943 // System compatible string hash
944 //==----------------------------------------------------------------------------
945 #ifndef NO_WINTERNAL // UNICODE_STRING
946 
947 ULONG GetStringHash( WCSTR Str, ULONG Algorithm, bool caseSens ) // preliminary
948 {
949  static NTSTATUS (NTAPI *_RtlHashUnicodeString)(
950  const PUNICODE_STRING String, BOOLEAN CaseInSensitive,
951  ULONG HashAlgorithm, PULONG HashValue
952  );
953  UNICODE_STRING us;
954  ULONG hash = 0;
955  HMODULE hMod = NULL;
956 
958  {
959  hMod = GetModuleHandleA( "NTDLL" );
960  (FARPROC&)_RtlHashUnicodeString = GetProcAddress( hMod, "RtlHashUnicodeString" );
961  }
962 
964  {
965  _InitUnicodeString( &us, Str );
966  NTSTATUS rc = _RtlHashUnicodeString( &us, !caseSens, Algorithm, &hash );
967  if (!NT_SUCCESS( rc ))
968  {
969  hash = 0;
971  }
972  }
973  return hash;
974 }
975 
976 #endif//ndef NO_WINTERNAL
977 //==----------------------------------------------------------------------------
978 // Hex string
979 //==----------------------------------------------------------------------------
980 
981 CSTR HexString( PBYTE data, UINT len, TSTR buf, UINT size, bool dots )
982 {
983  static TCHAR buffer[ MAX_PATH ];
984  static CCSTR hex = _T("0123456789ABCDEF");
985 
986  // Bit of a hack, this one.. but it's lean and it works.
987 
988  TSTR dst;
989  UINT bufrem;
990  bool usrbuf = (buf != NULL && size != 0);
991 
992  if (usrbuf) {
993  dst = buf;
994  bufrem = size;
995  } else {
996  dst = buffer;
997  bufrem = dimof(buffer);
998  }
999 
1000  if (dots && bufrem < 7) { // 7="XX ...\0"
1001  SetLastError( ERROR_INSUFFICIENT_BUFFER );
1002  return S_BLANK;
1003  }
1004 
1005  if (dots) bufrem -= 4; // reserve buffer space for "...\0"
1006  for( *dst=0; len && bufrem; len--, bufrem -= 2 )
1007  {
1008  if ((bufrem <= 4) && (len > 1))
1009  {
1010  dots = true; // more data...
1011  break;
1012  }
1013  *dst++ = hex[ *data >> 4 ];
1014  *dst++ = hex[ *data & 0x0F ];
1015  if (len > 1)
1016  {
1017  *dst++ = SPACE;
1018  bufrem--;
1019  data++;
1020  }
1021  }
1022  if (dots) for( len=3; len && bufrem > 1; len--, bufrem-- )
1023  *dst++ = DOT;
1024  *dst = 0;
1025  return usrbuf ? buf : buffer;
1026 }
1027 
1028 //==----------------------------------------------------------------------------
1029 // Special strings
1030 //==----------------------------------------------------------------------------
1031 
1032 static TSTR _scatCh( TSTR ps, TCHAR ch ) { // String concatenate char.
1033  *ps++ = ch; *ps = 0;
1034  return ps;
1035  }
1036 
1037 BEGIN_STRSAFE_OVERRIDE //++ These two can't possibly overrun the buffer.
1038 
1039 static CCSTR sizePrefix = _T(" kMGTPEZY"); // Prefix of the size suffix (B/iB).
1040 
1041 #if 1 // Changed to fpt calc (for consistency w IsoDataSizeStr)
1042 CSTR DataSizeStr( UINT64 Size ) // xxx B(kB,MB,GB,TB,EB,PB)..
1043 {
1044  static TCHAR sbuf[40]; // Not on stack.
1045  CSTR pfx; double size = (double) Size;
1046  for( pfx = sizePrefix; size >= 1000; size /= 1000, pfx++ );
1047 
1048  _stprintf( sbuf, _T("%0.2f %cB"), size, *pfx );
1049  return sbuf;
1050 }
1051 #else // The legacy integer algorithm..
1052 CSTR DataSizeStr( UINT64 Size ) // xxx B(kB,MB,GB,TB,EB,PB)..
1053 {
1054  static TCHAR sbuf[40]; // Not on stack.
1055  CSTR pfx; ULONG frac = 0; static const UINT DIV = 1000;
1056  for( pfx = sizePrefix; Size >= DIV; frac = Size % DIV, Size /= DIV, pfx++ );
1057 
1058  _stprintf( sbuf, _T("%lu.%lu %cB"), ULONG(Size), frac/100, *pfx );
1059  return sbuf;
1060 }
1061 #endif
1062 
1063 // Note: Explorer is actually showing kiB, but doesn't use the correct 'i' suffix.
1064 
1065 #if 1 // FIX: Take the performance hit of floating point calculation..
1066 CSTR IsoDataSizeStr( UINT64 _Size ) // xxx B(kiB,MiB,GiB,TiB,EiB,PiB)..
1067 {
1068  static TCHAR sbuf[40]; // Not on stack.
1069  CSTR pfx; double size = (double)_Size;
1070  for( pfx = sizePrefix; size >= 1024; size /= 1024, pfx++ );
1071 
1072  _stprintf( sbuf, _T("%0.2f %ciB"), size, *pfx );
1073  return sbuf;
1074 }
1075 #else // BUGBUG: This begets wrong value for peculiar corner case Size arguments.
1076 CSTR IsoDataSizeStr( UINT64 _Size ) // xxx B(kiB,MiB,GiB,TiB,EiB,PiB)..
1077 {
1078  static TCHAR sbuf[40]; // Not on stack.
1079  TRACE( DP_WARNING, _F("Size = %llu\n"), _Size );
1080  CSTR pfx; ULONG frac = 0;
1081 
1082  for( pfx = sizePrefix; Size >= 1024; frac = Size & 0x3FF, Size >>= 10, pfx++ );
1083 
1084  _stprintf( sbuf, _T("%lu.%lu %ciB"), ULONG(_Size), frac/100, *pfx );
1085  TRACE( DP_WARNING, _F("WTF? IsoSize = %s ??\n"), sbuf );
1086  return sbuf;
1087 }
1088 #endif
1089 
1091 
1093 {
1094  static TCHAR sbuf[16]; // Not on stack.
1095  // D|A|H|R|S|C|E|O|P|Z|T
1096  // D: Directory
1097  // A: Archive
1098  // H: Hidden
1099  // R: ReadOnly
1100  // S: System
1101  // C: Compressed
1102  // E: Encrypted
1103  // O: OffLine
1104  // P: ReparsePoint
1105  // Z: Sparse
1106  // T: Temporary
1107  TSTR pz = sbuf;
1108  *pz = 0;
1109  if (Attr & FILE_ATTRIBUTE_DIRECTORY) pz = _scatCh( pz, _T('D') );
1110  if (Attr & FILE_ATTRIBUTE_HIDDEN) pz = _scatCh( pz, _T('H') );
1111  if (Attr & FILE_ATTRIBUTE_READONLY) pz = _scatCh( pz, _T('R') );
1112  if (Attr & FILE_ATTRIBUTE_SYSTEM) pz = _scatCh( pz, _T('S') );
1113  if (Attr & FILE_ATTRIBUTE_ARCHIVE) pz = _scatCh( pz, _T('A') );
1114  //
1115  if (Attr & FILE_ATTRIBUTE_COMPRESSED) pz = _scatCh( pz, _T('C') );
1116  if (Attr & FILE_ATTRIBUTE_ENCRYPTED) pz = _scatCh( pz, _T('E') );
1117  if (Attr & FILE_ATTRIBUTE_OFFLINE) pz = _scatCh( pz, _T('O') );
1118  if (Attr & FILE_ATTRIBUTE_REPARSE_POINT) pz = _scatCh( pz, _T('P') );
1119  if (Attr & FILE_ATTRIBUTE_SPARSE_FILE) pz = _scatCh( pz, _T('Z') );
1120  if (Attr & FILE_ATTRIBUTE_TEMPORARY) pz = _scatCh( pz, _T('T') );
1121  return sbuf;
1122 }
1123 
1124 CSTR FileTimeStr( FILETIME* FTime, CSTR Fmt )
1125 {
1126  SYSTEMTIME st;
1127  FileTimeToSystemTime( FTime, &st );
1128  return SysTimeStr( &st, Fmt );
1129 }
1130 
1131 CSTR SysTimeStr( SYSTEMTIME* Time, CSTR Fmt )
1132 {
1133  static TCHAR sbuf[ 80 ]; // Not on stack.
1134  struct tm T;
1135 
1136  sbuf[0] = 0;
1137  T.tm_sec = Time->wSecond;
1138  T.tm_min = Time->wMinute;
1139  T.tm_hour = Time->wHour;
1140  T.tm_mday = Time->wDay; // day of the month - [1,31]
1141  T.tm_mon = Time->wMonth - 1; // months since January - [0,11]
1142  T.tm_year = Time->wYear - 1900; // years since 1900
1143  T.tm_wday = Time->wDayOfWeek; // days since Sunday - [0,6]
1144  T.tm_yday = 0; // ComputeDayNr( T ); // days since January 1 - [0..365]
1145  T.tm_isdst = 0; // GetDaylightSavings( T, timezone ); // daylight savings time flag
1146 
1147  _tcsftime( sbuf,40, Fmt, &T );
1148  return sbuf;
1149 }
1150 
1152 {
1153  static TCHAR sbuf[ 80 ]; // In data section, not on stack. Mind concurrency!
1154 
1155  bool shInit = ShellFuncInitialized(); // Is shell access already initialized?
1156  if (!shInit) InitShellFunc();
1157 
1158  SHFILEINFO fi;
1159  if (SHGetFileInfo( FName, 0, &fi, sizeof(fi), SHGFI_TYPENAME ))
1160  _tcscpy_s( sbuf, dimof(sbuf), fi.szTypeName );
1161  else sbuf[0] = 0;
1162 
1163  if (!shInit) DoneShellFunc(); // If it wasn't then revert before returning
1164  return sbuf;
1165 }
1166 
1167 //==----------------------------------------------------------------------------
1168 // EngFormat - Format value with engineering/scientific SI prefix unit.
1169 //==----------------------------------------------------------------------------
1170 
1171 CSTR EngFormat( long double Value, BYTE nDecimals, CSTR Unit )
1172 {
1173  static CCSTR pfix = _T("yzafpnum kMGTPEZY"); // SI Prefix 10^-24 .. 10^24
1174  static const int midIx = 8; // Whole units, no prefix
1175  //static CCSTR smallPfix = _T("cd hD");
1176 
1177  // 10^24 yotta Y
1178  // 10^21 zetta Z
1179  // 10^18 exa E
1180  // 10^15 peta P
1181  // 10^12 tera T
1182  // 10^9 giga G
1183  // 10^6 mega M
1184  // 10^3 kilo k
1185  // #10^2 hekto h // not supported
1186  // #10^1 deka da // not supported
1187  // 1 // unity
1188  // #10^-1 deci d // not supported
1189  // #10^-2 centi c // not supported
1190  // 10^-3 milli m
1191  // 10^-6 micro µ
1192  // 10^-9 nano n
1193  // 10^-12 pico p
1194  // 10^-15 femto f
1195  // 10^-18 atto a
1196  // 10^-21 zepto z
1197  // 10^-24 yocto y
1198 
1199  static TCHAR sbuf[ 50 ];
1200  TCHAR pfixCh;
1201  int expo;
1202 
1203  Value = EngUnits( Value, &expo ); // In UtilFunc.cpp
1204  sbuf[0] = 0;
1205  if (!Unit) Unit = S_BLANK; // Suffix ?
1206 
1207  // MS (and MinGW) CRTL flavor of printf doesn't support 80-bit long double,
1208  // so we must unfortunately truncate them to a measly 64-bit precision :/
1209 
1210  double val = (double) Value;
1211 
1212  if (expo == 0)
1213  _stprintf_s( sbuf, dimof(sbuf), _T("%.*f %s"), nDecimals, val, Unit );
1214  else if (expo < -24 || expo > 24)
1215  _stprintf_s( sbuf, dimof(sbuf), _T("%.*fe%i %s"), nDecimals, val, expo, Unit );
1216  else
1217  {
1218  pfixCh = pfix[ midIx + (expo/3) ];
1219  _stprintf_s( sbuf, dimof(sbuf), _T("%.*f %c%s"), nDecimals, val, pfixCh, Unit );
1220  }
1221  return sbuf;
1222 }
1223 
1224 //==----------------------------------------------------------------------------
1225 // GUID strings
1226 //==----------------------------------------------------------------------------
1227 
1228 // Note that these APIs use static result buffers, so they're not re-entrant.
1229 
1230 CSTR GetGUIDString( REFIID riid, TSTR pzBuf, UINT ccBuf ) // GUID
1231 {
1232  static TCHAR szBuf[ 64 ]; // 39++
1233  static CCSTR S_GuidFmt = _T("{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}");
1234  //static CCSTR S_GuidFmt2 = _T("{ %08X, %04X, %04X, { %02X,%02X,%02X,%02X, %02X,%02X,%02X,%02X }}");
1235 
1236  if (!pzBuf)
1237  {
1238  pzBuf = szBuf;
1239  ccBuf = dimof(szBuf);
1240  }
1241  _stprintf_s( pzBuf, ccBuf, S_GuidFmt,
1242  riid.Data1, riid.Data2, riid.Data3, riid.Data4[0], riid.Data4[1],
1243  riid.Data4[2], riid.Data4[3], riid.Data4[4], riid.Data4[5],
1244  riid.Data4[6], riid.Data4[7]
1245  );
1246  return szBuf;
1247 }
1248 
1249 CSTR GetIIDString( REFIID riid, TSTR pzBuf, UINT ccBuf )
1250 {
1251  static TCHAR szBuf[ 128 ];
1252 
1253  TCHAR regPath[ 64 ];
1254  CSTR pzGuid = GetGUIDString( riid );
1255  int len = _stprintf_s( regPath, dimof(regPath), _T("Interface\\%s"), pzGuid );
1256  UNUSED( len );
1257 
1258  if (!pzBuf)
1259  {
1260  pzBuf = szBuf;
1261  ccBuf = dimof(szBuf);
1262  }
1263  *pzBuf = 0;
1264 
1265  TSTR pzDst = _tcsecpy( pzBuf, _T("IID_") );
1266  ccBuf -= 4; // "IID_"
1267  LONG cbData = ccBuf;
1268  #ifdef _UNICODE
1269  cbData *= sizeof(WCHAR);
1270  #endif
1271 
1272  bool ok = REG_OK( RegQueryValue( HKEY_CLASSES_ROOT, regPath, pzDst, &cbData ));
1273  if (!ok) _tcsncpyz( pzBuf, pzGuid, ccBuf ); // Rtn only the GUID string
1274 
1275  return pzBuf;
1276 }
1277 
1278 CSTR GetCLSIDString( REFIID riid, TSTR pzBuf, UINT ccBuf )
1279 {
1280  static TCHAR szBuf[256];
1281  if (!pzBuf)
1282  {
1283  pzBuf = szBuf;
1284  ccBuf = dimof(szBuf);
1285  }
1286  *pzBuf = 0;
1287  LPOLESTR poStr = NULL;
1288  HRESULT rc = OleRegGetUserType( riid, USERCLASSTYPE_SHORT, &poStr );
1289  if (FAILED( rc ) || !poStr)
1290  GetGUIDString( riid, pzBuf, ccBuf ); //_tcsncpyz( pzBuf, GetGUIDString( riid ), ccBuf );
1291  else
1292  {
1293  TSTR pzDst;
1294  if (0 == wcsncmp( poStr, L"CLSID_", 6 )) pzDst = pzBuf;
1295  else
1296  {
1297  pzDst = _tcsecpy( pzBuf, _T("CLSID_") );
1298  ccBuf -= 6; // "CLSID_"
1299  }
1300  #ifdef _UNICODE
1301  wcsncpyz( pzDst, poStr, ccBuf );
1302  #else
1303  WideCharToMultiByte( CP_ACP,0, poStr, -1, pzDst, ccBuf, NULL, NULL );
1304  #endif
1305  }
1306  if (poStr) CoTaskMemFree( poStr );
1307  return pzBuf;
1308 }
1309 
1310 CSTR GetCLSIDAppname( REFIID riid, TSTR pzBuf, UINT ccBuf )
1311 {
1312  static TCHAR szBuf[256];
1313  if (!pzBuf)
1314  {
1315  pzBuf = szBuf;
1316  ccBuf = dimof(szBuf);
1317  }
1318  *pzBuf = 0;
1319  LPOLESTR poStr = NULL;
1320  HRESULT rc = OleRegGetUserType( riid, USERCLASSTYPE_APPNAME, &poStr );
1321  if (FAILED( rc ) || !poStr)
1322  _tcsncpyz( pzBuf, GetGUIDString( riid ), ccBuf );
1323  else
1324  {
1325  #ifdef _UNICODE
1326  wcsncpyz( pzBuf, poStr, ccBuf );
1327  #else
1328  WideCharToMultiByte( CP_ACP,0, poStr, -1, pzBuf, ccBuf, NULL, NULL );
1329  #endif
1330  }
1331  if (poStr) CoTaskMemFree( poStr );
1332  return pzBuf;
1333 }
1334 
1335 //==----------------------------------------------------------------------------
1336 // UNICODE_STRING support
1337 //==----------------------------------------------------------------------------
1338 #ifndef NO_WINTERNAL // UNICODE_STRING
1339 
1340 PUNICODE_STRING _InitUnicodeString( PUNICODE_STRING puStr, PCWSTR pwzSrc )
1341 {
1342  puStr->Buffer = (PWSTR) pwzSrc;
1343  if (!pwzSrc) puStr->Length = puStr->MaximumLength = 0;
1344  else
1345  {
1346  puStr->Length = (USHORT) wcslen( pwzSrc ) * sizeof(WCHAR);
1347  puStr->MaximumLength = puStr->Length + sizeof(WCHAR); // Incl _NUL
1348  }
1349  return puStr;
1350 }
1351 
1352 PSTRING _InitString( PSTRING pStr, LPCSTR pzSrc )
1353 {
1354  pStr->Buffer = (LPSTR) pzSrc;
1355  if (!pzSrc) pStr->Length = pStr->MaximumLength = 0;
1356  else
1357  {
1358  pStr->Length = (USHORT) strlen( pzSrc );
1359  pStr->MaximumLength = pStr->Length + 1;
1360  }
1361  return pStr;
1362 }
1363 
1364 PUNICODE_STRING InitPackedUnicodeString( PVOID Buffer, USHORT cbBuffer )
1365 {
1366  INIT_PACKED_UNICODE_STRING( (PUNICODE_STRING) Buffer, cbBuffer );
1367  return (PUNICODE_STRING) Buffer;
1368 }
1369 
1370 bool SetUnicodeString( PUNICODE_STRING puStr, WCSTR wzSrc )
1371 {
1372  USHORT cbSrc = (USHORT) wcsbytes( wzSrc ); // Including _NUL
1373  bool ok = (cbSrc <= puStr->MaximumLength);
1374  if ( ok )
1375  {
1376  puStr->Length = cbSrc - WCHAR_SIZE; // Excluding _NUL
1377  memcpy( puStr->Buffer, wzSrc, cbSrc );
1378  }
1379  return ok;
1380 }
1381 
1382 PUNICODE_STRING mem_AllocUniStr( WORD ccStr, PULONG cbAlloc )
1383 {
1384  UINT cbStr = (ccStr + 2) * WCHAR_SIZE; // 2 extra ch (double _NUL)
1385  UINT cbBuf = sizeof(UNICODE_STRING) + cbStr;
1386 
1387  PUNICODE_STRING pu = (PUNICODE_STRING) mem_Alloc( cbBuf );
1388  if ( pu )
1389  {
1390  pu->Length = 0; pu->MaximumLength = cbStr;
1391  pu->Buffer = PWSTR( pu + 1 ); // Note: C typed ptr arithmetic.
1392  }
1393  if (cbAlloc) *cbAlloc = cbBuf;
1394  return pu;
1395 }
1396 
1397 #endif//ndef NO_WINTERNAL // UNICODE_STRING
1398 #ifdef __cplusplus
1399 
1400 //==----------------------------------------------------------------------------
1401 // UString - UNICODE_STRING class with automatic conversion
1402 //==----------------------------------------------------------------------------
1403 #ifndef NO_WINTERNAL // UNICODE_STRING
1404 
1405 UString::UString() : Flags( 0 )
1406 {
1407  _InitUnicodeString( this, NULL );
1408 }
1409 
1410 UString::UString( WCSTR Src ) : Flags( 0 )
1411 {
1412  MaximumLength = 0;
1413  Buffer = NULL;
1414  Set( Src );
1415 }
1416 
1417 UString::UString( ACSTR Src ) : Flags( 0 )
1418 {
1419  MaximumLength = 0;
1420  Buffer = NULL;
1421  Set( Src );
1422 }
1423 
1424 UString::UString( const UNICODE_STRING& Src ) : Flags( 0 )
1425 {
1426  MaximumLength = 0;
1427  Buffer = NULL;
1428  Set( Src );
1429 }
1430 
1431 UString::UString( size_t Len ) : Flags( 0 )
1432 {
1433  Length = MaximumLength = 0;
1434  Buffer = NULL;
1435  _allocBuf( Len );
1436 }
1437 
1439 {
1440  _freeBuf();
1441 }
1442 
1443 void UString::Set( WCSTR Src )
1444 {
1445  _freeBuf(); // Wide source don't require a conversion buffer.
1446  _InitUnicodeString( this, Src );
1447 }
1448 
1449 bool UString::Set( ACSTR Src )
1450 {
1451  Length = Src ? (USHORT) strlen( Src ) : 0;
1452  bool ok = _allocBuf( Length ); // Ansi source require a conversion buffer.
1453  if (!ok) Length = 0;
1454  else if ( Src )
1455  {
1456  MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, Src, Length+1, Buffer, Length+1 );
1457  Length *= sizeof(WCHAR);
1458  }
1459  return ok;
1460 }
1461 
1462 bool UString::Set( const UNICODE_STRING& Src )
1463 {
1464  USHORT Len = Src.Length / sizeof(WCHAR);
1465  USHORT Max = Src.MaximumLength / sizeof(WCHAR);
1466  bool ok = true; // All but one path in here lead to success.
1467 
1468  if (Src.Buffer[ Len ] != 0) // If not already null terminated...
1469  {
1470  if ((Max > Len) && !IsBadWritePtr( Src.Buffer + Len, WCHAR_SIZE ))
1471  {
1472  Src.Buffer[ Len ] = 0; // NUL terminate in place
1473  goto shallow_Copy;
1474  }
1475  else // Source buffer is too small for NUL termination
1476  {
1477  if (_allocBuf( Len )) // Sets MaximumLength on success
1478  {
1479  memcpy( Buffer, Src.Buffer, Src.Length );
1480  Buffer[ Len ] = 0;
1481  }
1482  else // The probability of this is infinitessimally small.
1483  {
1484  ok = false;
1485  TRACE( DP_ERROR, _F("Alloc failed. Target will not be NUL terminated!\n") );
1486  BREAK();
1487  goto shallow_Copy;
1488  }
1489  }
1490  }
1491  else // Source is already NUL terminated
1492  {
1493  shallow_Copy: _freeBuf(); // Free internal buffer, if any
1494  MaximumLength = Src.MaximumLength;
1495  Buffer = Src.Buffer;
1496  }
1497  Length = Src.Length;
1498  return ok;
1499 }
1500 
1502 {
1503  Set( Src );
1504  return *this;
1505 }
1506 
1508 {
1509  Set( Src );
1510  return *this;
1511 }
1512 
1513 UString& UString::operator = ( const UNICODE_STRING& Src )
1514 {
1515  Set( Src );
1516  return *this;
1517 }
1518 
1519 bool UString::_allocBuf( size_t nChar )
1520 {
1521  static const size_t _CHUNK = 16;
1522 
1523  size_t nBytes = nChar * sizeof(WCHAR);
1524  bool ok = ((Flags & UF_OWN_BUFFER) && (MaximumLength > nBytes));
1525  if (!ok)
1526  {
1527  nBytes += sizeof(WCHAR); // Add space for NUL terminator
1528  MaximumLength = (USHORT) ROUND_UP( nBytes, _CHUNK );
1529  if (!(Flags & UF_OWN_BUFFER)) Buffer = NULL;
1530 
1531  if (!Buffer) Buffer = (PWSTR) mem_Alloc( MaximumLength );
1532  else Buffer = (PWSTR) mem_Realloc( Buffer, MaximumLength );
1533 
1534  ok = (Buffer != NULL);
1535  if (ok) Flags |= UF_OWN_BUFFER;
1536  else
1537  {
1538  Length = MaximumLength = 0;
1539  Flags &= ~UF_OWN_BUFFER;
1540  }
1541  }
1542  return ok;
1543 }
1544 
1545 void UString::_freeBuf()
1546 {
1547  if ((Flags & UF_OWN_BUFFER) && Buffer) mem_Free( Buffer );
1548  Length = MaximumLength = 0;
1549  Flags &= ~UF_OWN_BUFFER;
1550  Buffer = NULL;
1551 }
1552 
1553 #endif//ndef NO_WINTERNAL
1554 //==----------------------------------------------------------------------------
1555 // StringCache
1556 //==----------------------------------------------------------------------------
1557 
1558 StringCache::StringCache( UINT InitSize, UINT ChunkSize )
1559 {
1560  StgUsed = 0; // Memory amount
1561 
1562  // The defaults used here protect thoughtless callers from themselves,
1563  // and enssure proper function of the StringCache instance..
1564 
1565  StgChunk = ChunkSize ? ChunkSize : 1024; // Better safe than sorry..
1566  StgSize = InitSize ? ROUND_UP( InitSize, StgChunk ) : StgChunk;
1567 
1568  Storage = (char*) mem_Alloc( StgSize );
1569  if (!Storage) StgSize = 0;
1570 }
1571 
1573 {
1574  mem_Free( Storage );
1575 }
1576 
1578 {
1579  if (Storage) Storage[ StgUsed = 0 ] = 0; // Hehe.. ;)
1580 }
1581 
1583 {
1584  Storage = (char*) mem_Free( Storage );
1585  StgSize = StgUsed = 0;
1586 }
1587 
1589 {
1590  bool ok = false;
1591  UINT newSize = StgSize + StgChunk;
1592  #ifdef HAVE_STRUCTURED_EH
1593  __try {
1594  #endif
1595  char* tmp = Storage
1596  ? (char*) mem_Realloc( Storage, newSize )
1597  : (char*) mem_Alloc( newSize ); // If repurposed after Free().
1598  ok = (tmp != NULL);
1599  if (ok)
1600  {
1601  Storage = tmp;
1602  StgSize = newSize;
1603  }
1604  TRACE( DP_DEBUG, _F("[%p] newSize=%li (%s)\n"), Storage, newSize, ok ? "ok":"fail" );
1605  #ifdef HAVE_STRUCTURED_EH
1606  } __except_execute {
1607  DWORD xcode = GetExceptionCode();
1608  TRACE( DP_DEBUG, _F("[%p] newSize=%li: Exceprion 0x%08x)\n"), Storage, newSize, xcode );
1609  BREAK();
1610  }
1611  __end_except
1612  #endif
1613  return ok;
1614 }
1615 
1616 char* StringCache::DupStr( char* Str )
1617 {
1618  UINT len = UINT( 1 + strlen( Str ));
1619  UINT end = StgUsed + len + 1;
1620  if (end > StgSize) GrowStorage();
1621 
1622  char* dup = NULL;
1623  #ifdef HAVE_STRUCTURED_EH
1624  __try {
1625  #endif
1626  dup = &Storage[ StgUsed ];
1627  memcpy( dup, Str, len );
1628  // Second multi-sz null is added below..
1629  #ifdef HAVE_STRUCTURED_EH
1630  } __except_execute {
1631  DWORD xcode = GetExceptionCode();
1632  TRACE( DP_ERROR, _F("Exception 0x%08X\n"), xcode );
1633  BREAK();
1634  }
1635  __end_except
1636  #endif
1637 
1638  StgUsed += len;
1639  Storage[ StgUsed ] = 0; // Extra null char (for multi-sz)
1640  return dup;
1641 }
1642 
1643 //---------------------------------------------------------------------------------------
1644 #if 0 // UNDER CONSIDERATION. Initial alphatest passed..
1645 
1646 template <typename TCh>
1647 class TStringCache {
1648 public:
1649  TCh* Storage;
1650 
1654 
1655  TStringCache( UINT InitSize DEF_(4096), UINT ChunkSize DEF_(4096) )
1656  {
1657  StgUsed = 0; // Memory amount
1658 
1659  // The defaults used here protect thoughtless callers from themselves,
1660  // and enssure proper function of the StringCache instance..
1661 
1662  StgChunk = ChunkSize ? ChunkSize : 1024; // Better safe than sorry..
1663  StgSize = InitSize ? ROUND_UP( InitSize, StgChunk ) : StgChunk;
1664  //StgSize *= sizeof(TCh); // No, sizes are already in bytes!
1665 
1666  Storage = (TCh*) mem_Alloc( StgSize );
1667  if (!Storage) StgSize = 0;
1668  }
1669 
1670  // TODO: Add ctor for existing multi-sz block, eg. ini section..
1671 
1672  ~TStringCache()
1673  {
1674  mem_Free( Storage );
1675  }
1676 
1677  TCh* DupStr( TCh* Str )
1678  {
1679  //UINT len = UINT( 1 + strlen( Str )); // FIXME
1680  TCh* _pz = Str; while( *_pz != 0 ) _pz++;
1681  // TODO: Add length constraint..
1682  UINT nbytes = UINT_PTR(_pz) - UINT_PTR(Str) + sizeof(TCh); // Incl NUL
1683  UINT end = StgUsed + nbytes;
1684  if (end > StgSize) GrowStorage();
1685 
1686  TCh* dup = NULL;
1687  #ifdef HAVE_STRUCTURED_EH
1688  __try {
1689  #endif
1690  dup = &Storage[ StgUsed ];
1691  memcpy( dup, Str, nbytes ); // Incl NUL
1692  // Second multi-sz null is added below..
1693  #ifdef HAVE_STRUCTURED_EH
1694  } __except_execute {
1695  DWORD xcode = GetExceptionCode();
1696  DebugBreak();
1697  //TRACE( DP_DEBUG, _F("Exception 0x%08X\n"), xcode );
1698  //BREAK();
1699  }
1700  __end_except
1701  #endif
1702 
1703  StgUsed += nbytes;
1704  Storage[ StgUsed ] = 0; // Extra null char (for multi-sz)
1705  return dup;
1706  }
1707 
1708  void Reset()
1709  {
1710  if (Storage) Storage[ StgUsed = 0 ] = 0; // Hehe.. ;)
1711  }
1712 
1713  void Free()
1714  {
1715  Storage = (TCh*) mem_Free( Storage );
1716  StgSize = StgUsed = 0;
1717  }
1718 
1719  int StorageSize() { return StgSize; }
1720  int StorageUsed() { return StgUsed; }
1721 
1722 protected:
1723  UINT StgSize, StgUsed, StgChunk; // Storage size, used, chunk size
1724  bool GrowStorage() // Grow the string content block.
1725  {
1726  bool ok = false;
1727  UINT newSize = StgSize + StgChunk;
1728  #ifdef HAVE_STRUCTURED_EH
1729  __try {
1730  #endif
1731  TCh* tmp = Storage
1732  ? (TCh*) mem_Realloc( Storage, newSize )
1733  : (TCh*) mem_Alloc( newSize ); // If repurposed after Free().
1734  ok = (tmp != NULL);
1735  if (ok)
1736  {
1737  Storage = tmp;
1738  StgSize = newSize;
1739  }
1740  //TRACE( DP_DEBUG, _F("[%p] newSize=%li (%s)\n"), Storage, newSize, ok ? "ok":"fail" );
1741  #ifdef HAVE_STRUCTURED_EH
1742  } __except_execute {
1743  DWORD xcode = GetExceptionCode();
1744  //TRACE( DP_DEBUG, _F("[%p] newSize=%li: Exceprion 0x%08x)\n"), Storage, newSize, xcode );
1745  //BREAK();
1746  }
1747  __end_except
1748  #endif
1749  return ok;
1750  }
1751 }; // TStringCache
1752 #endif
1753 
1754 //==----------------------------------------------------------------------------
1755 // WordList
1756 //==----------------------------------------------------------------------------
1757 
1758 WordList::WordList( UINT InitListDim, UINT InitStgSize, UINT ListGrowBy, UINT StgGrowBy )
1759 : StringCache( InitStgSize, StgGrowBy )
1760 {
1761  Count = 0;
1762  ListChunk = ListGrowBy ? ListGrowBy : 32; // Better safe than sorry
1763  Dim = InitListDim ? ROUND_UP( InitListDim, ListChunk ) : ListChunk;
1764  Strings = (char**) mem_Alloc( Dim * sizeof(char*) );
1765  if (!Strings) Dim = 0;
1766 }
1767 
1769 {
1770  mem_Free( Strings );
1771 }
1772 
1774 {
1775  Count = 0;
1777 }
1778 
1780 {
1782  Strings = (char**) mem_Free( Strings );
1783  Dim = Count = 0;
1784 }
1785 
1787 {
1788  int newDim = Dim + ListChunk;
1789  int newSize = newDim * sizeof(char*);
1790  char** tmp = Strings
1791  ? (char**) mem_Realloc( Strings, newSize )
1792  : (char**) mem_Alloc( newSize );
1793  bool ok = (tmp != NULL);
1794  if (ok)
1795  {
1796  Strings = tmp;
1797  Dim = newDim;
1798  }
1799  TRACE( DP_DEBUG, _F("[%p] newSize=%li(%li) (%s)\n"), Strings, newSize, newDim, ok ? "ok":"fail" );
1800  return ok;
1801 }
1802 
1803 bool WordList::AddString( char* Str, bool caseSens )
1804 {
1805  bool added = false;
1806  UINT cbMove;
1807 
1808  int (*cmpfunc)( const char *string1, const char *string2 );
1809  cmpfunc = caseSens ? strcmp : _stricmp;
1810 
1811  // Iterative binary search...
1812 
1813  int l = 0, r = Count-1, m = 0, cmp = 0;
1814  while( l <= r )
1815  {
1816  m = l + (r - l) / 2;
1817  cmp = cmpfunc( Str, Strings[ m ]);
1818  if (cmp == 0) // Don't add, it's already there.
1819  {
1820  TRACE( DP_DEBUG, _F("Skip duplicate: %s\n"), Str );
1821  #if defined(__GNUC__)
1822  return false;
1823  #else
1824  goto add_Done;
1825  #endif
1826  }
1827  else if (cmp > 0) l = m + 1;
1828  else r = m - 1;
1829  }
1830 
1831  // Not found...
1832 
1833  #ifdef HAVE_STRUCTURED_EH
1834  __try {
1835  #endif
1836  if (cmp > 0) m++; // Compute where it would have been if it existed.
1837  if (Count == Dim) Grow(); // If list is full, grow it.
1838 
1839  cbMove = (Count - m) * sizeof(char*);
1840  if (cbMove) memmove( &Strings[ m + 1 ], &Strings[ m ], cbMove ); // Make a hole..
1841 
1842  // Insert new cache item in sorted order.
1843  // Relocate the previous Strings if Storage changed due to realloc.
1844 
1845  INT_PTR preDup = (INT_PTR) Storage;
1846  Strings[ m ] = StringCache::DupStr( Str ); // Cache it
1847  INT_PTR offset = INT_PTR(Storage) - preDup;
1848  if (offset)
1849  {
1850  // Relocate preexisting string ptrs if the Storage block changed
1851  // address during a GrowStorage call in DupStr. Use the offset
1852  // between old and new Storage block to adjust the Strings pointers.
1853 
1854  for( UINT ix=0; ix <= Count; ix++ )
1855  {
1856  if (ix == UINT(m)) continue; // Dont clobber the present insert
1857  LITERAL( INT_PTR, Strings[ix] ) += offset; // Adjust string ptr
1858  }
1859  }
1860 
1861  added = true;
1862  Count++;
1863  #ifdef HAVE_STRUCTURED_EH
1864  } __except_execute {
1865  DWORD xcode = GetExceptionCode();
1866  TRACE( DP_ERROR, _F("Exception 0x%08X\n"), xcode );
1867  BREAK();
1868  }
1869  __end_except
1870  #endif
1871 add_Done:
1872  return added;
1873 }
1874 
1875 char* WordList::Search( char* Key,
1876  int (__stdcall *Compare)( char* Key, char* Str, void* Ctx ),
1877  void* Context )
1878 {
1879  char* item = NULL;
1880 
1881  // Iterative binary search...
1882 
1883  int l = 0, m = 0, r = Count-1, cmp = 0;
1884  while( l <= r )
1885  {
1886  m = l + (r - l) / 2;
1887  cmp = Compare( Key, Strings[ m ], Context );
1888  if (cmp == 0) // If found
1889  {
1890  item = Strings[ m ];
1891  break;
1892  }
1893  else if (cmp > 0) l = m + 1;
1894  else r = m - 1;
1895  }
1896 
1897  return item;
1898 }
1899 
1900 //==----------------------------------------------------------------------------
1901 #endif//def __cplusplus
1902 // EOF
UINT MultiSzLengthW(WCSTR MultiSz)
Definition: StrFunc.cpp:430
UINT ListChunk
Definition: StrFunc.h:827
UINT MultiSzLengthA(ACSTR MultiSz)
Definition: StrFunc.cpp:423
TSTR DuplicateMultiSz(CSTR pzMulti)
Definition: StrFunc.cpp:527
unsigned long DWORD
Definition: Common.h:414
#define DOT
Definition: Common.h:1216
UINT StgChunk
Definition: StrFunc.h:735
#define REG_OK(rc)
Definition: RegFunc.h:34
END_STRSAFE_OVERRIDE ACSTR _MBStr(WCSTR pwStr)
Definition: StrFunc.cpp:281
const char * ACSTR
Definition: Common.h:345
ULONG GetStringHash(WCSTR Str, ULONG Algorithm, bool caseSens)
Definition: StrFunc.cpp:947
#define CSTR
Definition: Common.h:329
char * Storage
Definition: StrFunc.h:706
WCSTR FindResourceStrEx(HMODULE hModule, UINT Id, LANGID Lang, PWORD pCount)
Definition: StrFunc.cpp:339
CSTR WithoutBackslash(CSTR PathName)
Definition: StrFunc.cpp:668
CSTR WithBackslash(CSTR PathName)
Definition: StrFunc.cpp:682
#define S_BLANK
Definition: Common.h:1235
UINT EnumerateMultiSzA(ASTR MultiSz, PFnEnumMultiStringA Action, PVOID Context)
Definition: StrFunc.cpp:392
CSTR mem_FreeStr(CSTR Dup)
Definition: StrFunc.cpp:270
CSTR FileTimeStr(FILETIME *FTime, CSTR Fmt)
Definition: StrFunc.cpp:1124
unsigned short WORD
Definition: Common.h:413
UINT MultiSzCountA(ACSTR MultiSz)
Definition: StrFunc.cpp:439
PUNICODE_STRING mem_AllocUniStr(WORD ccStr, PULONG cbAlloc)
Definition: StrFunc.cpp:1382
CSTR FreeResourceStrEx(CSTR pzRcDupStr)
Definition: StrFunc.cpp:383
#define INIT_PACKED_UNICODE_STRING(pu, bufsize)
Definition: StrFunc.h:607
void * mem_Realloc(void *pBlk, size_t Bytes)
Definition: MemFunc.cpp:80
PUNICODE_STRING _InitUnicodeString(PUNICODE_STRING puStr, PCWSTR pwzSrc)
Definition: StrFunc.cpp:1340
#define TCHAR_SIZE
Definition: Common.h:376
#define DP_DEBUG
Definition: Debug.h:85
ASTR mem_ADupWStr(WCSTR pWStr, UINT CodePg, UINT ccExtra)
Definition: StrFunc.cpp:290
TSTR MultiCrLfToLf(TSTR pText)
Definition: StrFunc.cpp:467
void * mem_Alloc(size_t Bytes)
Definition: MemFunc.cpp:33
BEGIN_STRSAFE_OVERRIDE CSTR newStr(CSTR Src)
Definition: StrFunc.cpp:167
wchar_t * WSTR
Definition: Common.h:366
long double EngUnits(long double Value, int *pExpo)
Definition: UtilFunc.cpp:180
#define BEGIN_STRSAFE_OVERRIDE
Definition: StrFunc.h:28
#define TSTR
Definition: Common.h:328
unsigned char * PBYTE
Definition: Common.h:412
TSTR ReplaceStrChar(TSTR Str, TCHAR From, TCHAR To, OPTOUT UINT *pCount)
Definition: StrFunc.cpp:699
bool InitShellFunc(bool useOle=false, DWORD coFlag=COINIT_APARTMENTTHREADED)
Definition: ShellUtil.cpp:37
char * ASTR
Definition: Common.h:344
bool SplitUncPath(CSTR UncPath, TSTR Svr, UINT ccSvr, TSTR Share, UINT ccShare, TSTR Path, UINT ccPath)
Definition: StrFunc.cpp:568
#define dimof(x)
Definition: Common.h:949
#define OPTOUT
Definition: Common.h:264
PUNICODE_STRING InitPackedUnicodeString(PVOID Buffer, USHORT cbBuffer)
Definition: StrFunc.cpp:1364
TSTR newStrBuf(WORD nChar)
Definition: StrFunc.cpp:183
CSTR LoadStr(HMODULE hModule, UINT Id, TSTR Buf, UINT Count)
Definition: StrFunc.cpp:310
wchar_t *__fastcall wcsncpyz(register wchar_t *Dst, register const wchar_t *Src, size_t Count)
Definition: StrFunc.cpp:142
void Reset()
Definition: StrFunc.cpp:1773
WORD Flags
Definition: StrFunc.h:634
#define _INVALPARM
UINT Count
Definition: StrFunc.h:785
#define TRACE(_lvl,...)
Definition: Debug.h:216
bool SplitNetShareName(IN CSTR ShareName, OUT WSTR Server, UINT ccServer, OUT WSTR Share, UINT ccShare)
Definition: StrFunc.cpp:634
bool(__stdcall * PFnEnumMultiStringW)(WSTR Str, PVOID Context)
Definition: StrFunc.h:287
WSTR mem_WDupAStr(ACSTR pAStr, UINT CodePg, UINT ccExtra)
Definition: StrFunc.cpp:298
UINT StgUsed
Definition: StrFunc.h:735
#define EnumerateMultiSz
Definition: StrFunc.h:275
UINT DeduplicateCharSepText(ASTR Text, CHAR Separator, bool caseSens, bool emitSorted)
Definition: StrFunc.cpp:847
TSTR LinesToMultiSz(TSTR pText, UINT *ccSz)
Definition: StrFunc.cpp:493
void Reset()
Definition: StrFunc.cpp:1577
char * stristr(const char *str, const char *pattern)
Definition: StrFunc.cpp:96
char * DupStr(char *Str)
Definition: StrFunc.cpp:1616
bool ShellFuncInitialized()
Definition: ShellUtil.cpp:24
#define __except_execute
Definition: Common.h:647
const wchar_t * WCSTR
Definition: Common.h:367
#define DELETE_ARRAY(A)
Definition: Common.h:992
UINT EnumerateMultiSzW(WSTR MultiSz, PFnEnumMultiStringW Action, PVOID Context)
Definition: StrFunc.cpp:407
bool MatchPattern(CSTR String, CSTR Pattern, bool CaseSens)
Definition: StrFunc.cpp:743
class WordList * PWordList
Definition: StrFunc.h:830
#define _tcsecpy
Definition: StrFunc.h:74
UINT StgSize
Definition: StrFunc.h:735
CSTR GetIIDString(REFIID riid, TSTR pzBuf, UINT ccBuf)
Definition: StrFunc.cpp:1249
ASTR mem_AllocAStr(WORD nChar)
Definition: StrFunc.cpp:258
#define BREAK()
Definition: Debug.h:208
CSTR GetGUIDString(REFIID riid, TSTR pzBuf, UINT ccBuf)
Definition: StrFunc.cpp:1230
BOOL(WINAPI *SysImgList::Shell_GetImageLists)(HIMAGELIST *pimlLarge
const LPCTSTR CCSTR
Definition: Common.h:335
PVOID WINAPI LoadCustomResourceEx(HMODULE hModule, CSTR Id, CSTR Type, LANGID Language OPTIN=0, UINT *pSize OPTOUT=NULL)
#define mem_AllocStr
Definition: StrFunc.h:142
void * mem_Free(void *pBlk)
Definition: MemFunc.cpp:124
TSTR MultiSzToLines(TSTR pText)
Definition: StrFunc.cpp:514
CSTR GetCLSIDAppname(REFIID riid, TSTR pzBuf, UINT ccBuf)
Definition: StrFunc.cpp:1310
_NTFN_EXTERN NTSTATUS _RtlHashUnicodeString(IN CONST UNICODE_STRING *String, IN BOOLEAN CaseInSensitive, IN ULONG HashAlgorithm, OUT PULONG HashValue)
char ** Strings
Definition: StrFunc.h:780
WSTR mem_AllocWStr(WORD nChar)
Definition: StrFunc.cpp:264
char *__fastcall strnecpy(register char *Dst, register const char *Src, size_t n)
Definition: StrFunc.cpp:77
void Set(WCSTR Src)
Definition: StrFunc.cpp:1443
void Free()
Definition: StrFunc.cpp:1779
bool SetLastErrorFromNtStatus(NTSTATUS Status)
Definition: Debug.cpp:74
CSTR EngFormat(long double Value, BYTE nDecimals, CSTR Unit)
Definition: StrFunc.cpp:1171
StringCache(UINT InitSize=4096, UINT ChunkSize=4096)
Definition: StrFunc.cpp:1558
CSTR __cdecl StrFmt(TSTR Buf, UINT ccBuf, CSTR Fmt,...)
Definition: StrFunc.cpp:545
#define SPACE
Definition: Common.h:1219
UString & operator=(WCSTR Src)
Definition: StrFunc.cpp:1501
bool __GetRoot(OUT TSTR Root, UINT ccRoot, IN CSTR PathName)
bool SetUnicodeString(PUNICODE_STRING puStr, WCSTR wzSrc)
Definition: StrFunc.cpp:1370
#define ROUND_UP(x, chunk)
Definition: Common.h:979
unsigned __int64 UINT64
Definition: Common.h:400
CSTR IsoDataSizeStr(UINT64 _Size)
Definition: StrFunc.cpp:1066
__inline bool __ChkOkSetErr(BOOL Ok, DWORD Err)
Definition: _Internal.h:25
bool AddString(char *Str, bool caseSens=true)
Definition: StrFunc.cpp:1803
bool __forceinline bool_cast(BOOL B52)
Definition: Common.h:767
#define DP_ERROR
Definition: Debug.h:82
UINT MultiSzCountW(WCSTR MultiSz)
Definition: StrFunc.cpp:451
#define CR
Definition: Common.h:1230
INT_PTR CharIndexA(const char *Buffer, const char *Inside)
Definition: StrFunc.cpp:18
UINT AppendString(TSTR String, UINT ccBuf, TCHAR Sep, CSTR Epilog)
Definition: StrFunc.cpp:924
wchar_t *__fastcall wcsnecpy(register wchar_t *Dst, register const wchar_t *Src, size_t n)
Definition: StrFunc.cpp:84
#define UNUSED(x)
Definition: Common.h:970
WSTR mem_DupWStr(WCSTR Src)
Definition: StrFunc.cpp:250
bool Grow()
Definition: StrFunc.cpp:1786
CSTR DupResourceStrEx(HMODULE hModule, UINT Id, LANGID Lang, PWORD pCount)
Definition: StrFunc.cpp:360
Debug and error handling support.
UINT Dim
Definition: StrFunc.h:826
WordList(UINT InitListDim=128, UINT InitStgSize=4096, UINT ListGrowBy=128, UINT StgGrowBy=4096)
Definition: StrFunc.cpp:1758
#define COLON
Definition: Common.h:1222
INT_PTR CharIndex(const chrType *Buffer, const chrType *Inside)
Definition: StrFunc.h:93
void Free()
Definition: StrFunc.cpp:1582
TSTR FreeMultiSz(TSTR pzMulti)
Definition: StrFunc.cpp:538
INT_PTR CharIndexW(const wchar_t *Buffer, const wchar_t *Inside)
Definition: StrFunc.cpp:25
#define DEF_(x)
Definition: Common.h:240
wchar_t *__fastcall wcsecpy(register wchar_t *Dst, register const wchar_t *Src)
Definition: StrFunc.cpp:68
#define MultiSzLength
Definition: StrFunc.h:277
char * Search(char *Key, int(__stdcall *Compare)(char *Key, char *Str, void *Ctx), void *Context)
Definition: StrFunc.cpp:1875
CSTR GetCLSIDString(REFIID riid, TSTR pzBuf, UINT ccBuf)
Definition: StrFunc.cpp:1278
#define BSLASH
Definition: Common.h:1217
WCSTR newWStr(WCSTR Src)
Definition: StrFunc.cpp:206
CSTR DataSizeStr(UINT64 Size)
Definition: StrFunc.cpp:1042
unsigned short * PWORD
Definition: Common.h:413
#define _F(s)
Definition: Debug.h:49
void DoneShellFunc()
Definition: ShellUtil.cpp:64
#define WCHAR_SIZE
Definition: Common.h:379
#define DP_INFO
Definition: Debug.h:84
bool GrowStorage()
Definition: StrFunc.cpp:1588
#define LITERAL(type, x)
Definition: Common.h:969
#define NT_SUCCESS(Status)
Definition: Common.h:154
size_t wcsbytes(const wchar_t *Src)
Definition: StrFunc.cpp:154
CSTR deleteStr(CSTR Dup)
Definition: StrFunc.cpp:191
WCSTR deleteWStr(WCSTR Dup)
Definition: StrFunc.cpp:219
CSTR FileTypeStr(CSTR FName)
Definition: StrFunc.cpp:1151
PSTRING _InitString(PSTRING pStr, LPCSTR pzSrc)
Definition: StrFunc.cpp:1352
virtual ~UString()
Definition: StrFunc.cpp:1438
WCSTR GetResourceStr(HMODULE hModule, UINT Id, PWORD pCount)
Definition: StrFunc.cpp:324
#define END_STRSAFE_OVERRIDE
Definition: StrFunc.h:29
CSTR HexString(PBYTE data, UINT len, TSTR buf, UINT size, bool dots)
Definition: StrFunc.cpp:981
bool GetRootOf(IN CSTR PathName, OUT TSTR Root, UINT ccRoot)
Definition: StrFunc.cpp:661
CSTR SysTimeStr(SYSTEMTIME *Time, CSTR Fmt)
Definition: StrFunc.cpp:1131
#define DP_WARNING
Definition: Debug.h:83
#define LF
Definition: Common.h:1231
unsigned char BYTE
Definition: Common.h:412
UINT PrependString(TSTR String, UINT ccBuf, TCHAR Sep, CSTR Prolog)
Definition: StrFunc.cpp:904
bool __forceinline IsString(CSTR Str)
Definition: StrFunc.h:84
char *__fastcall strncpyz(register char *Dst, register const char *Src, size_t Count)
Definition: StrFunc.cpp:134
char *__fastcall strecpy(register char *Dst, register const char *Src)
Definition: StrFunc.cpp:37
ASTR mem_DupAStr(ACSTR Src)
Definition: StrFunc.cpp:237
bool(__stdcall * PFnEnumMultiStringA)(ASTR Str, PVOID Context)
Definition: StrFunc.h:286
END_STRSAFE_OVERRIDE CSTR FileAttribStr(DWORD Attr)
Definition: StrFunc.cpp:1092
#define _tcsncpyz
Definition: StrFunc.h:77
wchar_t * wcsistr(const wchar_t *str, const wchar_t *pattern)
Definition: StrFunc.cpp:113