Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

981 lines
22 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. utility.c
  5. Abstract:
  6. This file contains utility functions that are
  7. used by all other files in this project.
  8. Author:
  9. Wesley Witt [wesw] 1-March-2000
  10. Revision History:
  11. --*/
  12. #include <precomp.h>
  13. INT
  14. Help(
  15. IN INT argc,
  16. IN PWSTR argv[]
  17. )
  18. /*++
  19. Routine Description:
  20. This routine lists out the various command supported by the
  21. tool.
  22. Arguments:
  23. None
  24. Return Value:
  25. None
  26. --*/
  27. {
  28. DisplayMsg( MSG_USAGE );
  29. return EXIT_CODE_SUCCESS;
  30. }
  31. HANDLE NtDllHandle = INVALID_HANDLE_VALUE;
  32. VOID
  33. DisplayErrorMsg(
  34. LONG msgId,
  35. ...
  36. )
  37. /*++
  38. Routine Description:
  39. This routine displays the error message correspnding to
  40. the error indicated by msgId.
  41. Arguments:
  42. msgId - the errorId. This is either the Win32 status code or the message ID.
  43. Return Value:
  44. None
  45. --*/
  46. {
  47. va_list args;
  48. LPWSTR lpMsgBuf;
  49. va_start( args, msgId );
  50. if (FormatMessage(
  51. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  52. NULL,
  53. MSG_ERROR,
  54. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  55. (LPWSTR) &lpMsgBuf,
  56. 0,
  57. NULL
  58. ))
  59. {
  60. wprintf( L"%ws", lpMsgBuf );
  61. LocalFree( lpMsgBuf );
  62. }
  63. if (FormatMessage(
  64. (msgId >= MSG_FIRST_MESSAGE_ID ? FORMAT_MESSAGE_FROM_HMODULE :
  65. FORMAT_MESSAGE_FROM_SYSTEM)
  66. | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  67. NULL,
  68. msgId,
  69. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  70. (LPWSTR) &lpMsgBuf,
  71. 0,
  72. &args
  73. ))
  74. {
  75. wprintf( L" %ws \n", (LPSTR)lpMsgBuf );
  76. LocalFree( lpMsgBuf );
  77. } else {
  78. if (NtDllHandle == INVALID_HANDLE_VALUE) {
  79. NtDllHandle = GetModuleHandle( L"NTDLL" );
  80. }
  81. if (FormatMessage(
  82. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  83. (LPVOID)NtDllHandle,
  84. msgId,
  85. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  86. (LPWSTR) &lpMsgBuf,
  87. 0,
  88. &args))
  89. {
  90. wprintf( L" %ws \n", (LPSTR)lpMsgBuf );
  91. LocalFree( lpMsgBuf );
  92. } else {
  93. wprintf( L"Unable to format message for id %x - %x\n", msgId, GetLastError( ));
  94. }
  95. }
  96. va_end( args );
  97. }
  98. VOID
  99. DisplayMsg(
  100. LONG msgId,
  101. ...
  102. )
  103. /*++
  104. Routine Description:
  105. This routine displays the error message correspnding to
  106. the error indicated by msgId.
  107. Arguments:
  108. msgId - the errorId. This is either the Win32 status or the
  109. message Id
  110. Return Value:
  111. None
  112. --*/
  113. {
  114. va_list args;
  115. LPWSTR lpMsgBuf;
  116. va_start( args, msgId );
  117. if (FormatMessage(
  118. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  119. NULL,
  120. msgId,
  121. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  122. (LPWSTR) &lpMsgBuf,
  123. 0,
  124. &args
  125. ))
  126. {
  127. wprintf( L"%ws", (LPSTR)lpMsgBuf );
  128. LocalFree( lpMsgBuf );
  129. } else {
  130. if (NtDllHandle == INVALID_HANDLE_VALUE) {
  131. NtDllHandle = GetModuleHandle( L"NTDLL" );
  132. }
  133. if (FormatMessage(
  134. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  135. (LPVOID)NtDllHandle,
  136. msgId,
  137. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  138. (LPWSTR) &lpMsgBuf,
  139. 0,
  140. &args))
  141. {
  142. wprintf( L" %ws \n", (LPSTR)lpMsgBuf );
  143. LocalFree( lpMsgBuf );
  144. } else {
  145. wprintf( L"Unable to format message for id %x - %x\n", msgId, GetLastError( ));
  146. }
  147. }
  148. va_end( args );
  149. }
  150. VOID
  151. DisplayError(
  152. void
  153. )
  154. /*++
  155. Routine Description:
  156. This routine displays the last error message.
  157. Arguments:
  158. None
  159. Return Value:
  160. None
  161. --*/
  162. {
  163. DisplayErrorMsg( GetLastError() );
  164. }
  165. BOOL
  166. EnablePrivilege(
  167. LPCWSTR SePrivilege
  168. )
  169. {
  170. HANDLE Token;
  171. PTOKEN_PRIVILEGES NewPrivileges;
  172. BYTE OldPriv[1024];
  173. PBYTE pbOldPriv;
  174. ULONG cbNeeded;
  175. BOOL b = TRUE;
  176. BOOL fRc;
  177. LUID LuidPrivilege;
  178. //
  179. // Make sure we have access to adjust and to get the old
  180. // token privileges
  181. //
  182. if (!OpenProcessToken( GetCurrentProcess(),
  183. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  184. &Token))
  185. {
  186. return( FALSE );
  187. }
  188. cbNeeded = 0;
  189. //
  190. // Initialize the privilege adjustment structure
  191. //
  192. LookupPrivilegeValue(NULL, SePrivilege, &LuidPrivilege );
  193. NewPrivileges = (PTOKEN_PRIVILEGES)
  194. calloc(1,sizeof(TOKEN_PRIVILEGES) +
  195. (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
  196. if (NewPrivileges == NULL)
  197. {
  198. CloseHandle(Token);
  199. return(FALSE);
  200. }
  201. NewPrivileges->PrivilegeCount = 1;
  202. NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  203. NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  204. //
  205. // Enable the privilege
  206. //
  207. pbOldPriv = OldPriv;
  208. fRc = AdjustTokenPrivileges( Token,
  209. FALSE,
  210. NewPrivileges,
  211. 1024,
  212. (PTOKEN_PRIVILEGES)pbOldPriv,
  213. &cbNeeded );
  214. if (!fRc)
  215. {
  216. //
  217. // If the stack was too small to hold the privileges
  218. // then allocate off the heap
  219. //
  220. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  221. {
  222. pbOldPriv = (PBYTE)calloc(1,cbNeeded);
  223. if (pbOldPriv == NULL)
  224. {
  225. CloseHandle(Token);
  226. return(FALSE);
  227. }
  228. fRc = AdjustTokenPrivileges( Token,
  229. FALSE,
  230. NewPrivileges,
  231. cbNeeded,
  232. (PTOKEN_PRIVILEGES)pbOldPriv,
  233. &cbNeeded );
  234. }
  235. }
  236. CloseHandle( Token );
  237. return( b );
  238. }
  239. BOOL
  240. IsUserAdmin(
  241. VOID
  242. )
  243. /*++
  244. Routine Description:
  245. This routine returns TRUE if the caller's process is a
  246. member of the Administrators local group.
  247. Caller is NOT expected to be impersonating anyone and IS
  248. expected to be able to open their own process and process
  249. token.
  250. Arguments:
  251. None.
  252. Return Value:
  253. TRUE - Caller has Administrators local group.
  254. FALSE - Caller does not have Administrators local group.
  255. --*/
  256. {
  257. HANDLE Token;
  258. BOOL b = FALSE;
  259. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  260. PSID AdministratorsGroup = NULL;
  261. ImpersonateSelf( SecurityImpersonation );
  262. //
  263. // Open the process token.
  264. //
  265. if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, FALSE, &Token)) {
  266. try {
  267. //
  268. // Get SID for Administrators group
  269. //
  270. b = AllocateAndInitializeSid(
  271. &NtAuthority,
  272. 2,
  273. SECURITY_BUILTIN_DOMAIN_RID,
  274. DOMAIN_ALIAS_RID_ADMINS,
  275. 0, 0, 0, 0, 0, 0,
  276. &AdministratorsGroup
  277. );
  278. if (!b) {
  279. leave;
  280. }
  281. //
  282. // Check to see if that group is currently enabled. Failure
  283. // means that we aren't administrator
  284. //
  285. if (!CheckTokenMembership( Token, AdministratorsGroup, &b )) {
  286. printf("Failure - %d\n", GetLastError( ));
  287. b = FALSE;
  288. }
  289. } finally {
  290. CloseHandle(Token);
  291. }
  292. }
  293. RevertToSelf( );
  294. return(b);
  295. }
  296. BOOL
  297. IsVolumeLocalNTFS(
  298. WCHAR DriveLetter
  299. )
  300. {
  301. BOOL b;
  302. ULONG i;
  303. WCHAR DosName[16];
  304. WCHAR PhysicalName[MAX_PATH];
  305. DosName[0] = DriveLetter;
  306. DosName[1] = L':';
  307. DosName[2] = L'\\';
  308. DosName[3] = L'\0';
  309. switch (GetDriveType( DosName )) {
  310. case DRIVE_UNKNOWN:
  311. case DRIVE_REMOTE:
  312. return FALSE;
  313. }
  314. b = GetVolumeInformation(
  315. DosName,
  316. NULL,
  317. 0,
  318. NULL,
  319. &i,
  320. &i,
  321. PhysicalName,
  322. sizeof(PhysicalName)/sizeof(WCHAR)
  323. );
  324. if (!b ) {
  325. DisplayError();
  326. return FALSE;
  327. }
  328. if (_wcsicmp( PhysicalName, L"NTFS" ) != 0) {
  329. return FALSE;
  330. }
  331. return TRUE;
  332. }
  333. BOOL
  334. IsVolumeNTFS(
  335. PWCHAR path
  336. )
  337. {
  338. //
  339. // Scan backwards through the path looking for \ and trying at each level until we
  340. // get to the root. We'll terminate it there and pass it to GetVolumeInformation
  341. //
  342. PWCHAR LastBackSlash = path + wcslen( path );
  343. WCHAR c;
  344. BOOL b;
  345. ULONG i;
  346. WCHAR PhysicalName[MAX_PATH];
  347. while (TRUE) {
  348. while (TRUE) {
  349. if (LastBackSlash < path) {
  350. DisplayError();
  351. return FALSE;
  352. }
  353. if (*LastBackSlash == L'\\') {
  354. break;
  355. }
  356. LastBackSlash--;
  357. }
  358. c = LastBackSlash[1];
  359. LastBackSlash[1] = L'\0';
  360. b = GetVolumeInformation(
  361. path,
  362. NULL,
  363. 0,
  364. NULL,
  365. &i,
  366. &i,
  367. PhysicalName,
  368. sizeof(PhysicalName)/sizeof(WCHAR)
  369. );
  370. LastBackSlash[1] = c;
  371. LastBackSlash--;
  372. if ( b ) {
  373. return _wcsicmp( PhysicalName, L"NTFS" ) == 0;
  374. }
  375. }
  376. }
  377. BOOL
  378. IsVolumeLocal(
  379. WCHAR DriveLetter
  380. )
  381. {
  382. BOOL b;
  383. ULONG i;
  384. WCHAR DosName[16];
  385. WCHAR PhysicalName[MAX_PATH];
  386. DosName[0] = DriveLetter;
  387. DosName[1] = L':';
  388. DosName[2] = L'\\';
  389. DosName[3] = L'\0';
  390. switch (GetDriveType( DosName )) {
  391. case DRIVE_UNKNOWN:
  392. case DRIVE_REMOTE:
  393. return FALSE;
  394. }
  395. return TRUE;
  396. }
  397. PWSTR
  398. GetFullPath(
  399. IN PWSTR FilenameIn
  400. )
  401. {
  402. WCHAR Filename[MAX_PATH];
  403. PWSTR FilePart;
  404. if (!GetFullPathName( FilenameIn, sizeof(Filename)/sizeof(WCHAR), Filename, &FilePart )) {
  405. return NULL;
  406. }
  407. return _wcsdup( Filename );
  408. }
  409. //
  410. // I64-width number formatting is broken in FormatMessage. We have to convert the numbers
  411. // ourselves and then display them as strings. Rather than declaring buffers on the stack,
  412. // we will allocate space dynamically, and format the text into that spot.
  413. //
  414. // While *TECHNICALLY* this is a leak, the utility quickly exits.
  415. //
  416. #define NUMERICBUFFERLENGTH 40
  417. PWSTR
  418. QuadToDecimalText(
  419. ULONGLONG Value
  420. )
  421. {
  422. PWSTR Buffer = malloc( sizeof( WCHAR ) * NUMERICBUFFERLENGTH );
  423. if (Buffer == NULL) {
  424. exit( 1);
  425. }
  426. swprintf( Buffer, L"%I64u", Value );
  427. return Buffer;
  428. }
  429. PWSTR
  430. QuadToHexText(
  431. ULONGLONG Value
  432. )
  433. {
  434. PWSTR Buffer = malloc( sizeof( WCHAR ) * NUMERICBUFFERLENGTH );
  435. if (Buffer == NULL) {
  436. exit( 1);
  437. }
  438. swprintf( Buffer, L"%I64x", Value );
  439. return Buffer;
  440. }
  441. PWSTR
  442. QuadToPaddedHexText(
  443. ULONGLONG Value
  444. )
  445. {
  446. PWSTR Buffer = malloc( sizeof( WCHAR ) * NUMERICBUFFERLENGTH );
  447. if (Buffer == NULL) {
  448. exit( 1);
  449. }
  450. swprintf( Buffer, L"%016I64x", Value );
  451. return Buffer;
  452. }
  453. #if TRUE
  454. /***
  455. *wcstoq, wcstouq(nptr,endptr,ibase) - Convert ascii string to un/signed __int64.
  456. *
  457. *Purpose:
  458. * Convert an ascii string to a 64-bit __int64 value. The base
  459. * used for the caculations is supplied by the caller. The base
  460. * must be in the range 0, 2-36. If a base of 0 is supplied, the
  461. * ascii string must be examined to determine the base of the
  462. * number:
  463. * (a) First wchar_t = '0', second wchar_t = 'x' or 'X',
  464. * use base 16.
  465. * (b) First wchar_t = '0', use base 8
  466. * (c) First wchar_t in range '1' - '9', use base 10.
  467. *
  468. * If the 'endptr' value is non-NULL, then wcstoq/wcstouq places
  469. * a pointer to the terminating character in this value.
  470. * See ANSI standard for details
  471. *
  472. *Entry:
  473. * nptr == NEAR/FAR pointer to the start of string.
  474. * endptr == NEAR/FAR pointer to the end of the string.
  475. * ibase == integer base to use for the calculations.
  476. *
  477. * string format: [whitespace] [sign] [0] [x] [digits/letters]
  478. *
  479. *Exit:
  480. * Good return:
  481. * result
  482. *
  483. * Overflow return:
  484. * wcstoq -- _I64_MAX or _I64_MIN
  485. * wcstouq -- _UI64_MAX
  486. * wcstoq/wcstouq -- errno == ERANGE
  487. *
  488. * No digits or bad base return:
  489. * 0
  490. * endptr = nptr*
  491. *
  492. *Exceptions:
  493. * None.
  494. *******************************************************************************/
  495. /* flag values */
  496. #define FL_UNSIGNED 1 /* wcstouq called */
  497. #define FL_NEG 2 /* negative sign found */
  498. #define FL_OVERFLOW 4 /* overflow occured */
  499. #define FL_READDIGIT 8 /* we've read at least one correct digit */
  500. static unsigned __int64 __cdecl wcstoxq (
  501. const wchar_t *nptr,
  502. const wchar_t **endptr,
  503. int ibase,
  504. int flags
  505. )
  506. {
  507. const wchar_t *p;
  508. wchar_t c;
  509. unsigned __int64 number;
  510. unsigned digval;
  511. unsigned __int64 maxval;
  512. p = nptr; /* p is our scanning pointer */
  513. number = 0; /* start with zero */
  514. c = *p++; /* read wchar_t */
  515. while ( iswspace(c) )
  516. c = *p++; /* skip whitespace */
  517. if (c == '-') {
  518. flags |= FL_NEG; /* remember minus sign */
  519. c = *p++;
  520. }
  521. else if (c == '+')
  522. c = *p++; /* skip sign */
  523. if (ibase < 0 || ibase == 1 || ibase > 36) {
  524. /* bad base! */
  525. if (endptr)
  526. /* store beginning of string in endptr */
  527. *endptr = nptr;
  528. return 0L; /* return 0 */
  529. }
  530. else if (ibase == 0) {
  531. /* determine base free-lance, based on first two chars of
  532. string */
  533. if (c != '0')
  534. ibase = 10;
  535. else if (*p == 'x' || *p == 'X')
  536. ibase = 16;
  537. else
  538. ibase = 8;
  539. }
  540. if (ibase == 16) {
  541. /* we might have 0x in front of number; remove if there */
  542. if (c == '0' && (*p == 'x' || *p == 'X')) {
  543. ++p;
  544. c = *p++; /* advance past prefix */
  545. }
  546. }
  547. /* if our number exceeds this, we will overflow on multiply */
  548. maxval = _UI64_MAX / ibase;
  549. for (;;) { /* exit in middle of loop */
  550. /* convert c to value */
  551. if ( isdigit((unsigned)c) )
  552. digval = c - '0';
  553. else if ( isalpha((unsigned)c) )
  554. digval = toupper(c) - 'A' + 10;
  555. else
  556. break;
  557. if (digval >= (unsigned)ibase)
  558. break; /* exit loop if bad digit found */
  559. /* record the fact we have read one digit */
  560. flags |= FL_READDIGIT;
  561. /* we now need to compute number = number * base + digval,
  562. but we need to know if overflow occured. This requires
  563. a tricky pre-check. */
  564. if (number < maxval || (number == maxval &&
  565. (unsigned __int64)digval <= _UI64_MAX % ibase)) {
  566. /* we won't overflow, go ahead and multiply */
  567. number = number * ibase + digval;
  568. }
  569. else {
  570. /* we would have overflowed -- set the overflow flag */
  571. flags |= FL_OVERFLOW;
  572. }
  573. c = *p++; /* read next digit */
  574. }
  575. --p; /* point to place that stopped scan */
  576. if (!(flags & FL_READDIGIT)) {
  577. /* no number there; return 0 and point to beginning of
  578. string */
  579. /* store beginning of string in endptr later on */
  580. p = nptr;
  581. number = 0L; /* return 0 */
  582. }
  583. else if ((flags & FL_OVERFLOW) ||
  584. (!(flags & FL_UNSIGNED) &&
  585. (number & ((unsigned __int64)_I64_MAX+1)))) {
  586. /* overflow occurred or signed overflow occurred */
  587. errno = ERANGE;
  588. if (flags & FL_UNSIGNED)
  589. number = _UI64_MAX;
  590. else
  591. /* set error code, will be negated if necc. */
  592. number = _I64_MAX;
  593. flags &= ~FL_NEG;
  594. }
  595. else if ((flags & FL_UNSIGNED) && (flags & FL_NEG)) {
  596. // Disallow a negative sign if we're reading an unsigned
  597. number = 0L;
  598. p = nptr;
  599. }
  600. if (endptr != NULL)
  601. /* store pointer to wchar_t that stopped the scan */
  602. *endptr = p;
  603. if (flags & FL_NEG)
  604. /* negate result if there was a neg sign */
  605. number = (unsigned __int64)(-(__int64)number);
  606. return number; /* done. */
  607. }
  608. __int64 __cdecl My_wcstoi64(
  609. const wchar_t *nptr,
  610. wchar_t **endptr,
  611. int ibase
  612. )
  613. {
  614. return (__int64) wcstoxq(nptr, endptr, ibase, 0);
  615. }
  616. unsigned __int64 __cdecl My_wcstoui64 (
  617. const wchar_t *nptr,
  618. wchar_t **endptr,
  619. int ibase
  620. )
  621. {
  622. return wcstoxq(nptr, endptr, ibase, FL_UNSIGNED);
  623. }
  624. /***
  625. *wcstol, wcstoul(nptr,endptr,ibase) - Convert ascii string to long un/signed
  626. * int.
  627. *
  628. *Purpose:
  629. * Convert an ascii string to a long 32-bit value. The base
  630. * used for the caculations is supplied by the caller. The base
  631. * must be in the range 0, 2-36. If a base of 0 is supplied, the
  632. * ascii string must be examined to determine the base of the
  633. * number:
  634. * (a) First char = '0', second char = 'x' or 'X',
  635. * use base 16.
  636. * (b) First char = '0', use base 8
  637. * (c) First char in range '1' - '9', use base 10.
  638. *
  639. * If the 'endptr' value is non-NULL, then wcstol/wcstoul places
  640. * a pointer to the terminating character in this value.
  641. * See ANSI standard for details
  642. *
  643. *Entry:
  644. * nptr == NEAR/FAR pointer to the start of string.
  645. * endptr == NEAR/FAR pointer to the end of the string.
  646. * ibase == integer base to use for the calculations.
  647. *
  648. * string format: [whitespace] [sign] [0] [x] [digits/letters]
  649. *
  650. *Exit:
  651. * Good return:
  652. * result
  653. *
  654. * Overflow return:
  655. * wcstol -- LONG_MAX or LONG_MIN
  656. * wcstoul -- ULONG_MAX
  657. * wcstol/wcstoul -- errno == ERANGE
  658. *
  659. * No digits or bad base return:
  660. * 0
  661. * endptr = nptr*
  662. *
  663. *Exceptions:
  664. * None.
  665. *
  666. *******************************************************************************/
  667. /* flag values */
  668. #define FL_UNSIGNED 1 /* wcstoul called */
  669. #define FL_NEG 2 /* negative sign found */
  670. #define FL_OVERFLOW 4 /* overflow occured */
  671. #define FL_READDIGIT 8 /* we've read at least one correct digit */
  672. static unsigned long __cdecl wcstoxl (
  673. const wchar_t *nptr,
  674. const wchar_t **endptr,
  675. int ibase,
  676. int flags
  677. )
  678. {
  679. const wchar_t *p;
  680. wchar_t c;
  681. unsigned long number;
  682. unsigned digval;
  683. unsigned long maxval;
  684. p = nptr; /* p is our scanning pointer */
  685. number = 0; /* start with zero */
  686. c = *p++; /* read char */
  687. while ( iswspace(c) )
  688. c = *p++; /* skip whitespace */
  689. if (c == '-') {
  690. flags |= FL_NEG; /* remember minus sign */
  691. c = *p++;
  692. }
  693. else if (c == '+')
  694. c = *p++; /* skip sign */
  695. if (ibase < 0 || ibase == 1 || ibase > 36) {
  696. /* bad base! */
  697. if (endptr)
  698. /* store beginning of string in endptr */
  699. *endptr = nptr;
  700. return 0L; /* return 0 */
  701. }
  702. else if (ibase == 0) {
  703. /* determine base free-lance, based on first two chars of
  704. string */
  705. if (c != L'0')
  706. ibase = 10;
  707. else if (*p == L'x' || *p == L'X')
  708. ibase = 16;
  709. else
  710. ibase = 8;
  711. }
  712. if (ibase == 16) {
  713. /* we might have 0x in front of number; remove if there */
  714. if (c == L'0' && (*p == L'x' || *p == L'X')) {
  715. ++p;
  716. c = *p++; /* advance past prefix */
  717. }
  718. }
  719. /* if our number exceeds this, we will overflow on multiply */
  720. maxval = ULONG_MAX / ibase;
  721. for (;;) { /* exit in middle of loop */
  722. /* make sure c is not too big */
  723. if ( (unsigned)c > UCHAR_MAX )
  724. break;
  725. /* convert c to value */
  726. if ( iswdigit(c) )
  727. digval = c - L'0';
  728. else if ( iswalpha(c))
  729. digval = towupper(c) - L'A' + 10;
  730. else
  731. break;
  732. if (digval >= (unsigned)ibase)
  733. break; /* exit loop if bad digit found */
  734. /* record the fact we have read one digit */
  735. flags |= FL_READDIGIT;
  736. /* we now need to compute number = number * base + digval,
  737. but we need to know if overflow occured. This requires
  738. a tricky pre-check. */
  739. if (number < maxval || (number == maxval &&
  740. (unsigned long)digval <= ULONG_MAX % ibase)) {
  741. /* we won't overflow, go ahead and multiply */
  742. number = number * ibase + digval;
  743. }
  744. else {
  745. /* we would have overflowed -- set the overflow flag */
  746. flags |= FL_OVERFLOW;
  747. }
  748. c = *p++; /* read next digit */
  749. }
  750. --p; /* point to place that stopped scan */
  751. if (!(flags & FL_READDIGIT)) {
  752. /* no number there; return 0 and point to beginning of
  753. string */
  754. if (endptr)
  755. /* store beginning of string in endptr later on */
  756. p = nptr;
  757. number = 0L; /* return 0 */
  758. }
  759. else if ( (flags & FL_OVERFLOW) ||
  760. ( !(flags & FL_UNSIGNED) &&
  761. ( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||
  762. ( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) )
  763. {
  764. /* overflow or signed overflow occurred */
  765. errno = ERANGE;
  766. if ( flags & FL_UNSIGNED )
  767. number = ULONG_MAX;
  768. else
  769. number = LONG_MAX;
  770. flags &= ~FL_NEG;
  771. }
  772. else if ((flags & FL_UNSIGNED) && (flags & FL_NEG)) {
  773. // Disallow a negative sign if we're reading an unsigned
  774. number = 0L;
  775. p = nptr;
  776. }
  777. if (endptr != NULL)
  778. /* store pointer to char that stopped the scan */
  779. *endptr = p;
  780. if (flags & FL_NEG)
  781. /* negate result if there was a neg sign */
  782. number = (unsigned long)(-(long)number);
  783. return number; /* done. */
  784. }
  785. long __cdecl My_wcstol (
  786. const wchar_t *nptr,
  787. wchar_t **endptr,
  788. int ibase
  789. )
  790. {
  791. return (long) wcstoxl(nptr, endptr, ibase, 0);
  792. }
  793. unsigned long __cdecl My_wcstoul (
  794. const wchar_t *nptr,
  795. wchar_t **endptr,
  796. int ibase
  797. )
  798. {
  799. return wcstoxl(nptr, endptr, ibase, FL_UNSIGNED);
  800. }
  801. #else
  802. #define My_wcstoui64 _wcstoui64
  803. #define My_wcstoul _wcstoul
  804. #endif