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.

11964 lines
285 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. strings.c
  5. Abstract:
  6. A number of string utilities useful for any project
  7. Author:
  8. Jim Schmidt (jimschm) 12-Sept-1996
  9. Revisions:
  10. ovidiut 12-Jan-2000 Added GetNodePatternMinMaxLevels,PatternIncludesPattern
  11. ovidiut 14-Sep-1999 Updated for new coding conventions and Win64 compliance
  12. marcw 2-Sep-1999 Moved over from Win9xUpg project.
  13. jimschm 08-Jul-1999 IsPatternMatchEx
  14. jimschm 07-Jan-1999 GetFileExtensionFromPath fixed again, added
  15. GetDotExtensionFromPath
  16. calinn 23-Sep-1998 GetFileExtensionFromPath bug fix
  17. calinn 29-Jan-1998 Fixed a bug in EnumNextMultiSz.
  18. calinn 11-Jan-1998 Added EnumFirstMultiSz and EnumNextMultiSz functions.
  19. marcw 15-Dec-1997 Added ExpandEnvironmentTextEx functions.
  20. marcw 14-Nov-1997 SlightJoinText revisions.
  21. jimschm 21-May-1997 AppendWack revisions
  22. marcw 24-Mar-1997 StringReplace functions.
  23. jimschm 14-Mar-1997 New critical section stuff, enhanced message resource
  24. routines, C runtime extensions, registry root utils
  25. jimschm 26-Nov-1996 Added message resource tools.
  26. mikeco 01-Jul-1997 Add FreeStringResourcePtr Fns
  27. mikeco 29-Sep-1997 IsLeadByte wrapper for IsDBCSLeadByte
  28. --*/
  29. #include "pch.h"
  30. //
  31. // Includes
  32. //
  33. #include "utilsp.h"
  34. #define DBG_STRINGS "Strings"
  35. //
  36. // Strings
  37. //
  38. // None
  39. //
  40. // Constants
  41. //
  42. // Error stack size (normally only one or two, so 32 is relatively huge)
  43. #define MAX_STACK 32
  44. #define WACK_REPLACE_CHAR 0x02
  45. #define DWORD_MAX 0xFFFFFFFFu
  46. //
  47. // Macros
  48. //
  49. // None
  50. //
  51. // Types
  52. //
  53. typedef enum {
  54. BEGIN_PATTERN,
  55. BEGIN_COMPOUND_PATTERN,
  56. BEGIN_PATTERN_EXPR,
  57. SAVE_EXACT_MATCH,
  58. SAVE_SEGMENT,
  59. LOOK_FOR_NUMBER,
  60. LOOK_FOR_INCLUDE,
  61. LOOK_FOR_EXCLUDE,
  62. ADVANCE_TO_END_OF_EXPR,
  63. PARSE_CHAR_EXPR_OR_END,
  64. SKIP_EXCLUDE_SET,
  65. CONDENSE_SET,
  66. PARSE_END_FOUND,
  67. SKIP_INCLUDE_SET,
  68. END_PATTERN_EXPR,
  69. PATTERN_DONE,
  70. PATTERN_ERROR
  71. } PATTERNSTATE;
  72. typedef struct {
  73. UINT char1;
  74. UINT char2;
  75. UINT result;
  76. } DHLIST, *PDHLIST;
  77. //
  78. // Globals
  79. //
  80. BOOL g_LeadByteArray[256];
  81. CHAR EscapedCharsA[] = "?*\020<>,^";
  82. WCHAR EscapedCharsW[] = L"?*\020<>,^";
  83. DWORD g_dwErrorStack[MAX_STACK];
  84. DWORD g_dwStackPos = 0;
  85. DHLIST g_DHList[] = {{0xB3, 0xDE, 0x8394},
  86. {0xB6, 0xDE, 0x834B},
  87. {0xB7, 0xDE, 0x834D},
  88. {0xB8, 0xDE, 0x834F},
  89. {0xB9, 0xDE, 0x8351},
  90. {0xBA, 0xDE, 0x8353},
  91. {0xBB, 0xDE, 0x8355},
  92. {0xBC, 0xDE, 0x8357},
  93. {0xBD, 0xDE, 0x8359},
  94. {0xBE, 0xDE, 0x835B},
  95. {0xBF, 0xDE, 0x835D},
  96. {0xC0, 0xDE, 0x835F},
  97. {0xC1, 0xDE, 0x8361},
  98. {0xC2, 0xDE, 0x8364},
  99. {0xC3, 0xDE, 0x8366},
  100. {0xC4, 0xDE, 0x8368},
  101. {0xCA, 0xDE, 0x836F},
  102. {0xCB, 0xDE, 0x8372},
  103. {0xCC, 0xDE, 0x8375},
  104. {0xCD, 0xDE, 0x8378},
  105. {0xCE, 0xDE, 0x837B},
  106. {0xCA, 0xDF, 0x8370},
  107. {0xCB, 0xDF, 0x8373},
  108. {0xCC, 0xDF, 0x8376},
  109. {0xCD, 0xDF, 0x8379},
  110. {0xCE, 0xDF, 0x837C},
  111. {0x00, 0x00, 0x0000}};
  112. extern OUR_CRITICAL_SECTION g_MessageCs; // in main.c
  113. extern PMHANDLE g_TextPool; // in main.c
  114. PGROWBUFFER g_LastAllocTable;
  115. //
  116. // Macro expansion list
  117. //
  118. // None
  119. //
  120. // Private function prototypes
  121. //
  122. BOOL
  123. pTestSetA (
  124. IN MBCHAR ch,
  125. IN PCSTR IncludeSet, OPTIONAL
  126. IN PCSTR ExcludeSet OPTIONAL
  127. );
  128. BOOL
  129. pTestSetW (
  130. IN WCHAR ch,
  131. IN PCWSTR IncludeSet, OPTIONAL
  132. IN PCWSTR ExcludeSet OPTIONAL
  133. );
  134. //
  135. // Macro expansion definition
  136. //
  137. // None
  138. //
  139. // Code
  140. //
  141. // This has bugs on JPN systems. We need to terminate the string and then call CharLowerA
  142. // #define OURTOLOWER(l) ((WORD)CharLowerA((PSTR)((WORD)(l))))
  143. MBCHAR
  144. OURTOLOWER (
  145. MBCHAR ch
  146. )
  147. {
  148. CHAR str [3];
  149. MBCHAR result = 0;
  150. if (((PBYTE)(&ch))[1]) {
  151. str [0] = ((PBYTE)(&ch))[1];
  152. str [1] = ((PBYTE)(&ch))[0];
  153. } else {
  154. str [0] = ((PBYTE)(&ch))[0];
  155. str [1] = 0;
  156. }
  157. CharLowerA (str);
  158. if (str[1]) {
  159. ((PBYTE)(&result))[0] = str [1];
  160. ((PBYTE)(&result))[1] = str [0];
  161. } else {
  162. ((PBYTE)(&result))[0] = str [0];
  163. }
  164. return result;
  165. }
  166. VOID
  167. InitLeadByteTable (
  168. VOID
  169. )
  170. {
  171. INT i;
  172. g_LeadByteArray[0] = FALSE;
  173. for (i = 1 ; i < 256 ; i++) {
  174. g_LeadByteArray[i] = IsDBCSLeadByte ((BYTE) i);
  175. }
  176. }
  177. /*++
  178. Routine Description:
  179. StringCopy implements lstrcpyA and a UNICODE version. We don't use the Win32
  180. api because of speed and because we want to compile lint-free.
  181. Arguments:
  182. Destination - Receivies the string copy
  183. Source - Specifies the string to copy
  184. Return Value:
  185. The pointer to the Destionation's nul terminator.
  186. --*/
  187. PSTR
  188. StringCopyA (
  189. OUT PSTR Destination,
  190. IN PCSTR Source
  191. )
  192. {
  193. PCSTR current = Source;
  194. PCSTR end;
  195. while (*current) {
  196. *Destination++ = *current++;
  197. }
  198. //
  199. // Make sure DBCS string is properly terminated
  200. //
  201. end = current;
  202. current--;
  203. while (current >= Source) {
  204. if (!IsLeadByte (current)) {
  205. //
  206. // destEnd is correct
  207. //
  208. break;
  209. }
  210. current--;
  211. }
  212. if (!((end - current) & 1)) {
  213. Destination--;
  214. }
  215. *Destination = 0;
  216. return Destination;
  217. }
  218. PWSTR
  219. StringCopyW (
  220. OUT PWSTR Destination,
  221. IN PCWSTR Source
  222. )
  223. {
  224. while (*Source) {
  225. *Destination++ = *Source++;
  226. }
  227. *Destination = 0;
  228. return Destination;
  229. }
  230. /*++
  231. Routine Description:
  232. StringCopyByteCount implements lstrcpynA and a UNICODE version. We don't
  233. use the Win32 api because of speed and because we want to compile lint-free.
  234. Arguments:
  235. Destination - Receivies the string copy
  236. Source - Specifies the string to copy
  237. Count - Specifies the maximum number of bytes to copy, including the
  238. nul terminator. If Count is zero, then not even a nul
  239. terminator is written.
  240. Return Value:
  241. None.
  242. --*/
  243. PSTR
  244. StringCopyByteCountA (
  245. OUT PSTR Destination,
  246. IN PCSTR Source,
  247. IN UINT Count
  248. )
  249. {
  250. PCSTR end;
  251. PCSTR current;
  252. PSTR destEnd;
  253. destEnd = Destination;
  254. if (Count >= sizeof (CHAR)) {
  255. current = Source;
  256. end = (PCSTR) ((PBYTE) Source + Count - sizeof (CHAR));
  257. while (*current && current < end) {
  258. *destEnd++ = *current++;
  259. }
  260. //
  261. // If current has data left, we need to make sure a DBCS string
  262. // is properly terminated.
  263. //
  264. if (*current) {
  265. end = current;
  266. current--;
  267. while (current >= Source) {
  268. if (!IsLeadByte (current)) {
  269. //
  270. // destEnd is correct
  271. //
  272. break;
  273. }
  274. current--;
  275. }
  276. if (!((end - current) & 1)) {
  277. destEnd--;
  278. }
  279. }
  280. *destEnd = 0;
  281. }
  282. return destEnd;
  283. }
  284. PWSTR
  285. StringCopyByteCountW (
  286. OUT PWSTR Destination,
  287. IN PCWSTR Source,
  288. IN UINT Count
  289. )
  290. {
  291. PCWSTR end;
  292. if (Count < sizeof (WCHAR)) {
  293. DEBUGMSG_IF ((
  294. Count != 0,
  295. DBG_WHOOPS,
  296. "Buffer passed to StringCopyByteCountW is a fraction of one character"
  297. ));
  298. return Destination;
  299. }
  300. end = (PCWSTR) ((PBYTE) Source + Count - sizeof (WCHAR));
  301. while ((Source < end) && (*Source)){
  302. *Destination++ = *Source++;
  303. }
  304. *Destination = 0;
  305. return Destination;
  306. }
  307. PSTR
  308. StringCopyByteCountABA (
  309. OUT PSTR Destination,
  310. IN PCSTR Start,
  311. IN PCSTR End,
  312. IN UINT MaxBytesToCopyIncNul
  313. )
  314. /*++
  315. Routine Description:
  316. StringCopyByteCountAB copies a string segment into a destination buffer,
  317. and limits the copy to a maximum buffer size. The return string is always
  318. nul-terminated, unless the buffer is too small to even hold a nul character.
  319. Arguments:
  320. Destination - Receives the string starting at Start and ending one
  321. character before End.
  322. Start - Specifies the start of the string.
  323. End - Specifies the first character not to copy. If End
  324. is equal or less than Start, then Destination is set
  325. to an empty string (assuming the buffer can hold at
  326. least one character)
  327. MaxBytesToCopyIncNul - Specifies the size of Destination, in bytes, and
  328. including the nul terminator.
  329. Return Value:
  330. A pointer to the destination nul terminator.
  331. --*/
  332. {
  333. INT width;
  334. #ifdef DEBUG
  335. PCSTR check;
  336. check = Start;
  337. while (check < End) {
  338. if (!(*check)) {
  339. DEBUGMSG ((DBG_WHOOPS, "StringCopyByteCountABA: Nul found between start and end"));
  340. break;
  341. }
  342. check++;
  343. }
  344. #endif
  345. width = (INT) ((End - Start + 1) * sizeof (CHAR));
  346. if (width > sizeof (CHAR)) {
  347. return StringCopyByteCountA (Destination, Start, min ((UINT) width, MaxBytesToCopyIncNul));
  348. } else if (MaxBytesToCopyIncNul >= sizeof (CHAR)) {
  349. *Destination = 0;
  350. }
  351. return Destination;
  352. }
  353. PWSTR
  354. StringCopyByteCountABW (
  355. OUT PWSTR Destination,
  356. IN PCWSTR Start,
  357. IN PCWSTR End,
  358. IN UINT MaxBytesToCopyIncNul
  359. )
  360. {
  361. INT width;
  362. #ifdef DEBUG
  363. PCWSTR check;
  364. check = Start;
  365. while (check < End) {
  366. if (!(*check)) {
  367. DEBUGMSG ((DBG_WHOOPS, "StringCopyByteCountABW: Nul found between start and end"));
  368. break;
  369. }
  370. check++;
  371. }
  372. #endif
  373. width = (INT) ((End - Start + 1) * sizeof (WCHAR));
  374. if (width > sizeof (WCHAR)) {
  375. return StringCopyByteCountW (Destination, Start, min ((UINT) width, MaxBytesToCopyIncNul));
  376. } else if (MaxBytesToCopyIncNul >= sizeof (WCHAR)) {
  377. *Destination = 0;
  378. }
  379. return Destination;
  380. }
  381. /*++
  382. Routine Description:
  383. AllocTextEx allocates a block of memory from the specified pool, or g_TextPool
  384. if no pool is specified, and is designated specifically for text processing.
  385. The g_TextPool is initialized when migutil.lib loads up, and there is 64K of
  386. guaranteed workspace, which will grow as necessary.
  387. Arguments:
  388. Pool - Specifies the pool to allocate memory from
  389. CountOfChars - Specifies the number of characters (not bytes) to allocate. The
  390. return pointer is a block of memory that can hold CountOfChars characters,
  391. weather they are SBCS, DBCS or UNICODE.
  392. Return Value:
  393. A pointer to the allocated memory, or NULL if the pool could not be expanded
  394. to hold the number of specified characters.
  395. --*/
  396. PSTR
  397. RealAllocTextExA (
  398. IN PMHANDLE Pool,
  399. IN UINT CountOfChars
  400. )
  401. {
  402. PSTR text;
  403. if (!Pool) {
  404. Pool = g_TextPool;
  405. }
  406. MYASSERT (Pool);
  407. MYASSERT (CountOfChars);
  408. text = PmGetAlignedMemory (Pool, CountOfChars * sizeof (CHAR) * 2);
  409. if (text) {
  410. text [0] = 0;
  411. }
  412. return text;
  413. }
  414. PWSTR
  415. RealAllocTextExW (
  416. IN PMHANDLE Pool,
  417. IN UINT CountOfChars
  418. )
  419. {
  420. PWSTR text;
  421. if (!Pool) {
  422. Pool = g_TextPool;
  423. }
  424. MYASSERT (Pool);
  425. MYASSERT (CountOfChars);
  426. text = PmGetAlignedMemory (Pool, CountOfChars * sizeof (WCHAR));
  427. if (text) {
  428. text [0] = 0;
  429. }
  430. return text;
  431. }
  432. /*++
  433. Routine Description:
  434. FreeText frees the memory allocated by AllocText. After all strings are freed,
  435. the block will be emptied but not deallocated.
  436. It is important NOT to leak memory, because a leak will cause the pool to
  437. expand, and non-empty pools cause memory fragmentation.
  438. Arguments:
  439. Text - Specifies the text to free, as returned from AllocText, DuplicateText,
  440. DuplicateTextEx, etc...
  441. Return Value:
  442. none
  443. --*/
  444. VOID
  445. FreeTextExA (
  446. IN PMHANDLE Pool, OPTIONAL
  447. IN PCSTR Text OPTIONAL
  448. )
  449. {
  450. if (Text) {
  451. if (!Pool) {
  452. Pool = g_TextPool;
  453. }
  454. PmReleaseMemory (Pool, (PVOID) Text);
  455. }
  456. }
  457. VOID
  458. FreeTextExW (
  459. IN PMHANDLE Pool, OPTIONAL
  460. IN PCWSTR Text OPTIONAL
  461. )
  462. {
  463. if (Text) {
  464. if (!Pool) {
  465. Pool = g_TextPool;
  466. }
  467. PmReleaseMemory (Pool, (PVOID) Text);
  468. }
  469. }
  470. /*++
  471. Routine Description:
  472. DuplicateTextEx duplicates a text string and allocates additional space a
  473. caller needs to complete its processing. Optionally, the caller receives
  474. a pointer to the nul of the duplicated string (to allow more efficient
  475. appends).
  476. Arguments:
  477. Text - Specifies the text to duplicate
  478. ExtraChars - Specifies the number of characters (not bytes) to allocate
  479. space for. The characters can be from the SBCS, DBCS or
  480. UNICODE character sets.
  481. NulChar - Receives a pointer to the nul at the end of the duplicated
  482. string. Use for fast appends.
  483. Return Value:
  484. A pointer to the duplicated and expanded string, or NULL if g_TextPool
  485. could not be expanded to fit the duplicated string and extra characters.
  486. --*/
  487. PSTR
  488. RealDuplicateTextExA (
  489. IN PMHANDLE Pool, OPTIONAL
  490. IN PCSTR Text,
  491. IN UINT ExtraChars,
  492. OUT PSTR *NulChar OPTIONAL
  493. )
  494. {
  495. PSTR buf;
  496. PSTR d;
  497. PCSTR s;
  498. buf = AllocTextExA (Pool, CharCountA (Text) + ExtraChars + 1);
  499. if (buf) {
  500. s = Text;
  501. d = buf;
  502. while (*s) {
  503. if (IsLeadByte (s)) {
  504. *d++ = *s++;
  505. }
  506. *d++ = *s++;
  507. }
  508. *d = 0;
  509. if (NulChar) {
  510. *NulChar = d;
  511. }
  512. }
  513. return buf;
  514. }
  515. PWSTR
  516. RealDuplicateTextExW (
  517. IN PMHANDLE Pool, OPTIONAL
  518. IN PCWSTR Text,
  519. IN UINT ExtraChars,
  520. OUT PWSTR *NulChar OPTIONAL
  521. )
  522. {
  523. PWSTR buf;
  524. PWSTR d;
  525. PCWSTR s;
  526. buf = AllocTextExW (Pool, CharCountW (Text) + ExtraChars + 1);
  527. if (buf) {
  528. s = Text;
  529. d = buf;
  530. while (*s) {
  531. *d++ = *s++;
  532. }
  533. *d = 0;
  534. if (NulChar) {
  535. *NulChar = d;
  536. }
  537. }
  538. return buf;
  539. }
  540. /*++
  541. Routine Description:
  542. JoinText duplicates String1 and appends String2 to it delimited with the optional delimiterstring.
  543. Arguments:
  544. String1 - Specifies the text to duplciate
  545. String2 - Specifies the text to append to String1
  546. DelimiterString - Optionally specifies the string to place between string 1 and string 2.
  547. ExtraChars - Specifies the number of characters (not bytes) to allocate
  548. space for. The characters can be from the SBCS, DBCS or
  549. UNICODE character sets.
  550. NulChar - Receives a pointer to the nul at the end of the duplicated
  551. string. Use for fast appends.
  552. Return Value:
  553. A pointer to the duplicated string and extra characters.
  554. --*/
  555. PSTR
  556. RealJoinTextExA (
  557. IN PMHANDLE Pool, OPTIONAL
  558. IN PCSTR String1,
  559. IN PCSTR String2,
  560. IN PCSTR CenterString, OPTIONAL
  561. IN UINT ExtraChars,
  562. OUT PSTR *NulChar OPTIONAL
  563. )
  564. {
  565. PSTR buf;
  566. PSTR end;
  567. PSTR d;
  568. PCSTR s;
  569. buf = DuplicateTextExA (
  570. Pool,
  571. String1,
  572. CharCountA (String2) + ExtraChars + (CenterString ? CharCountA (CenterString) : 0),
  573. &end
  574. );
  575. MYASSERT (buf);
  576. d = end;
  577. if (CenterString) {
  578. s = CenterString;
  579. while (*s) {
  580. if (IsLeadByte (s)) {
  581. *d++ = *s++;
  582. }
  583. *d++ = *s++;
  584. }
  585. }
  586. s = String2;
  587. while (*s) {
  588. if (IsLeadByte (s)) {
  589. *d++ = *s++;
  590. }
  591. *d++ = *s++;
  592. }
  593. *d = 0;
  594. if (NulChar) {
  595. *NulChar = d;
  596. }
  597. return buf;
  598. }
  599. PWSTR
  600. RealJoinTextExW (
  601. IN PMHANDLE Pool, OPTIONAL
  602. IN PCWSTR String1,
  603. IN PCWSTR String2,
  604. IN PCWSTR CenterString, OPTIONAL
  605. IN UINT ExtraChars,
  606. OUT PWSTR *NulChar OPTIONAL
  607. )
  608. {
  609. PWSTR buf;
  610. PWSTR end;
  611. PCWSTR s;
  612. PWSTR d;
  613. buf = DuplicateTextExW (
  614. Pool,
  615. String1,
  616. CharCountW (String2) + ExtraChars + (CenterString ? CharCountW(CenterString) : 0),
  617. &end
  618. );
  619. MYASSERT (buf);
  620. d = end;
  621. if (CenterString) {
  622. s = CenterString;
  623. while (*s) {
  624. *d++ = *s++;
  625. }
  626. }
  627. s = String2;
  628. while (*s) {
  629. *d++ = *s++;
  630. }
  631. *d = 0;
  632. if (NulChar) {
  633. *NulChar = d;
  634. }
  635. return buf;
  636. }
  637. /*++
  638. Routine Description:
  639. ExpandEnvironmentTextEx takes a block of text containing zero or more environment variables
  640. (encoded in %'s) and returns the text with the environment variables expanded. The function
  641. also allows the caller to specify additional environment variables in an array and will use
  642. these variables before calling GetEnvironmentVariable.
  643. The returned text is allocated out of the Text pool and should be freed using FreeText().
  644. Arguments:
  645. InString - The string containing environement variables to be processed.
  646. ExtraVars - Optional var pointing to an array of environment variables to be used to supersede
  647. or suppliment the system environment variables. Even entries in the list are the
  648. names of environment variables, odd entries there values.
  649. (e.g. {"name1","value1","name2","value2",...}
  650. Return Value:
  651. An expanded string.
  652. --*/
  653. PWSTR
  654. RealExpandEnvironmentTextExW (
  655. IN PCWSTR InString,
  656. IN PCWSTR * ExtraVars OPTIONAL
  657. )
  658. {
  659. PWSTR rString = NULL;
  660. PWSTR newString = NULL;
  661. PWSTR envName = NULL;
  662. PWSTR envValue = NULL;
  663. BOOL inSubstitution = FALSE;
  664. BOOL ignoreNextPercent = FALSE;
  665. BOOL errorOccurred = FALSE;
  666. BOOL foundValue = FALSE;
  667. BOOL freeValue = FALSE;
  668. PCWSTR nextPercent = NULL;
  669. PCWSTR source = NULL;
  670. PCWSTR savedSource = NULL;
  671. UINT maxSize = 0;
  672. UINT curSize = 0;
  673. UINT index = 0;
  674. UINT size = 0;
  675. if (!InString) {
  676. return NULL;
  677. }
  678. if (*InString == 0) {
  679. return DuplicateTextW (InString);
  680. }
  681. //
  682. // Set source to the start of InString to begin with...
  683. //
  684. source = InString;
  685. __try {
  686. while (*source) {
  687. //
  688. // Reallocate the string if necessary. We assume that most strings
  689. // are smaller than 1024 chars and that we will therefore only rarely
  690. // reallocate a string.
  691. //
  692. if (curSize + 3 > maxSize) {
  693. maxSize += 1024;
  694. newString = AllocTextW (maxSize);
  695. if (!newString) {
  696. DEBUGMSG((DBG_ERROR,"ExpandEnvironmentTextEx: Memory Error!"));
  697. errorOccurred = TRUE;
  698. __leave;
  699. }
  700. if (rString) {
  701. //lint -e(671)
  702. CopyMemory (newString, rString, (SIZE_T) ((UINT)curSize * sizeof(WCHAR)));
  703. FreeTextW(rString);
  704. }
  705. rString = newString;
  706. }
  707. //
  708. // if we find a percent sign, and we are not currently expanding
  709. // an environment variable (or copying an empty set of %'s),
  710. // then we have probably found an environment variable. Attempt
  711. // to expand it.
  712. //
  713. if (*source == L'%' && !inSubstitution) {
  714. if (ignoreNextPercent) {
  715. ignoreNextPercent = FALSE;
  716. }
  717. else {
  718. ignoreNextPercent = FALSE;
  719. nextPercent = wcschr(source + 1,L'%');
  720. if (nextPercent == source + 1) {
  721. //
  722. // We found two consecutive %s in this string. We'll ignore them and simply copy them as
  723. // normal text.
  724. //
  725. ignoreNextPercent = TRUE;
  726. DEBUGMSGW((DBG_WARNING,"ExpandEnvironmentTextEx: Empty Environment variable in %s. Ignoring.",InString));
  727. }
  728. else if (nextPercent) {
  729. //
  730. // Create a variable to hold the envName.
  731. //
  732. envName = AllocTextW(nextPercent - source);
  733. if (!envName) {
  734. errorOccurred = TRUE;
  735. __leave;
  736. }
  737. StringCopyByteCountABW (
  738. envName,
  739. source + 1,
  740. nextPercent,
  741. (UINT) ((UBINT)nextPercent - (UBINT)source)
  742. );
  743. //
  744. // Try to find the variable.
  745. //
  746. foundValue = FALSE;
  747. freeValue = FALSE;
  748. if (ExtraVars) {
  749. //
  750. // Search through the list of extra vars passed in by the caller.
  751. // Even entries of this list are env var names. Odd entries are env values.
  752. // {envname1,envvalue1,envname2,envvalue2,...}
  753. //
  754. index = 0;
  755. while (ExtraVars[index]) {
  756. if (StringIMatchW(ExtraVars[index],envName) && ExtraVars[index + 1]) {
  757. foundValue = TRUE;
  758. envValue = (PWSTR) ExtraVars[index + 1];
  759. break;
  760. }
  761. index +=2;
  762. }
  763. }
  764. if (!foundValue) {
  765. //
  766. // Still haven't found the environment variable. Use GetEnvironmentString.
  767. //
  768. //
  769. size = GetEnvironmentVariableW(envName,NULL,0);
  770. if (!size) {
  771. errorOccurred = TRUE;
  772. DEBUGMSGW((DBG_WARNING,"ExpandEnvironmentTextEx: Environment variable %s not found!",envName));
  773. } else {
  774. //
  775. // Create a buffer large enough to hold this value and copy it in.
  776. //
  777. envValue = AllocTextW(size);
  778. if ((size - 1) != GetEnvironmentVariableW(envName,envValue,size)) {
  779. errorOccurred = TRUE;
  780. DEBUGMSGW((DBG_ERROR,"ExpandEnvironmentTextEx: Error from GetEnvironmentVariable."));
  781. }
  782. else {
  783. foundValue = TRUE;
  784. }
  785. freeValue = TRUE;
  786. }
  787. }
  788. if (foundValue) {
  789. //
  790. // Ok, we have a valid environment value. Need to copy this data over.
  791. // To do this, we update and save the current source into old source, set source = to the envValue,
  792. // and set the inSubstitution value so that we don't attempt to expand any percents within
  793. // the value.
  794. //
  795. savedSource = nextPercent + 1;
  796. source = envValue;
  797. inSubstitution = TRUE;
  798. }
  799. else {
  800. DEBUGMSGW ((DBG_WARNING, "ExpandEnvironmentTextEx: No Environment variable found for %s.", envName));
  801. ignoreNextPercent = TRUE;
  802. }
  803. //
  804. // We are done with the environment name at this time, so clean it up.
  805. //
  806. FreeTextW(envName);
  807. envName = NULL;
  808. }
  809. ELSE_DEBUGMSGW((DBG_WARNING,"ExpandEnvironmentTextEx: No matching percent found in %s. Ignoring.",InString));
  810. }
  811. }
  812. //
  813. // Copy over the current character.
  814. //
  815. rString[curSize++] = *source++; //lint !e613
  816. if (!*source) {
  817. if (inSubstitution) {
  818. //
  819. // The source for the environment variable is fully copied.
  820. // restore the old source.
  821. //
  822. inSubstitution = FALSE;
  823. source = savedSource;
  824. if (!*source) { //lint !e613
  825. rString[curSize] = 0; //lint !e613
  826. }
  827. if (freeValue) {
  828. FreeTextW(envValue);
  829. freeValue = FALSE;
  830. }
  831. envValue = NULL;
  832. }
  833. else {
  834. rString[curSize] = 0; //lint !e613
  835. }
  836. }
  837. }
  838. } //lint !e613
  839. __finally {
  840. DEBUGMSGW_IF (( errorOccurred, DBG_WARNING, "ExpandEnvironmentText: Some errors occurred while processing %s = %s.", InString, rString ? rString : L"NULL"));
  841. if (envName) {
  842. FreeTextW(envName);
  843. }
  844. if (envValue && freeValue) {
  845. FreeTextW(envValue);
  846. }
  847. }
  848. return rString;
  849. }
  850. PSTR
  851. RealExpandEnvironmentTextExA (
  852. IN PCSTR InString,
  853. IN PCSTR * ExtraVars OPTIONAL
  854. )
  855. {
  856. PSTR rString = NULL;
  857. PSTR newString = NULL;
  858. PSTR envName = NULL;
  859. PSTR envValue = NULL;
  860. BOOL inSubstitution = FALSE;
  861. BOOL ignoreNextPercent = FALSE;
  862. BOOL errorOccurred = FALSE;
  863. BOOL foundValue = FALSE;
  864. BOOL freeValue = FALSE;
  865. PCSTR nextPercent = NULL;
  866. PCSTR source = NULL;
  867. PCSTR savedSource = NULL;
  868. UINT maxSize = 0;
  869. UINT curSize = 0;
  870. UINT index = 0;
  871. UINT size = 0;
  872. if (!InString) {
  873. return NULL;
  874. }
  875. if (*InString == 0) {
  876. return DuplicateTextA (InString);
  877. }
  878. //
  879. // Set source to the start of InString to begin with...
  880. //
  881. source = InString;
  882. __try {
  883. while (*source) {
  884. //
  885. // Reallocate the string if necessary. We assume that most strings
  886. // are smaller than 1024 chars and that we will therefore only rarely
  887. // reallocate a string.
  888. //
  889. if (curSize + 3 > maxSize) {
  890. maxSize += 1024;
  891. newString = AllocTextA (maxSize);
  892. if (rString) {
  893. CopyMemory (newString, rString, curSize * sizeof(CHAR)); //lint !e671
  894. FreeTextA(rString);
  895. }
  896. rString = newString;
  897. }
  898. //
  899. // if we find a percent sign, and we are not currently expanding
  900. // an environment variable (or copying an empty set of %'s),
  901. // then we have probably found an environment variable. Attempt
  902. // to expand it.
  903. //
  904. if (!IsLeadByte(source) && *source == '%' && !inSubstitution) {
  905. if (ignoreNextPercent) {
  906. ignoreNextPercent = FALSE;
  907. }
  908. else {
  909. ignoreNextPercent = FALSE;
  910. nextPercent = _mbschr(source + 1,'%');
  911. if (nextPercent == source + 1) {
  912. //
  913. // We found two consecutive %s in this string. We'll ignore them and simply copy them as
  914. // normal text.
  915. //
  916. ignoreNextPercent = TRUE;
  917. DEBUGMSGA((DBG_WARNING,"ExpandEnvironmentTextEx: Empty Environment variable in %s. Ignoring.",InString));
  918. }
  919. else if (nextPercent) {
  920. //
  921. // Create a variable to hold the envName.
  922. //
  923. envName = AllocTextA(nextPercent - source);
  924. StringCopyABA (envName, source+1, nextPercent);
  925. //
  926. // Try to find the variable.
  927. //
  928. foundValue = FALSE;
  929. freeValue = FALSE;
  930. if (ExtraVars) {
  931. //
  932. // Search through the list of extra vars passed in by the caller.
  933. // Even entries of this list are env var names. Odd entries are env values.
  934. // {envname1,envvalue1,envname2,envvalue2,...}
  935. //
  936. index = 0;
  937. while (ExtraVars[index]) {
  938. if (StringIMatchA (ExtraVars[index],envName) && ExtraVars[index + 1]) {
  939. foundValue = TRUE;
  940. envValue = (PSTR) ExtraVars[index + 1];
  941. break;
  942. }
  943. index +=2;
  944. }
  945. }
  946. if (!foundValue) {
  947. //
  948. // Still haven't found the environment variable. Use GetEnvironmentString.
  949. //
  950. //
  951. size = GetEnvironmentVariableA(envName,NULL,0);
  952. if (!size) {
  953. errorOccurred = TRUE;
  954. DEBUGMSGA((DBG_WARNING,"ExpandEnvironmentTextEx: Environment variable %s not found!",envName));
  955. }
  956. else {
  957. //
  958. // Create a buffer large enough to hold this value and copy it in.
  959. //
  960. envValue = AllocTextA(size);
  961. freeValue = TRUE;
  962. if ((size - 1) != GetEnvironmentVariableA(envName,envValue,size)) {
  963. errorOccurred = TRUE;
  964. DEBUGMSGA((DBG_ERROR,"ExpandEnvironmentTextEx: Error from GetEnvironmentVariable."));
  965. }
  966. else {
  967. foundValue = TRUE;
  968. }
  969. }
  970. }
  971. if (foundValue) {
  972. //
  973. // Ok, we have a valid environment value. Need to copy this data over.
  974. // To do this, we update and save the current source into old source, set source = to the envValue,
  975. // and set the inSubstitution value so that we don't attempt to expand any percents within
  976. // the value.
  977. //
  978. savedSource = nextPercent + 1;
  979. source = envValue;
  980. inSubstitution = TRUE;
  981. }
  982. else {
  983. DEBUGMSGA ((DBG_WARNING, "ExpandEnvironmentTextEx: No Environment variable found for %s.", envName));
  984. ignoreNextPercent = TRUE;
  985. }
  986. //
  987. // We are done with the environment name at this time, so clean it up.
  988. //
  989. FreeTextA(envName);
  990. envName = NULL;
  991. }
  992. ELSE_DEBUGMSGA((DBG_WARNING,"ExpandEnvironmentTextEx: No matching percent found in %s. Ignoring.",InString));
  993. }
  994. }
  995. //
  996. // Copy over the current character.
  997. //
  998. if (IsLeadByte(source)) { //lint !e613
  999. rString[curSize++] = *source++; //lint !e613
  1000. }
  1001. rString[curSize++] = *source++; //lint !e613
  1002. if (!*source) {
  1003. if (inSubstitution) {
  1004. //
  1005. // The source for the environment variable is fully copied.
  1006. // restore the old source.
  1007. //
  1008. inSubstitution = FALSE;
  1009. source = savedSource;
  1010. if (!*source) { //lint !e613
  1011. rString[curSize] = 0; //lint !e613
  1012. }
  1013. if (freeValue) {
  1014. FreeTextA(envValue);
  1015. freeValue = FALSE;
  1016. }
  1017. envValue = NULL;
  1018. }
  1019. else {
  1020. rString[curSize] = 0; //lint !e613
  1021. }
  1022. }
  1023. }
  1024. } //lint !e613
  1025. __finally {
  1026. DEBUGMSGA_IF (( errorOccurred, DBG_WARNING, "ExpandEnvironmentText: Some errors occurred while processing %s = %s.", InString, rString ? rString : "NULL"));
  1027. if (envName) {
  1028. FreeTextA(envName);
  1029. }
  1030. if (envValue && freeValue) {
  1031. FreeTextA(envValue);
  1032. }
  1033. }
  1034. return rString;
  1035. }
  1036. /*++
  1037. Routine Description:
  1038. AppendWack adds a backslash to the end of any string, unless the string
  1039. already ends in a backslash.
  1040. AppendDosWack adds a backslash, but only if the path does not already
  1041. end in a backslash or colon. AppendWack supports DOS naming
  1042. conventions: it does not append a back-slash if the path is empty,
  1043. ends in a colon or if it ends in a back-slash already.
  1044. AppendUncWack supports UNC naming conventions: it does not append a
  1045. backslash if the path is empty or if it ends in a backslash already.
  1046. AppendPathWack supports both DOS and UNC naming conventions, and uses the
  1047. UNC naming convention if the string starts with double-wacks.
  1048. Arguments:
  1049. Str - A buffer that holds the path, plus additional space for another
  1050. backslash.
  1051. Return Value:
  1052. none
  1053. --*/
  1054. PSTR
  1055. AppendWackA (
  1056. IN PSTR Str
  1057. )
  1058. {
  1059. PCSTR last;
  1060. if (!Str)
  1061. return Str;
  1062. last = Str;
  1063. while (*Str) {
  1064. last = Str;
  1065. Str = _mbsinc (Str);
  1066. }
  1067. if (*last != '\\') {
  1068. *Str = '\\';
  1069. Str++;
  1070. *Str = 0;
  1071. }
  1072. return Str;
  1073. }
  1074. PWSTR
  1075. AppendWackW (
  1076. IN PWSTR Str
  1077. )
  1078. {
  1079. PCWSTR last;
  1080. if (!Str)
  1081. return Str;
  1082. if (*Str) {
  1083. Str = GetEndOfStringW (Str);
  1084. last = Str - 1;
  1085. } else {
  1086. last = Str;
  1087. }
  1088. if (*last != '\\') {
  1089. *Str = L'\\';
  1090. Str++;
  1091. *Str = 0;
  1092. }
  1093. return Str;
  1094. }
  1095. PSTR
  1096. AppendDosWackA (
  1097. IN PSTR Str
  1098. )
  1099. {
  1100. PCSTR last;
  1101. if (!Str || !(*Str))
  1102. return Str;
  1103. do {
  1104. last = Str;
  1105. Str = _mbsinc (Str);
  1106. } while (*Str);
  1107. if (*last != '\\' && *last != ':') {
  1108. *Str = '\\';
  1109. Str++;
  1110. *Str = 0;
  1111. }
  1112. return Str;
  1113. }
  1114. PWSTR
  1115. AppendDosWackW (
  1116. IN PWSTR Str
  1117. )
  1118. {
  1119. PWSTR last;
  1120. if (!Str || !(*Str))
  1121. return Str;
  1122. Str = GetEndOfStringW (Str);
  1123. last = Str - 1;
  1124. if (*last != L'\\' && *last != L':') {
  1125. *Str = L'\\';
  1126. Str++;
  1127. *Str = 0;
  1128. }
  1129. return Str;
  1130. }
  1131. PSTR
  1132. AppendUncWackA (
  1133. IN PSTR Str
  1134. )
  1135. {
  1136. PCSTR last;
  1137. if (!Str || !(*Str))
  1138. return Str;
  1139. do {
  1140. last = Str;
  1141. Str = _mbsinc (Str);
  1142. } while (*Str);
  1143. if (*last != '\\') {
  1144. *Str = '\\';
  1145. Str++;
  1146. *Str = 0;
  1147. }
  1148. return Str;
  1149. }
  1150. PWSTR
  1151. AppendUncWackW (
  1152. IN PWSTR Str
  1153. )
  1154. {
  1155. PWSTR last;
  1156. if (!Str || !(*Str))
  1157. return Str;
  1158. Str = GetEndOfStringW (Str);
  1159. last = Str - 1;
  1160. if (*last != L'\\') {
  1161. *Str = L'\\';
  1162. Str++;
  1163. *Str = 0;
  1164. }
  1165. return Str;
  1166. }
  1167. PSTR
  1168. AppendPathWackA (
  1169. IN PSTR Str
  1170. )
  1171. {
  1172. if (!Str) {
  1173. return Str;
  1174. }
  1175. if (Str[0] == '\\' && Str[1] == '\\') {
  1176. return AppendUncWackA (Str);
  1177. }
  1178. return AppendDosWackA (Str);
  1179. }
  1180. PWSTR
  1181. AppendPathWackW (
  1182. IN PWSTR Str
  1183. )
  1184. {
  1185. if (!Str) {
  1186. return Str;
  1187. }
  1188. if (Str[0] == L'\\' && Str[1] == L'\\') {
  1189. return AppendUncWackW (Str);
  1190. }
  1191. return AppendDosWackW (Str);
  1192. }
  1193. DWORD
  1194. pGetStringsTotalSizeA (
  1195. IN va_list args
  1196. )
  1197. {
  1198. DWORD size = 0;
  1199. PCSTR source;
  1200. for (source = va_arg(args, PCSTR); source != NULL; source = va_arg(args, PCSTR)) {
  1201. size += ByteCountA (source) + DWSIZEOF(CHAR);
  1202. }
  1203. return size;
  1204. }
  1205. DWORD
  1206. pGetStringsTotalSizeW (
  1207. IN va_list args
  1208. )
  1209. {
  1210. DWORD size = 0;
  1211. PCWSTR source;
  1212. for (source = va_arg(args, PCWSTR); source != NULL; source = va_arg(args, PCWSTR)) {
  1213. size += ByteCountW (source) + DWSIZEOF(WCHAR);
  1214. }
  1215. return size;
  1216. }
  1217. PSTR
  1218. pJoinPathsInBufferA (
  1219. OUT PSTR Buffer,
  1220. IN va_list args
  1221. )
  1222. {
  1223. PSTR end;
  1224. PSTR endMinusOne;
  1225. PCSTR source;
  1226. PCSTR p;
  1227. INT counter;
  1228. *Buffer = 0;
  1229. counter = 0;
  1230. p = end = Buffer;
  1231. for (source = va_arg(args, PCSTR); source != NULL; source = va_arg(args, PCSTR)) {
  1232. if (counter > 0) {
  1233. endMinusOne = _mbsdec2 (p, end);
  1234. if (endMinusOne) {
  1235. if (_mbsnextc (source) == '\\') {
  1236. if (_mbsnextc (endMinusOne) == '\\') {
  1237. source++;
  1238. }
  1239. } else {
  1240. if (_mbsnextc (endMinusOne) != '\\') {
  1241. *end = '\\';
  1242. end++;
  1243. *end = 0;
  1244. }
  1245. }
  1246. }
  1247. }
  1248. if (*source) {
  1249. p = end;
  1250. end = StringCatA (end, source);
  1251. }
  1252. counter++;
  1253. }
  1254. return end;
  1255. }
  1256. PWSTR
  1257. pJoinPathsInBufferW (
  1258. OUT PWSTR Buffer,
  1259. IN va_list args
  1260. )
  1261. {
  1262. PWSTR end;
  1263. PWSTR endMinusOne;
  1264. PCWSTR source;
  1265. PCWSTR p;
  1266. INT counter;
  1267. *Buffer = 0;
  1268. counter = 0;
  1269. p = end = Buffer;
  1270. for (source = va_arg(args, PCWSTR); source != NULL; source = va_arg(args, PCWSTR)) {
  1271. if (counter > 0) {
  1272. endMinusOne = end > p ? end - 1 : NULL;
  1273. if (endMinusOne) {
  1274. if (*source == L'\\') {
  1275. if (*endMinusOne == L'\\') {
  1276. source++;
  1277. }
  1278. } else {
  1279. if (*endMinusOne != L'\\') {
  1280. *end = L'\\';
  1281. end++;
  1282. *end = 0;
  1283. }
  1284. }
  1285. }
  1286. }
  1287. if (*source) {
  1288. p = end;
  1289. end = StringCatW (end, source);
  1290. }
  1291. counter++;
  1292. }
  1293. return end;
  1294. }
  1295. PSTR
  1296. _cdecl
  1297. RealJoinPathsInPoolExA (
  1298. IN PMHANDLE Pool, OPTIONAL
  1299. ...
  1300. )
  1301. {
  1302. DWORD size;
  1303. PSTR dest;
  1304. va_list args;
  1305. if (!Pool) {
  1306. Pool = g_PathsPool;
  1307. }
  1308. va_start (args, Pool);
  1309. size = pGetStringsTotalSizeA (args);
  1310. va_end (args);
  1311. if (size == 0) {
  1312. return NULL;
  1313. }
  1314. dest = (PSTR) PmGetAlignedMemory (Pool, size);
  1315. MYASSERT (dest);
  1316. va_start (args, Pool);
  1317. pJoinPathsInBufferA (dest, args);
  1318. va_end (args);
  1319. return dest;
  1320. }
  1321. PWSTR
  1322. _cdecl
  1323. RealJoinPathsInPoolExW (
  1324. IN PMHANDLE Pool, OPTIONAL
  1325. ...
  1326. )
  1327. {
  1328. DWORD size;
  1329. PWSTR dest;
  1330. va_list args;
  1331. if (!Pool) {
  1332. Pool = g_PathsPool;
  1333. }
  1334. va_start (args, Pool);
  1335. size = pGetStringsTotalSizeW (args);
  1336. va_end (args);
  1337. if (size == 0) {
  1338. return NULL;
  1339. }
  1340. dest = (PWSTR) PmGetAlignedMemory (Pool, size);
  1341. MYASSERT (dest);
  1342. va_start (args, Pool);
  1343. pJoinPathsInBufferW (dest, args);
  1344. va_end (args);
  1345. return dest;
  1346. }
  1347. BOOL
  1348. JoinPathsExA (
  1349. IN OUT PGROWBUFFER Gb,
  1350. ...
  1351. )
  1352. {
  1353. PSTR end;
  1354. DWORD size;
  1355. va_list args;
  1356. MYASSERT (Gb);
  1357. if (!Gb) {
  1358. return FALSE;
  1359. }
  1360. va_start (args, Gb);
  1361. size = pGetStringsTotalSizeA (args);
  1362. va_end (args);
  1363. if (size == 0) {
  1364. return FALSE;
  1365. }
  1366. end = (PSTR) GbGrow (Gb, size);
  1367. if (!end) {
  1368. return FALSE;
  1369. }
  1370. va_start (args, Gb);
  1371. end = pJoinPathsInBufferA (end, args);
  1372. va_end (args);
  1373. //
  1374. // adjust Gb->End if resulting path is actually shorter than predicted
  1375. //
  1376. MYASSERT ((PBYTE)end >= Gb->Buf && (PBYTE)(end + 1) <= Gb->Buf + Gb->End);
  1377. Gb->End = (DWORD)((PBYTE)(end + 1) - Gb->Buf);
  1378. return TRUE;
  1379. }
  1380. BOOL
  1381. JoinPathsExW (
  1382. IN OUT PGROWBUFFER Gb,
  1383. ...
  1384. )
  1385. {
  1386. PWSTR end;
  1387. DWORD size;
  1388. va_list args;
  1389. MYASSERT (Gb);
  1390. if (!Gb) {
  1391. return FALSE;
  1392. }
  1393. va_start (args, Gb);
  1394. size = pGetStringsTotalSizeW (args);
  1395. va_end (args);
  1396. if (size == 0) {
  1397. return FALSE;
  1398. }
  1399. end = (PWSTR) GbGrow (Gb, size);
  1400. if (!end) {
  1401. return FALSE;
  1402. }
  1403. va_start (args, Gb);
  1404. end = pJoinPathsInBufferW (end, args);
  1405. va_end (args);
  1406. //
  1407. // adjust Gb->End if resulting path is actually shorter than predicted
  1408. //
  1409. MYASSERT ((PBYTE)end >= Gb->Buf && (PBYTE)(end + 1) <= Gb->Buf + Gb->End);
  1410. Gb->End = (DWORD)((PBYTE)(end + 1) - Gb->Buf);
  1411. return TRUE;
  1412. }
  1413. PSTR
  1414. pBuildPathInBufferA (
  1415. OUT PSTR Buffer,
  1416. IN va_list args
  1417. )
  1418. {
  1419. PCSTR source;
  1420. INT counter;
  1421. *Buffer = 0;
  1422. counter = 0;
  1423. for (source = va_arg(args, PCSTR); source != NULL; source = va_arg(args, PCSTR)) {
  1424. if (counter > 0) {
  1425. *Buffer++ = '\\';
  1426. *Buffer = 0;
  1427. }
  1428. Buffer = StringCatA (Buffer, source);
  1429. counter++;
  1430. }
  1431. return Buffer;
  1432. }
  1433. PWSTR
  1434. pBuildPathInBufferW (
  1435. OUT PWSTR Buffer,
  1436. IN va_list args
  1437. )
  1438. {
  1439. PCWSTR source;
  1440. INT counter;
  1441. *Buffer = 0;
  1442. counter = 0;
  1443. for (source = va_arg(args, PCWSTR); source != NULL; source = va_arg(args, PCWSTR)) {
  1444. if (counter > 0) {
  1445. *Buffer++ = L'\\';
  1446. *Buffer = 0;
  1447. }
  1448. Buffer = StringCatW (Buffer, source);
  1449. counter++;
  1450. }
  1451. return Buffer;
  1452. }
  1453. DWORD
  1454. BuildPathA (
  1455. OUT PSTR Buffer, OPTIONAL
  1456. IN DWORD SizeInBytes, OPTIONAL
  1457. ...
  1458. )
  1459. {
  1460. PSTR end;
  1461. DWORD size;
  1462. va_list args;
  1463. va_start (args, SizeInBytes);
  1464. size = pGetStringsTotalSizeA (args);
  1465. va_end (args);
  1466. if (!size) {
  1467. //
  1468. // no args
  1469. //
  1470. return 0;
  1471. }
  1472. if (!Buffer) {
  1473. return size;
  1474. }
  1475. if (SizeInBytes < size) {
  1476. //
  1477. // buffer too small
  1478. //
  1479. return 0;
  1480. }
  1481. va_start (args, SizeInBytes);
  1482. end = pBuildPathInBufferA (Buffer, args);
  1483. va_end (args);
  1484. MYASSERT (size == (DWORD)((PBYTE)(end + 1) - (PBYTE)Buffer));
  1485. return size;
  1486. }
  1487. DWORD
  1488. BuildPathW (
  1489. OUT PWSTR Buffer, OPTIONAL
  1490. IN DWORD SizeInBytes, OPTIONAL
  1491. ...
  1492. )
  1493. {
  1494. PWSTR end;
  1495. DWORD size;
  1496. va_list args;
  1497. va_start (args, SizeInBytes);
  1498. size = pGetStringsTotalSizeW (args);
  1499. va_end (args);
  1500. if (!size) {
  1501. //
  1502. // no args
  1503. //
  1504. return 0;
  1505. }
  1506. if (!Buffer) {
  1507. return size;
  1508. }
  1509. if (SizeInBytes < size) {
  1510. //
  1511. // buffer too small
  1512. //
  1513. return 0;
  1514. }
  1515. va_start (args, SizeInBytes);
  1516. end = pBuildPathInBufferW (Buffer, args);
  1517. va_end (args);
  1518. MYASSERT (size == (DWORD)((PBYTE)(end + 1) - (PBYTE)Buffer));
  1519. return size;
  1520. }
  1521. BOOL
  1522. BuildPathExA (
  1523. IN OUT PGROWBUFFER Gb,
  1524. ...
  1525. )
  1526. {
  1527. PSTR end;
  1528. DWORD size;
  1529. va_list args;
  1530. MYASSERT (Gb);
  1531. if (!Gb) {
  1532. return FALSE;
  1533. }
  1534. va_start (args, Gb);
  1535. size = pGetStringsTotalSizeA (args);
  1536. va_end (args);
  1537. if (!size) {
  1538. //
  1539. // no args
  1540. //
  1541. return FALSE;
  1542. }
  1543. end = (PSTR) GbGrow (Gb, size);
  1544. if (!end) {
  1545. return FALSE;
  1546. }
  1547. va_start (args, Gb);
  1548. end = pBuildPathInBufferA (end, args);
  1549. va_end (args);
  1550. MYASSERT ((PBYTE)(end + 1) == Gb->Buf + Gb->End);
  1551. return (size != 0);
  1552. }
  1553. BOOL
  1554. BuildPathExW (
  1555. IN OUT PGROWBUFFER Gb,
  1556. ...
  1557. )
  1558. {
  1559. PWSTR end;
  1560. DWORD size;
  1561. va_list args;
  1562. MYASSERT (Gb);
  1563. if (!Gb) {
  1564. return FALSE;
  1565. }
  1566. va_start (args, Gb);
  1567. size = pGetStringsTotalSizeW (args);
  1568. va_end (args);
  1569. if (!size) {
  1570. //
  1571. // no args
  1572. //
  1573. return FALSE;
  1574. }
  1575. end = (PWSTR) GbGrow (Gb, size);
  1576. if (!end) {
  1577. return FALSE;
  1578. }
  1579. va_start (args, Gb);
  1580. end = pBuildPathInBufferW (end, args);
  1581. va_end (args);
  1582. MYASSERT ((PBYTE)(end + 1) == Gb->Buf + Gb->End);
  1583. return (size != 0);
  1584. }
  1585. PSTR
  1586. RealBuildPathInPoolA (
  1587. IN PMHANDLE Pool, OPTIONAL
  1588. ...
  1589. )
  1590. {
  1591. PSTR dest;
  1592. DWORD size;
  1593. va_list args;
  1594. if (!Pool) {
  1595. Pool = g_PathsPool;
  1596. }
  1597. va_start (args, Pool);
  1598. size = pGetStringsTotalSizeA (args);
  1599. va_end (args);
  1600. if (!size) {
  1601. //
  1602. // no args
  1603. //
  1604. return NULL;
  1605. }
  1606. dest = (PSTR) PmGetAlignedMemory (Pool, size);
  1607. MYASSERT (dest);
  1608. va_start (args, Pool);
  1609. pBuildPathInBufferA (dest, args);
  1610. va_end (args);
  1611. return dest;
  1612. }
  1613. PWSTR
  1614. RealBuildPathInPoolW (
  1615. IN PMHANDLE Pool, OPTIONAL
  1616. ...
  1617. )
  1618. {
  1619. PWSTR dest;
  1620. DWORD size;
  1621. va_list args;
  1622. if (!Pool) {
  1623. Pool = g_PathsPool;
  1624. }
  1625. va_start (args, Pool);
  1626. size = pGetStringsTotalSizeW (args);
  1627. va_end (args);
  1628. if (!size) {
  1629. //
  1630. // no args
  1631. //
  1632. return NULL;
  1633. }
  1634. dest = (PWSTR) PmGetAlignedMemory (Pool, size);
  1635. MYASSERT (dest);
  1636. va_start (args, Pool);
  1637. pBuildPathInBufferW (dest, args);
  1638. va_end (args);
  1639. return dest;
  1640. }
  1641. PSTR
  1642. RealAllocPathStringA (
  1643. IN DWORD Tchars
  1644. )
  1645. {
  1646. PSTR str;
  1647. if (Tchars == 0) {
  1648. Tchars = MAX_MBCHAR_PATH;
  1649. }
  1650. str = (PSTR) PmGetAlignedMemory (g_PathsPool, Tchars);
  1651. str [0] = 0;
  1652. return str;
  1653. }
  1654. PWSTR
  1655. RealAllocPathStringW (
  1656. IN DWORD Tchars
  1657. )
  1658. {
  1659. PWSTR str;
  1660. if (Tchars == 0) {
  1661. Tchars = MAX_WCHAR_PATH;
  1662. }
  1663. str = (PWSTR) PmGetAlignedMemory (g_PathsPool, Tchars * sizeof (WCHAR));
  1664. str [0] = 0;
  1665. return str;
  1666. }
  1667. VOID
  1668. RealSplitPathA (
  1669. IN PCSTR Path,
  1670. OUT PSTR *DrivePtr,
  1671. OUT PSTR *PathPtr,
  1672. OUT PSTR *FileNamePtr,
  1673. OUT PSTR *ExtPtr
  1674. )
  1675. {
  1676. CHAR drive[_MAX_DRIVE];
  1677. CHAR dir[_MAX_DIR];
  1678. CHAR fileName[_MAX_FNAME];
  1679. CHAR ext[_MAX_EXT];
  1680. _splitpath (Path, drive, dir, fileName, ext);
  1681. if (DrivePtr) {
  1682. *DrivePtr = PmDuplicateStringA (g_PathsPool, drive);
  1683. MYASSERT (*DrivePtr);
  1684. }
  1685. if (PathPtr) {
  1686. *PathPtr = PmDuplicateStringA (g_PathsPool, dir);
  1687. MYASSERT (*PathPtr);
  1688. }
  1689. if (FileNamePtr) {
  1690. *FileNamePtr = PmDuplicateStringA (g_PathsPool, fileName);
  1691. MYASSERT (*FileNamePtr);
  1692. }
  1693. if (ExtPtr) {
  1694. *ExtPtr = PmDuplicateStringA (g_PathsPool, ext);
  1695. MYASSERT (*ExtPtr);
  1696. }
  1697. }
  1698. VOID
  1699. RealSplitPathW (
  1700. IN PCWSTR Path,
  1701. OUT PWSTR *DrivePtr,
  1702. OUT PWSTR *PathPtr,
  1703. OUT PWSTR *FileNamePtr,
  1704. OUT PWSTR *ExtPtr
  1705. )
  1706. {
  1707. WCHAR drive[_MAX_DRIVE];
  1708. WCHAR dir[_MAX_DIR];
  1709. WCHAR fileName[_MAX_FNAME];
  1710. WCHAR ext[_MAX_EXT];
  1711. _wsplitpath (Path, drive, dir, fileName, ext);
  1712. if (DrivePtr) {
  1713. *DrivePtr = PmDuplicateStringW (g_PathsPool, drive);
  1714. MYASSERT (*DrivePtr);
  1715. }
  1716. if (PathPtr) {
  1717. *PathPtr = PmDuplicateStringW (g_PathsPool, dir);
  1718. MYASSERT (*PathPtr);
  1719. }
  1720. if (FileNamePtr) {
  1721. *FileNamePtr = PmDuplicateStringW (g_PathsPool, fileName);
  1722. MYASSERT (*FileNamePtr);
  1723. }
  1724. if (ExtPtr) {
  1725. *ExtPtr = PmDuplicateStringW (g_PathsPool, ext);
  1726. MYASSERT (*ExtPtr);
  1727. }
  1728. }
  1729. PSTR
  1730. RealDuplicatePathStringA (
  1731. IN PCSTR Path,
  1732. IN DWORD ExtraBytes
  1733. )
  1734. {
  1735. PSTR str;
  1736. str = PmGetAlignedMemory (
  1737. g_PathsPool,
  1738. SizeOfStringA (Path) + ExtraBytes
  1739. );
  1740. MYASSERT (str);
  1741. StringCopyA (str, Path);
  1742. return str;
  1743. }
  1744. PWSTR
  1745. RealDuplicatePathStringW (
  1746. IN PCWSTR Path,
  1747. IN DWORD ExtraBytes
  1748. )
  1749. {
  1750. PWSTR str;
  1751. str = PmGetAlignedMemory (
  1752. g_PathsPool,
  1753. SizeOfStringW (Path) + ExtraBytes
  1754. );
  1755. MYASSERT (str);
  1756. StringCopyW (str, Path);
  1757. return str;
  1758. }
  1759. BOOL
  1760. EnumFirstPathExA (
  1761. OUT PPATH_ENUMA PathEnum,
  1762. IN PCSTR AdditionalPath,
  1763. IN PCSTR WinDir,
  1764. IN PCSTR SysDir,
  1765. IN BOOL IncludeEnvPath
  1766. )
  1767. {
  1768. DWORD bufferSize;
  1769. DWORD pathSize;
  1770. PSTR currPathEnd;
  1771. if (PathEnum == NULL) {
  1772. return FALSE;
  1773. }
  1774. bufferSize = pathSize = GetEnvironmentVariableA ("PATH", NULL, 0);
  1775. bufferSize *= 2;
  1776. if (AdditionalPath != NULL) {
  1777. bufferSize += SizeOfStringA (AdditionalPath);
  1778. }
  1779. if (SysDir != NULL) {
  1780. bufferSize += SizeOfStringA (SysDir);
  1781. }
  1782. if (WinDir != NULL) {
  1783. bufferSize += SizeOfStringA (WinDir);
  1784. }
  1785. PathEnum->BufferPtr = HeapAlloc (g_hHeap, 0, bufferSize);
  1786. if (PathEnum->BufferPtr == NULL) {
  1787. return FALSE;
  1788. }
  1789. PathEnum->BufferPtr [0] = 0;
  1790. if (AdditionalPath != NULL) {
  1791. StringCopyA (PathEnum->BufferPtr, AdditionalPath);
  1792. StringCatA (PathEnum->BufferPtr, ";");
  1793. }
  1794. if (SysDir != NULL) {
  1795. StringCatA (PathEnum->BufferPtr, SysDir);
  1796. StringCatA (PathEnum->BufferPtr, ";");
  1797. }
  1798. if (WinDir != NULL) {
  1799. StringCatA (PathEnum->BufferPtr, WinDir);
  1800. StringCatA (PathEnum->BufferPtr, ";");
  1801. }
  1802. if (IncludeEnvPath) {
  1803. currPathEnd = GetEndOfStringA (PathEnum->BufferPtr);
  1804. GetEnvironmentVariableA ("PATH", currPathEnd, pathSize);
  1805. }
  1806. PathEnum->PtrNextPath = PathEnum-> BufferPtr;
  1807. return EnumNextPathA (PathEnum);
  1808. }
  1809. BOOL
  1810. EnumNextPathA (
  1811. IN OUT PPATH_ENUMA PathEnum
  1812. )
  1813. {
  1814. PSTR currPathEnd;
  1815. if (PathEnum->PtrNextPath == NULL) {
  1816. AbortPathEnumA (PathEnum);
  1817. return FALSE;
  1818. }
  1819. PathEnum->PtrCurrPath = PathEnum->PtrNextPath;
  1820. PathEnum->PtrNextPath = _mbschr (PathEnum->PtrNextPath, ';');
  1821. if (PathEnum->PtrNextPath == NULL) {
  1822. return TRUE;
  1823. }
  1824. currPathEnd = PathEnum->PtrNextPath;
  1825. PathEnum->PtrNextPath = _mbsinc (PathEnum->PtrNextPath);
  1826. *currPathEnd = 0;
  1827. if (*(PathEnum->PtrNextPath) == 0) {
  1828. PathEnum->PtrNextPath = NULL;
  1829. }
  1830. if (*(PathEnum->PtrCurrPath) == 0) {
  1831. //
  1832. // We found an empty path segment. Skip it.
  1833. //
  1834. return EnumNextPathA (PathEnum);
  1835. }
  1836. return TRUE;
  1837. }
  1838. BOOL
  1839. AbortPathEnumA (
  1840. IN OUT PPATH_ENUMA PathEnum
  1841. )
  1842. {
  1843. if (PathEnum->BufferPtr != NULL) {
  1844. HeapFree (g_hHeap, 0, PathEnum->BufferPtr);
  1845. PathEnum->BufferPtr = NULL;
  1846. }
  1847. return TRUE;
  1848. }
  1849. BOOL
  1850. EnumFirstPathExW (
  1851. OUT PPATH_ENUMW PathEnum,
  1852. IN PCWSTR AdditionalPath,
  1853. IN PCWSTR WinDir,
  1854. IN PCWSTR SysDir,
  1855. IN BOOL IncludeEnvPath
  1856. )
  1857. {
  1858. DWORD bufferSize;
  1859. DWORD pathSize;
  1860. PWSTR currPathEnd;
  1861. if (PathEnum == NULL) {
  1862. return FALSE;
  1863. }
  1864. bufferSize = pathSize = GetEnvironmentVariableW (L"PATH", NULL, 0);
  1865. bufferSize *= 2;
  1866. if (AdditionalPath != NULL) {
  1867. bufferSize += SizeOfStringW (AdditionalPath);
  1868. }
  1869. if (SysDir != NULL) {
  1870. bufferSize += SizeOfStringW (SysDir);
  1871. }
  1872. if (WinDir != NULL) {
  1873. bufferSize += SizeOfStringW (WinDir);
  1874. }
  1875. PathEnum->BufferPtr = HeapAlloc (g_hHeap, 0, bufferSize);
  1876. if (PathEnum->BufferPtr == NULL) {
  1877. return FALSE;
  1878. }
  1879. PathEnum->BufferPtr [0] = 0;
  1880. if (AdditionalPath != NULL) {
  1881. StringCopyW (PathEnum->BufferPtr, AdditionalPath);
  1882. StringCatW (PathEnum->BufferPtr, L";");
  1883. }
  1884. if (SysDir != NULL) {
  1885. StringCatW (PathEnum->BufferPtr, SysDir);
  1886. StringCatW (PathEnum->BufferPtr, L";");
  1887. }
  1888. if (WinDir != NULL) {
  1889. StringCatW (PathEnum->BufferPtr, WinDir);
  1890. StringCatW (PathEnum->BufferPtr, L";");
  1891. }
  1892. if (IncludeEnvPath) {
  1893. currPathEnd = GetEndOfStringW (PathEnum->BufferPtr);
  1894. GetEnvironmentVariableW (L"PATH", currPathEnd, pathSize);
  1895. }
  1896. PathEnum->PtrNextPath = PathEnum-> BufferPtr;
  1897. return EnumNextPathW (PathEnum);
  1898. }
  1899. BOOL
  1900. EnumNextPathW (
  1901. IN OUT PPATH_ENUMW PathEnum
  1902. )
  1903. {
  1904. PWSTR currPathEnd;
  1905. if (PathEnum->PtrNextPath == NULL) {
  1906. AbortPathEnumW (PathEnum);
  1907. return FALSE;
  1908. }
  1909. PathEnum->PtrCurrPath = PathEnum->PtrNextPath;
  1910. PathEnum->PtrNextPath = wcschr (PathEnum->PtrNextPath, L';');
  1911. if (PathEnum->PtrNextPath == NULL) {
  1912. return TRUE;
  1913. }
  1914. currPathEnd = PathEnum->PtrNextPath;
  1915. PathEnum->PtrNextPath ++;
  1916. *currPathEnd = 0;
  1917. if (*(PathEnum->PtrNextPath) == 0) {
  1918. PathEnum->PtrNextPath = NULL;
  1919. }
  1920. if (*(PathEnum->PtrCurrPath) == 0) {
  1921. //
  1922. // We found an empty path segment. Skip it.
  1923. //
  1924. return EnumNextPathW (PathEnum);
  1925. }
  1926. return TRUE;
  1927. }
  1928. BOOL
  1929. AbortPathEnumW (
  1930. IN OUT PPATH_ENUMW PathEnum
  1931. )
  1932. {
  1933. if (PathEnum->BufferPtr != NULL) {
  1934. HeapFree (g_hHeap, 0, PathEnum->BufferPtr);
  1935. PathEnum->BufferPtr = NULL;
  1936. }
  1937. return TRUE;
  1938. }
  1939. VOID
  1940. FreePathStringExA (
  1941. IN PMHANDLE Pool, OPTIONAL
  1942. IN PCSTR Path OPTIONAL
  1943. )
  1944. {
  1945. if (Path) {
  1946. if (!Pool) {
  1947. Pool = g_PathsPool;
  1948. }
  1949. PmReleaseMemory (Pool, (PSTR) Path);
  1950. }
  1951. }
  1952. VOID
  1953. FreePathStringExW (
  1954. IN PMHANDLE Pool, OPTIONAL
  1955. IN PCWSTR Path OPTIONAL
  1956. )
  1957. {
  1958. if (Path) {
  1959. if (!Pool) {
  1960. Pool = g_PathsPool;
  1961. }
  1962. PmReleaseMemory (Pool, (PWSTR) Path);
  1963. }
  1964. }
  1965. /*++
  1966. Routine Description:
  1967. PushError and PopError push the error code onto a stack or pull the
  1968. last pushed error code off the stack. PushError uses GetLastError
  1969. and PopError uses SetLastError to modify the last error value.
  1970. Arguments:
  1971. none
  1972. Return Value:
  1973. none
  1974. --*/
  1975. VOID
  1976. PushNewError (DWORD dwError)
  1977. {
  1978. if (g_dwStackPos == MAX_STACK)
  1979. return;
  1980. g_dwErrorStack[g_dwStackPos] = dwError;
  1981. g_dwStackPos++;
  1982. }
  1983. VOID
  1984. PushError (VOID)
  1985. {
  1986. if (g_dwStackPos == MAX_STACK)
  1987. return;
  1988. g_dwErrorStack[g_dwStackPos] = GetLastError ();
  1989. g_dwStackPos++;
  1990. }
  1991. DWORD
  1992. PopError (VOID)
  1993. {
  1994. if (!g_dwStackPos)
  1995. return GetLastError();
  1996. g_dwStackPos--;
  1997. SetLastError (g_dwErrorStack[g_dwStackPos]);
  1998. return g_dwErrorStack[g_dwStackPos];
  1999. }
  2000. /*++
  2001. Routine Description:
  2002. GetHexDigit is a simple base 16 ASCII to int convertor. The
  2003. convertor is case-insensitive.
  2004. Arguments:
  2005. c - Character to convert
  2006. Return Value:
  2007. Base 16 value corresponding to character supplied, or -1 if
  2008. the character is not 0-9, A-F or a-f.
  2009. --*/
  2010. int
  2011. GetHexDigit (IN int c)
  2012. {
  2013. if (c >= '0' && c <= '9')
  2014. return (c - '0');
  2015. c = towlower ((wint_t) c);
  2016. if (c >= 'a' && c <= 'f')
  2017. return (c - 'a' + 10);
  2018. return -1;
  2019. }
  2020. /*++
  2021. Routine Description:
  2022. _tcsnum is similar to strtoul, except is figures out which base
  2023. the number should be calculated from. It supports decimal and
  2024. hexadecimal numbers (using the 0x00 notation). The return
  2025. value is the decoded value, or 0 if a syntax error was found.
  2026. Arguments:
  2027. szNum - Pointer to the string holding the number. This number
  2028. can be either decimal (a series of 0-9 characters), or
  2029. hexadecimal (a series of 0-9, A-F or a-f characters,
  2030. prefixed with 0x or 0X).
  2031. Return Value:
  2032. The decoded unsigned long value, or zero if a syntax error was
  2033. found.
  2034. --*/
  2035. DWORD
  2036. _mbsnum (IN PCSTR szNum)
  2037. {
  2038. unsigned int d = 0;
  2039. int i;
  2040. if (szNum[0] == '0' && OURTOLOWER (szNum[1]) == 'x') {
  2041. // Get hex value
  2042. szNum += 2;
  2043. while ((i = GetHexDigit ((int) *szNum)) != -1) {
  2044. d = d * 16 + (UINT)i;
  2045. szNum++;
  2046. }
  2047. }
  2048. else {
  2049. // Get decimal value
  2050. while (*szNum >= '0' && *szNum <= '9') {
  2051. d = d * 10 + (*szNum - '0');
  2052. szNum++;
  2053. }
  2054. }
  2055. return d;
  2056. }
  2057. DWORD
  2058. _wcsnum (
  2059. IN PCWSTR szNum
  2060. )
  2061. {
  2062. unsigned int d = 0;
  2063. int i;
  2064. if (szNum[0] == L'0' && towlower (szNum[1]) == L'x') {
  2065. // Get hex value
  2066. szNum += 2;
  2067. while ((i = GetHexDigit ((int) *szNum)) != -1) {
  2068. d = d * 16 + (UINT)i;
  2069. szNum++;
  2070. }
  2071. }
  2072. else {
  2073. // Get decimal value
  2074. while (*szNum >= L'0' && *szNum <= L'9') {
  2075. d = d * 10 + (*szNum - L'0');
  2076. szNum++;
  2077. }
  2078. }
  2079. return d;
  2080. }
  2081. /*++
  2082. Routine Description:
  2083. StringCat is a lstrcat-type routine. It returns the pointer to the end
  2084. of a string instead of the beginning, is faster, and has the proper types
  2085. to keep lint happy.
  2086. Arguments:
  2087. Destination - A pointer to a caller-allocated buffer that may point
  2088. anywhere within the string to append to
  2089. Source - A pointer to a string that is appended to Destination
  2090. Return Value:
  2091. A pointer to the NULL terminator within the Destination string.
  2092. --*/
  2093. PSTR
  2094. StringCatA (
  2095. OUT PSTR Destination,
  2096. IN PCSTR Source
  2097. )
  2098. {
  2099. PCSTR current = Source;
  2100. PCSTR end;
  2101. //
  2102. // Advance Destination to end of string
  2103. //
  2104. Destination = GetEndOfStringA (Destination);
  2105. while (*current) {
  2106. *Destination++ = *current++; //lint !e613
  2107. }
  2108. //
  2109. // Make sure DBCS string is properly terminated
  2110. //
  2111. end = current;
  2112. current--;
  2113. while (current >= Source) {
  2114. if (!IsLeadByte (current)) {
  2115. //
  2116. // destEnd is correct
  2117. //
  2118. break;
  2119. }
  2120. current--;
  2121. }
  2122. if (!((end - current) & 1)) {
  2123. Destination--; //lint !e794
  2124. }
  2125. *Destination = 0; //lint !e794
  2126. return Destination;
  2127. }
  2128. PWSTR
  2129. StringCatW (
  2130. OUT PWSTR Destination,
  2131. IN PCWSTR Source
  2132. )
  2133. {
  2134. //
  2135. // Advance Destination to end of string
  2136. //
  2137. Destination = GetEndOfStringW (Destination);
  2138. //
  2139. // Copy string
  2140. //
  2141. while (*Source) {
  2142. *Destination++ = *Source++;
  2143. }
  2144. *Destination = 0;
  2145. return Destination;
  2146. }
  2147. /*++
  2148. Routine Description:
  2149. _tcsistr is a case-insensitive version of _tcsstr.
  2150. Arguments:
  2151. szStr - A pointer to the larger string, which may hold szSubStr
  2152. szSubStr - A pointer to a string that may be enclosed in szStr
  2153. Return Value:
  2154. A pointer to the first occurance of szSubStr in szStr, or NULL if
  2155. no match is found.
  2156. --*/
  2157. PCSTR
  2158. _mbsistr (PCSTR mbstrStr, PCSTR mbstrSubStr)
  2159. {
  2160. PCSTR mbstrStart, mbstrStrPos, mbstrSubStrPos;
  2161. PCSTR mbstrEnd;
  2162. mbstrEnd = (PSTR) ((LPBYTE) mbstrStr + ByteCountA (mbstrStr) - ByteCountA (mbstrSubStr));
  2163. for (mbstrStart = mbstrStr ; mbstrStart <= mbstrEnd ; mbstrStart = _mbsinc (mbstrStart)) {
  2164. mbstrStrPos = mbstrStart;
  2165. mbstrSubStrPos = mbstrSubStr;
  2166. while (*mbstrSubStrPos &&
  2167. OURTOLOWER ((MBCHAR) _mbsnextc (mbstrSubStrPos)) == OURTOLOWER ((MBCHAR) _mbsnextc (mbstrStrPos)))
  2168. {
  2169. mbstrStrPos = _mbsinc (mbstrStrPos);
  2170. mbstrSubStrPos = _mbsinc (mbstrSubStrPos);
  2171. }
  2172. if (!(*mbstrSubStrPos))
  2173. return mbstrStart;
  2174. }
  2175. return NULL;
  2176. }
  2177. PCWSTR
  2178. _wcsistr (PCWSTR wstrStr, PCWSTR wstrSubStr)
  2179. {
  2180. PCWSTR wstrStart, wstrStrPos, wstrSubStrPos;
  2181. PCWSTR wstrEnd;
  2182. wstrEnd = (PWSTR) ((LPBYTE) wstrStr + ByteCountW (wstrStr) - ByteCountW (wstrSubStr));
  2183. for (wstrStart = wstrStr ; wstrStart <= wstrEnd ; wstrStart++) {
  2184. wstrStrPos = wstrStart;
  2185. wstrSubStrPos = wstrSubStr;
  2186. while (*wstrSubStrPos &&
  2187. towlower (*wstrSubStrPos) == towlower (*wstrStrPos))
  2188. {
  2189. wstrStrPos++;
  2190. wstrSubStrPos++;
  2191. }
  2192. if (!(*wstrSubStrPos))
  2193. return wstrStart;
  2194. }
  2195. return NULL;
  2196. }
  2197. /*++
  2198. Routine Description:
  2199. StringCompareAB compares a string against a string between to string
  2200. pointers
  2201. Arguments:
  2202. String - Specifies the string to compare
  2203. Start - Specifies the start of the string to compare against
  2204. end - Specifies the end of the string to compare against. The character
  2205. pointed to by End is not included in the comparision.
  2206. Return Value:
  2207. Less than zero: String is numerically less than the string between Start and
  2208. End
  2209. Zero: String matches the string between Start and End identically
  2210. Greater than zero: String is numerically greater than the string between
  2211. Start and End
  2212. --*/
  2213. INT
  2214. StringCompareABA (
  2215. IN PCSTR String,
  2216. IN PCSTR Start,
  2217. IN PCSTR End
  2218. )
  2219. {
  2220. while (*String && Start < End) {
  2221. if (_mbsnextc (String) != _mbsnextc (Start)) {
  2222. break;
  2223. }
  2224. String = _mbsinc (String);
  2225. Start = _mbsinc (Start);
  2226. }
  2227. if (Start == End && *String == 0) {
  2228. return 0;
  2229. }
  2230. return (INT) (_mbsnextc (Start) - _mbsnextc (String));
  2231. }
  2232. INT
  2233. StringCompareABW (
  2234. IN PCWSTR String,
  2235. IN PCWSTR Start,
  2236. IN PCWSTR End
  2237. )
  2238. {
  2239. while (*String && Start < End) {
  2240. if (*String != *Start) {
  2241. break;
  2242. }
  2243. String++;
  2244. Start++;
  2245. }
  2246. if (Start == End && *String == 0) {
  2247. return 0;
  2248. }
  2249. return *Start - *String;
  2250. }
  2251. BOOL
  2252. StringMatchA (
  2253. IN PCSTR String1,
  2254. IN PCSTR String2
  2255. )
  2256. /*++
  2257. Routine Description:
  2258. StringMatchA is an optimized string compare. Usually a comparison is used to
  2259. see if two strings are identical, and the numeric releationships aren't
  2260. important. This routine exploits that fact and does a byte-by-byte compare.
  2261. Arguments:
  2262. String1 - Specifies the first string to compare
  2263. String2 - Specifies the second string to compare
  2264. Return Value:
  2265. TRUE if the strings match identically, FALSE otherwise.
  2266. --*/
  2267. {
  2268. while (*String1) {
  2269. if (*String1 != *String2) {
  2270. return FALSE;
  2271. }
  2272. String1++;
  2273. String2++;
  2274. }
  2275. if (*String2) {
  2276. return FALSE;
  2277. }
  2278. return TRUE;
  2279. }
  2280. BOOL
  2281. StringMatchABA (
  2282. IN PCSTR String,
  2283. IN PCSTR Start,
  2284. IN PCSTR End
  2285. )
  2286. /*++
  2287. Routine Description:
  2288. StringMatchABA is an optimized string compare. Usually a comparison is
  2289. used to see if two strings are identical, and the numeric releationships
  2290. aren't important. This routine exploits that fact and does a byte-by-byte
  2291. compare.
  2292. Arguments:
  2293. String - Specifies the first string to compare
  2294. Start - Specifies the beginning of the second string to compare
  2295. End - Specifies the end of the second string to compare (points to one
  2296. character beyond the last valid character of the second string)
  2297. Return Value:
  2298. TRUE if the strings match identically, FALSE otherwise. If End is equal
  2299. or less than Start, the return value is always TRUE.
  2300. --*/
  2301. {
  2302. while (*String && Start < End) {
  2303. if (*String != *Start) {
  2304. return FALSE;
  2305. }
  2306. String++;
  2307. Start++;
  2308. }
  2309. if (Start < End && *Start) {
  2310. return FALSE;
  2311. }
  2312. return TRUE;
  2313. }
  2314. INT
  2315. StringICompareABA (
  2316. IN PCSTR String,
  2317. IN PCSTR Start,
  2318. IN PCSTR End
  2319. )
  2320. {
  2321. while (*String && Start < End) {
  2322. if (OURTOLOWER ((INT)(_mbsnextc (String))) != OURTOLOWER ((INT)(_mbsnextc (Start)))) {
  2323. break;
  2324. }
  2325. String = _mbsinc (String);
  2326. Start = _mbsinc (Start);
  2327. }
  2328. if (Start == End && *String == 0) {
  2329. return 0;
  2330. }
  2331. return (OURTOLOWER ((INT)(_mbsnextc (Start))) - OURTOLOWER ((INT)(_mbsnextc (String))));
  2332. }
  2333. INT
  2334. StringICompareABW (
  2335. IN PCWSTR String,
  2336. IN PCWSTR Start,
  2337. IN PCWSTR End
  2338. )
  2339. {
  2340. while (*String && Start < End) {
  2341. if (towlower (*String) != towlower (*Start)) {
  2342. break;
  2343. }
  2344. String++;
  2345. Start++;
  2346. }
  2347. if (Start == End && *String == 0) {
  2348. return 0;
  2349. }
  2350. return towlower (*Start) - towlower (*String);
  2351. }
  2352. VOID
  2353. _setmbchar (
  2354. IN OUT PSTR Str,
  2355. IN MBCHAR c
  2356. )
  2357. /*++
  2358. Routine Description:
  2359. _setmbchar sets the character at the specified string position, shifting
  2360. bytes if necessary to keep the string in tact.
  2361. Arguments:
  2362. Str - String
  2363. c - Character to set
  2364. Return Value:
  2365. none
  2366. --*/
  2367. {
  2368. if (c < 256) {
  2369. if (IsLeadByte (Str)) {
  2370. //
  2371. // Delete one byte from the string
  2372. //
  2373. MoveMemory (Str, Str+1, SizeOfStringA (Str+2) + 1);
  2374. }
  2375. *Str = (CHAR) c;
  2376. } else {
  2377. if (!IsLeadByte (Str)) {
  2378. //
  2379. // Insert one byte in the string
  2380. //
  2381. MoveMemory (Str+1, Str, SizeOfStringA (Str));
  2382. }
  2383. *((WORD *) Str) = (WORD) c;
  2384. }
  2385. }
  2386. /*++
  2387. Routine Description:
  2388. GetNextRuleChar extracts the first character in the *p_szRule string,
  2389. and determines the character value, decoding the ~xx~ syntax (which
  2390. specifies any arbitrary value).
  2391. GetNextRuleChar returns a complete character for SBCS and UNICODE, but
  2392. it may return either a lead byte or non-lead byte for MBCS. To indicate
  2393. a MBCS character, two ~xx~ hex values are needed.
  2394. Arguments:
  2395. p_szRule - A pointer to a pointer; a caller-allocated buffer that
  2396. holds the rule string.
  2397. p_bFromHex - A pointer to a caller-allocated BOOL that receives TRUE
  2398. when the return value was decoded from the <xx> syntax.
  2399. Return Value:
  2400. The decoded character; *p_bFromHex identifies if the return value was
  2401. a literal or was a hex-encoded character.
  2402. --*/
  2403. MBCHAR
  2404. GetNextRuleCharA (
  2405. IN OUT PCSTR *PtrToRule,
  2406. OUT BOOL *FromHex
  2407. )
  2408. {
  2409. MBCHAR ch;
  2410. MBCHAR Value;
  2411. INT i;
  2412. PCSTR StartPtr;
  2413. StartPtr = *PtrToRule;
  2414. if (FromHex) {
  2415. *FromHex = FALSE;
  2416. }
  2417. if (_mbsnextc (StartPtr) == '~') {
  2418. *PtrToRule += 1;
  2419. Value = 0;
  2420. i = 0;
  2421. for (i = 0 ; **PtrToRule && i < 8 ; i++) {
  2422. ch = _mbsnextc (*PtrToRule);
  2423. *PtrToRule += 1;
  2424. if (ch == '~') {
  2425. if (FromHex) {
  2426. *FromHex = TRUE;
  2427. }
  2428. return Value;
  2429. }
  2430. Value *= 16;
  2431. if (ch >= '0' && ch <= '9') {
  2432. Value += ch - '0';
  2433. } else if (ch >= 'a' && ch <= 'f') {
  2434. Value += ch - 'a' + 10;
  2435. } else if (ch >= 'A' && ch <= 'F') {
  2436. Value += ch - 'A' + 10;
  2437. } else {
  2438. break;
  2439. }
  2440. }
  2441. DEBUGMSGA ((DBG_WHOOPS, "Bad formatting in encoded string %s", StartPtr));
  2442. }
  2443. *PtrToRule = _mbsinc (StartPtr);
  2444. return _mbsnextc (StartPtr);
  2445. }
  2446. WCHAR
  2447. GetNextRuleCharW (
  2448. IN OUT PCWSTR *PtrToRule,
  2449. OUT BOOL *FromHex
  2450. )
  2451. {
  2452. WCHAR ch;
  2453. WCHAR Value;
  2454. INT i;
  2455. PCWSTR StartPtr;
  2456. StartPtr = *PtrToRule;
  2457. if (FromHex) {
  2458. *FromHex = FALSE;
  2459. }
  2460. if (*StartPtr == L'~') {
  2461. *PtrToRule += 1;
  2462. Value = 0;
  2463. i = 0;
  2464. for (i = 0 ; **PtrToRule && i < 8 ; i++) {
  2465. ch = **PtrToRule;
  2466. *PtrToRule += 1;
  2467. if (ch == L'~') {
  2468. if (FromHex) {
  2469. *FromHex = TRUE;
  2470. }
  2471. return Value;
  2472. }
  2473. Value *= 16;
  2474. if (ch >= L'0' && ch <= L'9') {
  2475. Value += ch - L'0';
  2476. } else if (ch >= L'a' && ch <= L'f') {
  2477. Value += ch - L'a' + 10;
  2478. } else if (ch >= L'A' && ch <= L'F') {
  2479. Value += ch - L'A' + 10;
  2480. } else {
  2481. break;
  2482. }
  2483. }
  2484. DEBUGMSGW ((DBG_WHOOPS, "Bad formatting in encoded string %s", StartPtr));
  2485. }
  2486. *PtrToRule = StartPtr + 1;
  2487. return *StartPtr;
  2488. }
  2489. /*++
  2490. Routine Description:
  2491. DecodeRuleChars takes a complete rule string (szRule), possibly
  2492. encoded with hex-specified character values (~xx~). The output
  2493. string contains unencoded characters.
  2494. Arguments:
  2495. szRule - A caller-allocated buffer, big enough to hold an
  2496. unencoded rule. szRule can be equal to szEncRule.
  2497. szEncRule - The string holding a possibly encoded string.
  2498. Return Value:
  2499. Equal to szRule.
  2500. --*/
  2501. PSTR
  2502. DecodeRuleCharsA (PSTR mbstrRule, PCSTR mbstrEncRule)
  2503. {
  2504. MBCHAR c;
  2505. PSTR mbstrOrgRule;
  2506. mbstrOrgRule = mbstrRule;
  2507. //
  2508. // Copy string, converting ~xx~ to a single char
  2509. //
  2510. do {
  2511. c = GetNextRuleCharA (&mbstrEncRule, NULL);
  2512. *mbstrRule = (CHAR) c;
  2513. mbstrRule++; // MBCS->incomplete char will be finished in next loop iteration
  2514. } while (c);
  2515. return mbstrOrgRule;
  2516. }
  2517. PWSTR
  2518. DecodeRuleCharsW (PWSTR wstrRule, PCWSTR wstrEncRule)
  2519. {
  2520. WCHAR c;
  2521. PWSTR wstrOrgRule;
  2522. wstrOrgRule = wstrRule;
  2523. //
  2524. // Copy string, converting ~xx~ to a single char
  2525. //
  2526. do {
  2527. c = GetNextRuleCharW (&wstrEncRule, NULL);
  2528. *wstrRule = c;
  2529. wstrRule++;
  2530. } while (c);
  2531. return wstrOrgRule;
  2532. }
  2533. PSTR
  2534. DecodeRuleCharsABA (PSTR mbstrRule, PCSTR mbstrEncRule, PCSTR End)
  2535. {
  2536. MBCHAR c;
  2537. PSTR mbstrOrgRule;
  2538. mbstrOrgRule = mbstrRule;
  2539. //
  2540. // Copy string, converting ~xx~ to a single char
  2541. //
  2542. while (mbstrEncRule < End) {
  2543. c = GetNextRuleCharA (&mbstrEncRule, NULL);
  2544. *mbstrRule = (CHAR) c;
  2545. mbstrRule++; // MBCS->incomplete char will be finished in next loop iteration
  2546. }
  2547. *mbstrRule = 0;
  2548. return mbstrOrgRule;
  2549. }
  2550. PWSTR
  2551. DecodeRuleCharsABW (PWSTR wstrRule, PCWSTR wstrEncRule, PCWSTR End)
  2552. {
  2553. WCHAR c;
  2554. PWSTR wstrOrgRule;
  2555. wstrOrgRule = wstrRule;
  2556. //
  2557. // Copy string, converting ~xx~ to a single char
  2558. //
  2559. while (wstrEncRule < End) {
  2560. c = GetNextRuleCharW (&wstrEncRule, NULL);
  2561. *wstrRule = c;
  2562. wstrRule++;
  2563. }
  2564. *wstrRule = 0;
  2565. return wstrOrgRule;
  2566. }
  2567. /*++
  2568. Routine Description:
  2569. EncodeRuleChars takes an unencoded rule string (szRule), and
  2570. converts it to a string possibly encoded with hex-specified
  2571. character values (~xx~). The output string contains encoded
  2572. characters.
  2573. Arguments:
  2574. szEncRule - A caller-allocated buffer, big enough to hold an
  2575. encoded rule. szEncRule CAN NOT be equal to szRule.
  2576. One way to calculate a max buffer size for szEncRule
  2577. is to use the following code:
  2578. allocsize = SizeOfString (szRule) * 6;
  2579. In the worst case, each character in szRule will take
  2580. six single-byte characters in szEncRule. In the normal
  2581. case, szEncRule will only be a few bytes bigger than
  2582. szRule.
  2583. szRule - The string holding an unencoded string.
  2584. Return Value:
  2585. Equal to szEncRule.
  2586. --*/
  2587. PSTR
  2588. EncodeRuleCharsExA (
  2589. PSTR mbstrEncRule,
  2590. PCSTR mbstrRule,
  2591. PCSTR mbstrEncChars OPTIONAL
  2592. )
  2593. {
  2594. PSTR mbstrOrgRule;
  2595. static CHAR mbstrExclusions[] = "[]<>\'*$|:?\";,%";
  2596. MBCHAR c;
  2597. if (!mbstrEncChars) {
  2598. mbstrEncChars = mbstrExclusions;
  2599. }
  2600. mbstrOrgRule = mbstrEncRule;
  2601. while (*mbstrRule) {
  2602. c = _mbsnextc (mbstrRule);
  2603. if (!_ismbcprint (c) || _mbschr (mbstrEncChars, c)) {
  2604. // Escape unprintable or excluded character
  2605. wsprintfA (mbstrEncRule, "~%X~", c);
  2606. mbstrEncRule = GetEndOfStringA (mbstrEncRule);
  2607. mbstrRule = _mbsinc (mbstrRule);
  2608. }
  2609. else {
  2610. // Copy multibyte character
  2611. if (IsLeadByte (mbstrRule)) {
  2612. *mbstrEncRule = *mbstrRule;
  2613. mbstrEncRule++;
  2614. mbstrRule++;
  2615. }
  2616. *mbstrEncRule = *mbstrRule;
  2617. mbstrEncRule++;
  2618. mbstrRule++;
  2619. }
  2620. }
  2621. *mbstrEncRule = 0; //lint !e613
  2622. return mbstrOrgRule;
  2623. }
  2624. PWSTR
  2625. EncodeRuleCharsExW (
  2626. PWSTR wstrEncRule,
  2627. PCWSTR wstrRule,
  2628. PCWSTR wstrEncChars OPTIONAL
  2629. )
  2630. {
  2631. PWSTR wstrOrgRule;
  2632. static WCHAR wstrExclusions[] = L"[]<>\'*$|:?\";,%";
  2633. WCHAR c;
  2634. if (!wstrEncChars) {
  2635. wstrEncChars = wstrExclusions;
  2636. }
  2637. wstrOrgRule = wstrEncRule;
  2638. while (c = *wstrRule) { //lint !e720
  2639. if (!iswprint (c) || wcschr (wstrEncChars, c)) {
  2640. wsprintfW (wstrEncRule, L"~%X~", c);
  2641. wstrEncRule = GetEndOfStringW (wstrEncRule);
  2642. }
  2643. else {
  2644. *wstrEncRule = *wstrRule;
  2645. wstrEncRule++;
  2646. }
  2647. wstrRule++;
  2648. }
  2649. *wstrEncRule = 0;
  2650. return wstrOrgRule;
  2651. }
  2652. /*++
  2653. Routine Description:
  2654. _tcsisprint is a string version of _istprint.
  2655. Arguments:
  2656. szStr - A pointer to the string to examine
  2657. Return Value:
  2658. Non-zero if szStr is made up only of printable characters.
  2659. --*/
  2660. int
  2661. _mbsisprint (PCSTR mbstrStr)
  2662. {
  2663. while (*mbstrStr && _ismbcprint ((MBCHAR) _mbsnextc (mbstrStr))) {
  2664. mbstrStr = _mbsinc (mbstrStr);
  2665. }
  2666. return *mbstrStr == 0;
  2667. }
  2668. int
  2669. _wcsisprint (PCWSTR wstrStr)
  2670. {
  2671. while (*wstrStr && iswprint (*wstrStr)) {
  2672. wstrStr++;
  2673. }
  2674. return *wstrStr == 0;
  2675. }
  2676. /*++
  2677. Routine Description:
  2678. SkipSpace returns a pointer to the next position within a string
  2679. that does not have whitespace characters. It uses the C
  2680. runtime isspace to determine what a whitespace character is.
  2681. Arguments:
  2682. szStr - A pointer to the string to examine
  2683. Return Value:
  2684. A pointer to the first non-whitespace character in the string,
  2685. or NULL if the string is made up of all whitespace characters
  2686. or the string is empty.
  2687. --*/
  2688. PCSTR
  2689. SkipSpaceA (PCSTR mbstrStr)
  2690. {
  2691. while (_ismbcspace ((MBCHAR) _mbsnextc (mbstrStr)))
  2692. mbstrStr = _mbsinc (mbstrStr);
  2693. return mbstrStr;
  2694. }
  2695. PCWSTR
  2696. SkipSpaceW (PCWSTR wstrStr)
  2697. {
  2698. while (iswspace (*wstrStr))
  2699. wstrStr++;
  2700. return wstrStr;
  2701. }
  2702. /*++
  2703. Routine Description:
  2704. SkipSpaceR returns a pointer to the next position within a string
  2705. that does not have whitespace characters. It uses the C
  2706. runtime isspace to determine what a whitespace character is.
  2707. This function is identical to SkipSpace except it works from
  2708. right to left instead of left to right.
  2709. Arguments:
  2710. StrBase - A pointer to the first character in the string
  2711. Str - A pointer to the end of the string, or NULL if the
  2712. end is not known.
  2713. Return Value:
  2714. A pointer to the first non-whitespace character in the string,
  2715. as viewed from right to left, or NULL if the string is made up
  2716. of all whitespace characters or the string is empty.
  2717. --*/
  2718. PCSTR
  2719. SkipSpaceRA (
  2720. IN PCSTR StrBase,
  2721. IN PCSTR Str OPTIONAL
  2722. )
  2723. {
  2724. if (!Str) {
  2725. Str = GetEndOfStringA (StrBase);
  2726. }
  2727. if (*Str == 0) { //lint !e613
  2728. Str = _mbsdec2 (StrBase, Str);
  2729. if (!Str) {
  2730. return NULL;
  2731. }
  2732. }
  2733. do {
  2734. if (!_ismbcspace((MBCHAR) _mbsnextc(Str))) {
  2735. return Str;
  2736. }
  2737. } while (Str = _mbsdec2(StrBase, Str)); //lint !e720
  2738. return NULL;
  2739. }
  2740. PCWSTR
  2741. SkipSpaceRW (
  2742. IN PCWSTR StrBase,
  2743. IN PCWSTR Str OPTIONAL
  2744. )
  2745. {
  2746. if (!Str) {
  2747. Str = GetEndOfStringW (StrBase);
  2748. }
  2749. if (*Str == 0) {
  2750. Str--;
  2751. if (Str < StrBase) {
  2752. return NULL;
  2753. }
  2754. }
  2755. do {
  2756. if (!iswspace(*Str)) {
  2757. return Str;
  2758. }
  2759. } while (Str-- != StrBase);
  2760. return NULL;
  2761. }
  2762. /*++
  2763. Routine Description:
  2764. TruncateTrailingSpace trims the specified string after the
  2765. very last non-space character, or empties the string if it
  2766. contains only space characters. This routine uses isspace
  2767. to determine what a space is.
  2768. Arguments:
  2769. Str - Specifies string to process
  2770. Return Value:
  2771. none
  2772. --*/
  2773. VOID
  2774. TruncateTrailingSpaceA (
  2775. IN OUT PSTR Str
  2776. )
  2777. {
  2778. PSTR LastNonSpace;
  2779. PSTR OrgStr;
  2780. OrgStr = Str;
  2781. LastNonSpace = NULL;
  2782. while (*Str) {
  2783. if (!_ismbcspace ((MBCHAR) _mbsnextc (Str))) {
  2784. LastNonSpace = Str;
  2785. }
  2786. Str = _mbsinc (Str);
  2787. }
  2788. if (LastNonSpace) {
  2789. *_mbsinc (LastNonSpace) = 0;
  2790. } else {
  2791. *OrgStr = 0;
  2792. }
  2793. }
  2794. VOID
  2795. TruncateTrailingSpaceW (
  2796. IN OUT PWSTR Str
  2797. )
  2798. {
  2799. PWSTR LastNonSpace;
  2800. PWSTR OrgStr;
  2801. OrgStr = Str;
  2802. LastNonSpace = NULL;
  2803. while (*Str) {
  2804. if (!iswspace (*Str)) {
  2805. LastNonSpace = Str;
  2806. }
  2807. Str++;
  2808. }
  2809. if (LastNonSpace) {
  2810. *(LastNonSpace + 1) = 0;
  2811. } else {
  2812. *OrgStr = 0;
  2813. }
  2814. }
  2815. /*++
  2816. Routine Description:
  2817. IsPatternMatch compares a string against a pattern that may contain
  2818. standard * or ? wildcards.
  2819. Arguments:
  2820. wstrPattern - A pattern possibly containing wildcards
  2821. wstrStr - The string to compare against the pattern
  2822. Return Value:
  2823. TRUE when wstrStr and wstrPattern match when wildcards are expanded.
  2824. FALSE if wstrStr does not match wstrPattern.
  2825. --*/
  2826. BOOL
  2827. IsPatternMatchA (
  2828. IN PCSTR strPattern,
  2829. IN PCSTR strStr
  2830. )
  2831. {
  2832. MBCHAR chSrc, chPat;
  2833. while (*strStr) {
  2834. chSrc = OURTOLOWER ((MBCHAR) _mbsnextc (strStr));
  2835. chPat = OURTOLOWER ((MBCHAR) _mbsnextc (strPattern));
  2836. if (chPat == '*') {
  2837. // Skip all asterisks that are grouped together
  2838. while (_mbsnextc (_mbsinc (strStr)) == '*') {
  2839. strStr = _mbsinc (strStr);
  2840. }
  2841. // Check if asterisk is at the end. If so, we have a match already.
  2842. if (!_mbsnextc (_mbsinc (strPattern))) {
  2843. return TRUE;
  2844. }
  2845. // do recursive check for rest of pattern
  2846. if (IsPatternMatchA (_mbsinc (strPattern), strStr)) {
  2847. return TRUE;
  2848. }
  2849. // Allow any character and continue
  2850. strStr = _mbsinc (strStr);
  2851. continue;
  2852. }
  2853. if (chPat != '?') {
  2854. if (chSrc != chPat) {
  2855. return FALSE;
  2856. }
  2857. }
  2858. strStr = _mbsinc (strStr);
  2859. strPattern = _mbsinc (strPattern);
  2860. }
  2861. //
  2862. // Fail when there is more pattern and pattern does not end in an asterisk
  2863. //
  2864. while (_mbsnextc (strPattern) == '*') {
  2865. strPattern = _mbsinc (strPattern);
  2866. }
  2867. if (_mbsnextc (strPattern)) {
  2868. return FALSE;
  2869. }
  2870. return TRUE;
  2871. }
  2872. BOOL
  2873. IsPatternMatchW (
  2874. IN PCWSTR wstrPattern,
  2875. IN PCWSTR wstrStr
  2876. )
  2877. {
  2878. WCHAR chSrc, chPat;
  2879. while (*wstrStr) {
  2880. chSrc = towlower (*wstrStr);
  2881. chPat = towlower (*wstrPattern);
  2882. if (chPat == L'*') {
  2883. // Skip all asterisks that are grouped together
  2884. while (wstrPattern[1] == L'*')
  2885. wstrPattern++;
  2886. // Check if asterisk is at the end. If so, we have a match already.
  2887. chPat = towlower (wstrPattern[1]);
  2888. if (!chPat)
  2889. return TRUE;
  2890. // Otherwise check if next pattern char matches current char
  2891. if (chPat == chSrc || chPat == L'?') {
  2892. // do recursive check for rest of pattern
  2893. wstrPattern++;
  2894. if (IsPatternMatchW (wstrPattern, wstrStr))
  2895. return TRUE;
  2896. // no, that didn't work, stick with star
  2897. wstrPattern--;
  2898. }
  2899. //
  2900. // Allow any character and continue
  2901. //
  2902. wstrStr++;
  2903. continue;
  2904. }
  2905. if (chPat != L'?') {
  2906. //
  2907. // if next pattern character is not a question mark, src and pat
  2908. // must be identical.
  2909. //
  2910. if (chSrc != chPat)
  2911. return FALSE;
  2912. }
  2913. //
  2914. // Advance when pattern character matches string character
  2915. //
  2916. wstrPattern++;
  2917. wstrStr++;
  2918. }
  2919. //
  2920. // Fail when there is more pattern and pattern does not end in an asterisk
  2921. //
  2922. chPat = *wstrPattern;
  2923. if (chPat && (chPat != L'*' || wstrPattern[1]))
  2924. return FALSE;
  2925. return TRUE;
  2926. }
  2927. BOOL
  2928. IsPatternContainedA (
  2929. IN PCSTR Container,
  2930. IN PCSTR Contained
  2931. )
  2932. {
  2933. MBCHAR chSrc, chPat;
  2934. while (*Contained) {
  2935. chSrc = OURTOLOWER ((MBCHAR) _mbsnextc (Contained));
  2936. chPat = OURTOLOWER ((MBCHAR) _mbsnextc (Container));
  2937. if (chPat == '*') {
  2938. // Skip all asterisks that are grouped together
  2939. while (_mbsnextc (_mbsinc (Container)) == '*') {
  2940. Container = _mbsinc (Container);
  2941. }
  2942. // Check if asterisk is at the end. If so, we have a match already.
  2943. if (!_mbsnextc (_mbsinc (Container))) {
  2944. return TRUE;
  2945. }
  2946. // do recursive check for rest of pattern
  2947. if (IsPatternContainedA (_mbsinc (Container), Contained)) {
  2948. return TRUE;
  2949. }
  2950. // Allow any character and continue
  2951. Contained = _mbsinc (Contained);
  2952. continue;
  2953. } else if (chPat == '?') {
  2954. if (chSrc == '*') {
  2955. return FALSE;
  2956. }
  2957. } else {
  2958. if (chSrc != chPat) {
  2959. return FALSE;
  2960. }
  2961. }
  2962. Contained = _mbsinc (Contained);
  2963. Container = _mbsinc (Container);
  2964. }
  2965. //
  2966. // Fail when there is more pattern and pattern does not end in an asterisk
  2967. //
  2968. while (_mbsnextc (Container) == '*') {
  2969. Container = _mbsinc (Container);
  2970. }
  2971. if (_mbsnextc (Container)) {
  2972. return FALSE;
  2973. }
  2974. return TRUE;
  2975. }
  2976. BOOL
  2977. IsPatternContainedW (
  2978. IN PCWSTR Container,
  2979. IN PCWSTR Contained
  2980. )
  2981. {
  2982. while (*Contained) {
  2983. if (*Container == L'*') {
  2984. // Skip all asterisks that are grouped together
  2985. while (Container[1] == L'*') {
  2986. Container++;
  2987. }
  2988. // Check if asterisk is at the end. If so, we have a match already.
  2989. if (!Container[1]) {
  2990. return TRUE;
  2991. }
  2992. // do recursive check for rest of pattern
  2993. if (IsPatternContainedW (Container + 1, Contained)) {
  2994. return TRUE;
  2995. }
  2996. // Allow any character and continue
  2997. Contained++;
  2998. continue;
  2999. } else if (*Container == L'?') {
  3000. if (*Contained == L'*') {
  3001. return FALSE;
  3002. }
  3003. } else {
  3004. if (*Container != *Contained) {
  3005. return FALSE;
  3006. }
  3007. }
  3008. Contained++;
  3009. Container++;
  3010. }
  3011. //
  3012. // Fail when there is more pattern and pattern does not end in an asterisk
  3013. //
  3014. while (*Container == '*') {
  3015. Container++;
  3016. }
  3017. if (*Container) {
  3018. return FALSE;
  3019. }
  3020. return TRUE;
  3021. }
  3022. /*++
  3023. Routine Description:
  3024. IsPatternMatchAB compares a string against a pattern that may contain
  3025. standard * or ? wildcards. It only processes the string up to the
  3026. specified end.
  3027. Arguments:
  3028. Pattern - A pattern possibly containing wildcards
  3029. Start - The string to compare against the pattern
  3030. End - Specifies the end of Start
  3031. Return Value:
  3032. TRUE when the string between Start and End matches Pattern when wildcards are expanded.
  3033. FALSE if the pattern does not match.
  3034. --*/
  3035. BOOL
  3036. IsPatternMatchABA (
  3037. IN PCSTR Pattern,
  3038. IN PCSTR Start,
  3039. IN PCSTR End
  3040. )
  3041. {
  3042. MBCHAR chSrc, chPat;
  3043. while (*Start && Start < End) {
  3044. chSrc = OURTOLOWER ((MBCHAR) _mbsnextc (Start));
  3045. chPat = OURTOLOWER ((MBCHAR) _mbsnextc (Pattern));
  3046. if (chPat == '*') {
  3047. // Skip all asterisks that are grouped together
  3048. while (_mbsnextc (_mbsinc (Start)) == '*') {
  3049. Start = _mbsinc (Start);
  3050. }
  3051. // Check if asterisk is at the end. If so, we have a match already.
  3052. if (!_mbsnextc (_mbsinc (Pattern))) {
  3053. return TRUE;
  3054. }
  3055. // do recursive check for rest of pattern
  3056. if (IsPatternMatchABA (_mbsinc (Pattern), Start, End)) {
  3057. return TRUE;
  3058. }
  3059. // Allow any character and continue
  3060. Start = _mbsinc (Start);
  3061. continue;
  3062. }
  3063. if (chPat != '?') {
  3064. if (chSrc != chPat) {
  3065. return FALSE;
  3066. }
  3067. }
  3068. Start = _mbsinc (Start);
  3069. Pattern = _mbsinc (Pattern);
  3070. }
  3071. //
  3072. // Fail when there is more pattern and pattern does not end in an asterisk
  3073. //
  3074. while (_mbsnextc (Pattern) == '*') {
  3075. Pattern = _mbsinc (Pattern);
  3076. }
  3077. if (_mbsnextc (Pattern)) {
  3078. return FALSE;
  3079. }
  3080. return TRUE;
  3081. }
  3082. BOOL
  3083. IsPatternMatchABW (
  3084. IN PCWSTR Pattern,
  3085. IN PCWSTR Start,
  3086. IN PCWSTR End
  3087. )
  3088. {
  3089. WCHAR chSrc, chPat;
  3090. while (*Start && Start < End) {
  3091. chSrc = towlower (*Start);
  3092. chPat = towlower (*Pattern);
  3093. if (chPat == L'*') {
  3094. // Skip all asterisks that are grouped together
  3095. while (Pattern[1] == L'*') {
  3096. Pattern++;
  3097. }
  3098. // Check if asterisk is at the end. If so, we have a match already.
  3099. chPat = towlower (Pattern[1]);
  3100. if (!chPat) {
  3101. return TRUE;
  3102. }
  3103. // Otherwise check if next pattern char matches current char
  3104. if (chPat == chSrc || chPat == L'?') {
  3105. // do recursive check for rest of pattern
  3106. Pattern++;
  3107. if (IsPatternMatchABW (Pattern, Start, End)) {
  3108. return TRUE;
  3109. }
  3110. // no, that didn't work, stick with star
  3111. Pattern--;
  3112. }
  3113. //
  3114. // Allow any character and continue
  3115. //
  3116. Start++;
  3117. continue;
  3118. }
  3119. if (chPat != L'?') {
  3120. //
  3121. // if next pattern character is not a question mark, src and pat
  3122. // must be identical.
  3123. //
  3124. if (chSrc != chPat) {
  3125. return FALSE;
  3126. }
  3127. }
  3128. //
  3129. // Advance when pattern character matches string character
  3130. //
  3131. Pattern++;
  3132. Start++;
  3133. }
  3134. //
  3135. // Fail when there is more pattern and pattern does not end in an asterisk
  3136. //
  3137. chPat = *Pattern;
  3138. if (chPat && (chPat != L'*' || Pattern[1])) {
  3139. return FALSE;
  3140. }
  3141. return TRUE;
  3142. }
  3143. /*++
  3144. Routine Description:
  3145. IsPatternMatchEx compares a string against a pattern that may contain
  3146. any of the following expressions:
  3147. * - Specifies zero or more characters
  3148. ? - Specifies any one character
  3149. *[set] - Specifies zero or more characters in set
  3150. ?[set] - Specifies any one character in set
  3151. *[n:set] - Specifies zero to n characters in set
  3152. ?[n:set] - Specifies exactly n characters in set
  3153. *[!(set)] - Specifies zero or more characters not in set
  3154. ?[!(set)] - Specifies one character not in set
  3155. *[n:!(set)] - Specifies zero to n characters not in set
  3156. ?[n:!(set)] - Specifies exactly n characters not in set
  3157. *[set1,!(set2)] - Specifies zero or more characters in set1 and
  3158. not in set2. It is assumed that set1 and set2
  3159. overlap.
  3160. ?[set1,!(set2)] - Specifies one character in set1 and not in set2.
  3161. *[n:set1,!(set2)] - Specifies zero to n characters in set1 and not
  3162. in set 2.
  3163. ?[n:set1,!(set2)] - Specifies exactly n characters in set1 and not
  3164. in set 2.
  3165. set, set1 and set2 are specified as follows:
  3166. a - Specifies a single character
  3167. a-b - Specifies a character range
  3168. a,b - Specifies two characters
  3169. a-b,c-d - Specifies two character ranges
  3170. a,b-c - Specifies a single character and a character range
  3171. etc...
  3172. Patterns can be joined by surrounding the entire expression in
  3173. greater than/less than braces.
  3174. Because of the syntax characters, the following characters must be
  3175. escaped by preceeding the character with a caret (^):
  3176. ^? ^[ ^- ^< ^! ^^
  3177. ^* ^] ^: ^> ^,
  3178. Here are some examples:
  3179. To specify any GUID:
  3180. {?[8:0-9,a-f]-?[4:0-9,a-f]-?[4:0-9,a-f]-?[4:0-9,a-f]-?[12:0-9,a-f]}
  3181. To specify a 32-bit hexadecimal number:
  3182. <0x*[8:0-9,a-f]><0*[7:0-9,a-f]h><?[1-9]*[7:0-9,a-f]h>
  3183. Arguments:
  3184. Pattern - A pattern possibly containing wildcards
  3185. Start - The string to compare against the pattern
  3186. End - Specifies the end of Start
  3187. Return Value:
  3188. TRUE when the string between Start and End matches Pattern when wildcards are expanded.
  3189. FALSE if the pattern does not match.
  3190. --*/
  3191. BOOL
  3192. IsPatternMatchExA (
  3193. IN PCSTR Pattern,
  3194. IN PCSTR String
  3195. )
  3196. {
  3197. PPARSEDPATTERNA Handle;
  3198. BOOL b;
  3199. Handle = CreateParsedPatternA (Pattern);
  3200. if (!Handle) {
  3201. return FALSE;
  3202. }
  3203. b = TestParsedPatternA (Handle, String);
  3204. DestroyParsedPatternA (Handle);
  3205. return b;
  3206. }
  3207. BOOL
  3208. IsPatternMatchExW (
  3209. IN PCWSTR Pattern,
  3210. IN PCWSTR String
  3211. )
  3212. {
  3213. PPARSEDPATTERNW Handle;
  3214. BOOL b;
  3215. Handle = CreateParsedPatternW (Pattern);
  3216. if (!Handle) {
  3217. return FALSE;
  3218. }
  3219. b = TestParsedPatternW (Handle, String);
  3220. DestroyParsedPatternW (Handle);
  3221. return b;
  3222. }
  3223. /*++
  3224. Routine Description:
  3225. IsPatternMatchExAB compares a string against a pattern that may contain
  3226. any of the following expressions:
  3227. * - Specifies zero or more characters
  3228. ? - Specifies any one character
  3229. *[set] - Specifies zero or more characters in set
  3230. ?[set] - Specifies any one character in set
  3231. *[n:set] - Specifies zero to n characters in set
  3232. ?[n:set] - Specifies exactly n characters in set
  3233. *[!(set)] - Specifies zero or more characters not in set
  3234. ?[!(set)] - Specifies one character not in set
  3235. *[n:!(set)] - Specifies zero to n characters not in set
  3236. ?[n:!(set)] - Specifies exactly n characters not in set
  3237. *[set1,!(set2)] - Specifies zero or more characters in set1 and
  3238. not in set2. It is assumed that set1 and set2
  3239. overlap.
  3240. ?[set1,!(set2)] - Specifies one character in set1 and not in set2.
  3241. *[n:set1,!(set2)] - Specifies zero to n characters in set1 and not
  3242. in set 2.
  3243. ?[n:set1,!(set2)] - Specifies exactly n characters in set1 and not
  3244. in set 2.
  3245. set, set1 and set2 are specified as follows:
  3246. a - Specifies a single character
  3247. a-b - Specifies a character range
  3248. a,b - Specifies two characters
  3249. a-b,c-d - Specifies two character ranges
  3250. a,b-c - Specifies a single character and a character range
  3251. etc...
  3252. Patterns can be joined by surrounding the entire expression in
  3253. greater than/less than braces.
  3254. Because of the syntax characters, the following characters must be
  3255. escaped by preceeding the character with a caret (^):
  3256. ^? ^[ ^- ^< ^! ^^
  3257. ^* ^] ^: ^> ^,
  3258. Here are some examples:
  3259. To specify any GUID:
  3260. {?[8:0-9,a-f]-?[4:0-9,a-f]-?[4:0-9,a-f]-?[4:0-9,a-f]-?[12:0-9,a-f]}
  3261. To specify a 32-bit hexadecimal number:
  3262. <0x*[8:0-9,a-f]><0*[7:0-9,a-f]h><?[1-9]*[7:0-9,a-f]h>
  3263. Arguments:
  3264. Pattern - A pattern possibly containing wildcards
  3265. Start - The string to compare against the pattern
  3266. End - Specifies the end of Start
  3267. Return Value:
  3268. TRUE when the string between Start and End matches Pattern when wildcards are expanded.
  3269. FALSE if the pattern does not match.
  3270. --*/
  3271. BOOL
  3272. IsPatternMatchExABA (
  3273. IN PCSTR Pattern,
  3274. IN PCSTR Start,
  3275. IN PCSTR End
  3276. )
  3277. {
  3278. PPARSEDPATTERNA Handle;
  3279. BOOL b;
  3280. Handle = CreateParsedPatternA (Pattern);
  3281. if (!Handle) {
  3282. return FALSE;
  3283. }
  3284. b = TestParsedPatternABA (Handle, Start, End);
  3285. DestroyParsedPatternA (Handle);
  3286. return b;
  3287. }
  3288. BOOL
  3289. IsPatternMatchExABW (
  3290. IN PCWSTR Pattern,
  3291. IN PCWSTR Start,
  3292. IN PCWSTR End
  3293. )
  3294. {
  3295. PPARSEDPATTERNW Handle;
  3296. BOOL b;
  3297. Handle = CreateParsedPatternW (Pattern);
  3298. if (!Handle) {
  3299. return FALSE;
  3300. }
  3301. b = TestParsedPatternABW (Handle, Start, End);
  3302. DestroyParsedPatternW (Handle);
  3303. return b;
  3304. }
  3305. BOOL
  3306. pTestSetsA (
  3307. IN PCSTR Container,
  3308. IN PCSTR Contained,
  3309. IN BOOL ExcludeMode
  3310. )
  3311. {
  3312. MBCHAR ch;
  3313. if (ExcludeMode) {
  3314. if (!Contained) {
  3315. return TRUE;
  3316. }
  3317. if (!Container) {
  3318. return FALSE;
  3319. }
  3320. } else {
  3321. if (!Container) {
  3322. return TRUE;
  3323. }
  3324. if (!Contained) {
  3325. return FALSE;
  3326. }
  3327. }
  3328. while (*Contained) {
  3329. ch = _mbsnextc (Contained);
  3330. if (!pTestSetA (ch, Container, NULL)) {
  3331. return FALSE;
  3332. }
  3333. Contained = _mbsinc (Contained);
  3334. }
  3335. return TRUE;
  3336. }
  3337. BOOL
  3338. pTestSetsW (
  3339. IN PCWSTR Container,
  3340. IN PCWSTR Contained,
  3341. IN BOOL ExcludeMode
  3342. )
  3343. {
  3344. if (ExcludeMode) {
  3345. if (!Contained) {
  3346. return TRUE;
  3347. }
  3348. if (!Container) {
  3349. return FALSE;
  3350. }
  3351. } else {
  3352. if (!Container) {
  3353. return TRUE;
  3354. }
  3355. if (!Contained) {
  3356. return FALSE;
  3357. }
  3358. }
  3359. while (*Contained) {
  3360. if (!pTestSetW (*Contained, Container, NULL)) {
  3361. return FALSE;
  3362. }
  3363. Contained ++;
  3364. }
  3365. return TRUE;
  3366. }
  3367. BOOL
  3368. pMatchSegmentA (
  3369. IN PSEGMENTA Source,
  3370. IN PSEGMENTA Destination
  3371. )
  3372. {
  3373. switch (Source->Type) {
  3374. case SEGMENTTYPE_OPTIONAL:
  3375. switch (Destination->Type) {
  3376. case SEGMENTTYPE_OPTIONAL:
  3377. if (Source->Wildcard.MaxLen) {
  3378. if ((Destination->Wildcard.MaxLen == 0) ||
  3379. (Source->Wildcard.MaxLen < Destination->Wildcard.MaxLen)
  3380. ) {
  3381. return FALSE;
  3382. }
  3383. }
  3384. if (!pTestSetsA (
  3385. Source->Wildcard.IncludeSet,
  3386. Destination->Wildcard.IncludeSet,
  3387. FALSE
  3388. )) {
  3389. return FALSE;
  3390. }
  3391. if (!pTestSetsA (
  3392. Destination->Wildcard.ExcludeSet,
  3393. Source->Wildcard.ExcludeSet,
  3394. TRUE
  3395. )) {
  3396. return FALSE;
  3397. }
  3398. return TRUE;
  3399. case SEGMENTTYPE_REQUIRED:
  3400. if (Source->Wildcard.MaxLen) {
  3401. if (Source->Wildcard.MaxLen < Destination->Wildcard.MaxLen) {
  3402. return FALSE;
  3403. }
  3404. }
  3405. if (!pTestSetsA (
  3406. Source->Wildcard.IncludeSet,
  3407. Destination->Wildcard.IncludeSet,
  3408. FALSE
  3409. )) {
  3410. return FALSE;
  3411. }
  3412. if (!pTestSetsA (
  3413. Destination->Wildcard.ExcludeSet,
  3414. Source->Wildcard.ExcludeSet,
  3415. TRUE
  3416. )) {
  3417. return FALSE;
  3418. }
  3419. return TRUE;
  3420. case SEGMENTTYPE_EXACTMATCH:
  3421. if (!pTestSetA (
  3422. _mbsnextc (Destination->Exact.LowerCasePhrase),
  3423. Source->Wildcard.IncludeSet,
  3424. Source->Wildcard.ExcludeSet
  3425. )) {
  3426. return FALSE;
  3427. }
  3428. return TRUE;
  3429. default:
  3430. return FALSE;
  3431. }
  3432. break;
  3433. case SEGMENTTYPE_REQUIRED:
  3434. switch (Destination->Type) {
  3435. case SEGMENTTYPE_OPTIONAL:
  3436. return FALSE;
  3437. case SEGMENTTYPE_REQUIRED:
  3438. if (!pTestSetsA (
  3439. Source->Wildcard.IncludeSet,
  3440. Destination->Wildcard.IncludeSet,
  3441. FALSE
  3442. )) {
  3443. return FALSE;
  3444. }
  3445. if (!pTestSetsA (
  3446. Destination->Wildcard.ExcludeSet,
  3447. Source->Wildcard.ExcludeSet,
  3448. TRUE
  3449. )) {
  3450. return FALSE;
  3451. }
  3452. return TRUE;
  3453. case SEGMENTTYPE_EXACTMATCH:
  3454. if (!pTestSetA (
  3455. _mbsnextc (Destination->Exact.LowerCasePhrase),
  3456. Source->Wildcard.IncludeSet,
  3457. Source->Wildcard.ExcludeSet
  3458. )) {
  3459. return FALSE;
  3460. }
  3461. return TRUE;
  3462. default:
  3463. return FALSE;
  3464. }
  3465. break;
  3466. case SEGMENTTYPE_EXACTMATCH:
  3467. switch (Destination->Type) {
  3468. case SEGMENTTYPE_OPTIONAL:
  3469. return FALSE;
  3470. case SEGMENTTYPE_REQUIRED:
  3471. return FALSE;
  3472. case SEGMENTTYPE_EXACTMATCH:
  3473. if (_mbsnextc (Destination->Exact.LowerCasePhrase) != _mbsnextc (Source->Exact.LowerCasePhrase)) {
  3474. return FALSE;
  3475. }
  3476. return TRUE;
  3477. default:
  3478. return FALSE;
  3479. }
  3480. break;
  3481. default:
  3482. return FALSE;
  3483. }
  3484. }
  3485. BOOL
  3486. pMatchSegmentW (
  3487. IN PSEGMENTW Source,
  3488. IN PSEGMENTW Destination
  3489. )
  3490. {
  3491. switch (Source->Type) {
  3492. case SEGMENTTYPE_OPTIONAL:
  3493. switch (Destination->Type) {
  3494. case SEGMENTTYPE_OPTIONAL:
  3495. if (Source->Wildcard.MaxLen) {
  3496. if ((Destination->Wildcard.MaxLen == 0) ||
  3497. (Source->Wildcard.MaxLen < Destination->Wildcard.MaxLen)
  3498. ) {
  3499. return FALSE;
  3500. }
  3501. }
  3502. if (!pTestSetsW (
  3503. Source->Wildcard.IncludeSet,
  3504. Destination->Wildcard.IncludeSet,
  3505. FALSE
  3506. )) {
  3507. return FALSE;
  3508. }
  3509. if (!pTestSetsW (
  3510. Destination->Wildcard.ExcludeSet,
  3511. Source->Wildcard.ExcludeSet,
  3512. TRUE
  3513. )) {
  3514. return FALSE;
  3515. }
  3516. return TRUE;
  3517. case SEGMENTTYPE_REQUIRED:
  3518. if (Source->Wildcard.MaxLen) {
  3519. if (Source->Wildcard.MaxLen < Destination->Wildcard.MaxLen) {
  3520. return FALSE;
  3521. }
  3522. }
  3523. if (!pTestSetsW (
  3524. Source->Wildcard.IncludeSet,
  3525. Destination->Wildcard.IncludeSet,
  3526. FALSE
  3527. )) {
  3528. return FALSE;
  3529. }
  3530. if (!pTestSetsW (
  3531. Destination->Wildcard.ExcludeSet,
  3532. Source->Wildcard.ExcludeSet,
  3533. TRUE
  3534. )) {
  3535. return FALSE;
  3536. }
  3537. return TRUE;
  3538. case SEGMENTTYPE_EXACTMATCH:
  3539. if (!pTestSetW (
  3540. *Destination->Exact.LowerCasePhrase,
  3541. Source->Wildcard.IncludeSet,
  3542. Source->Wildcard.ExcludeSet
  3543. )) {
  3544. return FALSE;
  3545. }
  3546. return TRUE;
  3547. default:
  3548. return FALSE;
  3549. }
  3550. break;
  3551. case SEGMENTTYPE_REQUIRED:
  3552. switch (Destination->Type) {
  3553. case SEGMENTTYPE_OPTIONAL:
  3554. return FALSE;
  3555. case SEGMENTTYPE_REQUIRED:
  3556. if (!pTestSetsW (
  3557. Source->Wildcard.IncludeSet,
  3558. Destination->Wildcard.IncludeSet,
  3559. FALSE
  3560. )) {
  3561. return FALSE;
  3562. }
  3563. if (!pTestSetsW (
  3564. Destination->Wildcard.ExcludeSet,
  3565. Source->Wildcard.ExcludeSet,
  3566. TRUE
  3567. )) {
  3568. return FALSE;
  3569. }
  3570. return TRUE;
  3571. case SEGMENTTYPE_EXACTMATCH:
  3572. if (!pTestSetW (
  3573. *Destination->Exact.LowerCasePhrase,
  3574. Source->Wildcard.IncludeSet,
  3575. Source->Wildcard.ExcludeSet
  3576. )) {
  3577. return FALSE;
  3578. }
  3579. return TRUE;
  3580. default:
  3581. return FALSE;
  3582. }
  3583. break;
  3584. case SEGMENTTYPE_EXACTMATCH:
  3585. switch (Destination->Type) {
  3586. case SEGMENTTYPE_OPTIONAL:
  3587. return FALSE;
  3588. case SEGMENTTYPE_REQUIRED:
  3589. return FALSE;
  3590. case SEGMENTTYPE_EXACTMATCH:
  3591. if (*Destination->Exact.LowerCasePhrase != *Source->Exact.LowerCasePhrase) {
  3592. return FALSE;
  3593. }
  3594. return TRUE;
  3595. default:
  3596. return FALSE;
  3597. }
  3598. break;
  3599. default:
  3600. return FALSE;
  3601. }
  3602. }
  3603. BOOL
  3604. pIsOneParsedPatternContainedA (
  3605. IN PPATTERNPROPSA Container,
  3606. IN UINT StartContainer,
  3607. IN PPATTERNPROPSA Contained,
  3608. IN UINT StartContained,
  3609. IN BOOL SkipDotWithStar
  3610. )
  3611. {
  3612. UINT indexContainer = StartContainer;
  3613. UINT indexContained = StartContained;
  3614. PSEGMENTA containerSeg, containedSeg;
  3615. if (StartContainer == Container->SegmentCount) {
  3616. return FALSE;
  3617. }
  3618. while (indexContained < Contained->SegmentCount) {
  3619. containerSeg = &Container->Segment [indexContainer];
  3620. containedSeg = &Contained->Segment [indexContained];
  3621. if (containerSeg->Type == SEGMENTTYPE_OPTIONAL) {
  3622. // see if we can match contained segment
  3623. if (!pMatchSegmentA (containerSeg, containedSeg)) {
  3624. indexContainer ++;
  3625. if (indexContainer == Container->SegmentCount) {
  3626. return FALSE;
  3627. }
  3628. continue;
  3629. }
  3630. if (pIsOneParsedPatternContainedA (
  3631. Container,
  3632. indexContainer + 1,
  3633. Contained,
  3634. indexContained,
  3635. SkipDotWithStar
  3636. )) {
  3637. return TRUE;
  3638. }
  3639. indexContained ++;
  3640. continue;
  3641. } else if (containerSeg->Type == SEGMENTTYPE_REQUIRED) {
  3642. if (!pMatchSegmentA (containerSeg, containedSeg)) {
  3643. return FALSE;
  3644. }
  3645. } else {
  3646. if (!pMatchSegmentA (containerSeg, containedSeg)) {
  3647. return FALSE;
  3648. }
  3649. }
  3650. indexContainer ++;
  3651. indexContained ++;
  3652. }
  3653. //
  3654. // Fail when there is more pattern and pattern does not end in an asterisk
  3655. //
  3656. while (indexContainer < Container->SegmentCount) {
  3657. containerSeg = &Container->Segment [indexContainer];
  3658. if (containerSeg->Type != SEGMENTTYPE_OPTIONAL) {
  3659. if (SkipDotWithStar) {
  3660. // we allow one dot to be able to match *.* with files without extensions
  3661. if (containerSeg->Type == SEGMENTTYPE_EXACTMATCH) {
  3662. if (!pTestSetA (
  3663. _mbsnextc (containerSeg->Exact.LowerCasePhrase),
  3664. "..",
  3665. NULL
  3666. )) {
  3667. return FALSE;
  3668. } else {
  3669. // only one dot allowed
  3670. SkipDotWithStar = FALSE;
  3671. }
  3672. } else {
  3673. return FALSE;
  3674. }
  3675. } else {
  3676. return FALSE;
  3677. }
  3678. }
  3679. indexContainer ++;
  3680. }
  3681. return TRUE;
  3682. }
  3683. BOOL
  3684. pIsOneParsedPatternContainedW (
  3685. IN PPATTERNPROPSW Container,
  3686. IN UINT StartContainer,
  3687. IN PPATTERNPROPSW Contained,
  3688. IN UINT StartContained,
  3689. IN BOOL SkipDotWithStar
  3690. )
  3691. {
  3692. UINT indexContainer = StartContainer;
  3693. UINT indexContained = StartContained;
  3694. PSEGMENTW containerSeg, containedSeg;
  3695. if (StartContainer == Container->SegmentCount) {
  3696. return FALSE;
  3697. }
  3698. while (indexContained < Contained->SegmentCount) {
  3699. containerSeg = &Container->Segment [indexContainer];
  3700. containedSeg = &Contained->Segment [indexContained];
  3701. if (containerSeg->Type == SEGMENTTYPE_OPTIONAL) {
  3702. // see if we can match contained segment
  3703. if (!pMatchSegmentW (containerSeg, containedSeg)) {
  3704. indexContainer ++;
  3705. if (indexContainer == Container->SegmentCount) {
  3706. return FALSE;
  3707. }
  3708. continue;
  3709. }
  3710. if (pIsOneParsedPatternContainedW (
  3711. Container,
  3712. indexContainer + 1,
  3713. Contained,
  3714. indexContained,
  3715. SkipDotWithStar
  3716. )) {
  3717. return TRUE;
  3718. }
  3719. indexContained ++;
  3720. continue;
  3721. } else if (containerSeg->Type == SEGMENTTYPE_REQUIRED) {
  3722. if (!pMatchSegmentW (containerSeg, containedSeg)) {
  3723. return FALSE;
  3724. }
  3725. } else {
  3726. if (!pMatchSegmentW (containerSeg, containedSeg)) {
  3727. return FALSE;
  3728. }
  3729. }
  3730. indexContainer ++;
  3731. indexContained ++;
  3732. }
  3733. //
  3734. // Fail when there is more pattern and pattern does not end in an asterisk
  3735. //
  3736. while (indexContainer < Container->SegmentCount) {
  3737. containerSeg = &Container->Segment [indexContainer];
  3738. if (containerSeg->Type != SEGMENTTYPE_OPTIONAL) {
  3739. if (SkipDotWithStar) {
  3740. // we allow one dot to be able to match *.* with files without extensions
  3741. if (containerSeg->Type == SEGMENTTYPE_EXACTMATCH) {
  3742. if (!pTestSetW (
  3743. *containerSeg->Exact.LowerCasePhrase,
  3744. L"..",
  3745. NULL
  3746. )) {
  3747. return FALSE;
  3748. } else {
  3749. // only one dot allowed
  3750. SkipDotWithStar = FALSE;
  3751. }
  3752. } else {
  3753. return FALSE;
  3754. }
  3755. } else {
  3756. return FALSE;
  3757. }
  3758. }
  3759. indexContainer ++;
  3760. }
  3761. return TRUE;
  3762. }
  3763. BOOL
  3764. IsExplodedParsedPatternContainedExA (
  3765. IN PPARSEDPATTERNA Container,
  3766. IN PPARSEDPATTERNA Contained,
  3767. IN BOOL SkipDotWithStar
  3768. )
  3769. {
  3770. UINT u1, u2;
  3771. BOOL b = FALSE;
  3772. for (u1 = 0 ; u1 < Contained->PatternCount ; u1++) {
  3773. b = FALSE;
  3774. for (u2 = 0 ; u2 < Container->PatternCount ; u2++) {
  3775. b = pIsOneParsedPatternContainedA (
  3776. &Container->Pattern[u2],
  3777. 0,
  3778. &Contained->Pattern[u1],
  3779. 0,
  3780. SkipDotWithStar
  3781. );
  3782. if (b) break;
  3783. }
  3784. if (!b) {
  3785. return FALSE;
  3786. }
  3787. }
  3788. return TRUE;
  3789. }
  3790. BOOL
  3791. IsExplodedParsedPatternContainedExW (
  3792. IN PPARSEDPATTERNW Container,
  3793. IN PPARSEDPATTERNW Contained,
  3794. IN BOOL SkipDotWithStar
  3795. )
  3796. {
  3797. UINT u1, u2;
  3798. BOOL b = FALSE;
  3799. for (u1 = 0 ; u1 < Contained->PatternCount ; u1++) {
  3800. b = FALSE;
  3801. for (u2 = 0 ; u2 < Container->PatternCount ; u2++) {
  3802. b = pIsOneParsedPatternContainedW (
  3803. &Container->Pattern[u2],
  3804. 0,
  3805. &Contained->Pattern[u1],
  3806. 0,
  3807. SkipDotWithStar
  3808. );
  3809. if (b) break;
  3810. }
  3811. if (!b) {
  3812. return FALSE;
  3813. }
  3814. }
  3815. return TRUE;
  3816. }
  3817. BOOL
  3818. pDoOneParsedPatternIntersectA (
  3819. IN PPATTERNPROPSA Pat1,
  3820. IN UINT StartPat1,
  3821. IN PPATTERNPROPSA Pat2,
  3822. IN UINT StartPat2,
  3823. IN BOOL IgnoreWackAtEnd
  3824. )
  3825. {
  3826. UINT indexPat1 = StartPat1;
  3827. UINT indexPat2 = StartPat2;
  3828. PSEGMENTA pat1Seg, pat2Seg;
  3829. while ((indexPat1 < Pat1->SegmentCount) && (indexPat2 < Pat2->SegmentCount)) {
  3830. pat1Seg = &Pat1->Segment [indexPat1];
  3831. pat2Seg = &Pat2->Segment [indexPat2];
  3832. if (pat1Seg->Type == SEGMENTTYPE_OPTIONAL) {
  3833. // see if we can match contained segment
  3834. if (!pMatchSegmentA (pat1Seg, pat2Seg)) {
  3835. indexPat1 ++;
  3836. continue;
  3837. }
  3838. if (pDoOneParsedPatternIntersectA (
  3839. Pat1,
  3840. indexPat1 + 1,
  3841. Pat2,
  3842. indexPat2,
  3843. IgnoreWackAtEnd
  3844. )) {
  3845. return TRUE;
  3846. }
  3847. indexPat2 ++;
  3848. continue;
  3849. }
  3850. if (pat2Seg->Type == SEGMENTTYPE_OPTIONAL) {
  3851. // see if we can match contained segment
  3852. if (!pMatchSegmentA (pat2Seg, pat1Seg)) {
  3853. indexPat2 ++;
  3854. continue;
  3855. }
  3856. if (pDoOneParsedPatternIntersectA (
  3857. Pat1,
  3858. indexPat1,
  3859. Pat2,
  3860. indexPat2 + 1,
  3861. IgnoreWackAtEnd
  3862. )) {
  3863. return TRUE;
  3864. }
  3865. indexPat1 ++;
  3866. continue;
  3867. }
  3868. if (pat1Seg->Type == SEGMENTTYPE_REQUIRED) {
  3869. if (!pMatchSegmentA (pat1Seg, pat2Seg)) {
  3870. return FALSE;
  3871. }
  3872. indexPat1 ++;
  3873. indexPat2 ++;
  3874. continue;
  3875. }
  3876. if (pat2Seg->Type == SEGMENTTYPE_REQUIRED) {
  3877. if (!pMatchSegmentA (pat2Seg, pat1Seg)) {
  3878. return FALSE;
  3879. }
  3880. indexPat1 ++;
  3881. indexPat2 ++;
  3882. continue;
  3883. }
  3884. if (!pMatchSegmentA (pat1Seg, pat2Seg)) {
  3885. return FALSE;
  3886. }
  3887. indexPat1 ++;
  3888. indexPat2 ++;
  3889. }
  3890. //
  3891. // Fail when there is more pattern and pattern does not end in an asterisk
  3892. //
  3893. if ((indexPat1 < Pat1->SegmentCount) && IgnoreWackAtEnd) {
  3894. pat1Seg = &Pat1->Segment [indexPat1];
  3895. if ((pat1Seg->Type == SEGMENTTYPE_EXACTMATCH) &&
  3896. (StringMatchA (pat1Seg->Exact.LowerCasePhrase, "\\"))
  3897. ) {
  3898. indexPat1 ++;
  3899. }
  3900. }
  3901. while (indexPat1 < Pat1->SegmentCount) {
  3902. pat1Seg = &Pat1->Segment [indexPat1];
  3903. if (pat1Seg->Type != SEGMENTTYPE_OPTIONAL) {
  3904. return FALSE;
  3905. }
  3906. indexPat1 ++;
  3907. }
  3908. if ((indexPat2 < Pat2->SegmentCount) && IgnoreWackAtEnd) {
  3909. pat2Seg = &Pat2->Segment [indexPat2];
  3910. if ((pat2Seg->Type == SEGMENTTYPE_EXACTMATCH) &&
  3911. (StringMatchA (pat2Seg->Exact.LowerCasePhrase, "\\"))
  3912. ) {
  3913. indexPat2 ++;
  3914. }
  3915. }
  3916. while (indexPat2 < Pat2->SegmentCount) {
  3917. pat2Seg = &Pat2->Segment [indexPat2];
  3918. if (pat2Seg->Type != SEGMENTTYPE_OPTIONAL) {
  3919. return FALSE;
  3920. }
  3921. indexPat2 ++;
  3922. }
  3923. return TRUE;
  3924. }
  3925. BOOL
  3926. pDoOneParsedPatternIntersectW (
  3927. IN PPATTERNPROPSW Pat1,
  3928. IN UINT StartPat1,
  3929. IN PPATTERNPROPSW Pat2,
  3930. IN UINT StartPat2,
  3931. IN BOOL IgnoreWackAtEnd
  3932. )
  3933. {
  3934. UINT indexPat1 = StartPat1;
  3935. UINT indexPat2 = StartPat2;
  3936. PSEGMENTW pat1Seg, pat2Seg;
  3937. while ((indexPat1 < Pat1->SegmentCount) && (indexPat2 < Pat2->SegmentCount)) {
  3938. pat1Seg = &Pat1->Segment [indexPat1];
  3939. pat2Seg = &Pat2->Segment [indexPat2];
  3940. if (pat1Seg->Type == SEGMENTTYPE_OPTIONAL) {
  3941. // see if we can match contained segment
  3942. if (!pMatchSegmentW (pat1Seg, pat2Seg)) {
  3943. indexPat1 ++;
  3944. continue;
  3945. }
  3946. if (pDoOneParsedPatternIntersectW (
  3947. Pat1,
  3948. indexPat1 + 1,
  3949. Pat2,
  3950. indexPat2,
  3951. IgnoreWackAtEnd
  3952. )) {
  3953. return TRUE;
  3954. }
  3955. indexPat2 ++;
  3956. continue;
  3957. }
  3958. if (pat2Seg->Type == SEGMENTTYPE_OPTIONAL) {
  3959. // see if we can match contained segment
  3960. if (!pMatchSegmentW (pat2Seg, pat1Seg)) {
  3961. indexPat2 ++;
  3962. continue;
  3963. }
  3964. if (pDoOneParsedPatternIntersectW (
  3965. Pat1,
  3966. indexPat1,
  3967. Pat2,
  3968. indexPat2 + 1,
  3969. IgnoreWackAtEnd
  3970. )) {
  3971. return TRUE;
  3972. }
  3973. indexPat1 ++;
  3974. continue;
  3975. }
  3976. if (pat1Seg->Type == SEGMENTTYPE_REQUIRED) {
  3977. if (!pMatchSegmentW (pat1Seg, pat2Seg)) {
  3978. return FALSE;
  3979. }
  3980. indexPat1 ++;
  3981. indexPat2 ++;
  3982. continue;
  3983. }
  3984. if (pat2Seg->Type == SEGMENTTYPE_REQUIRED) {
  3985. if (!pMatchSegmentW (pat2Seg, pat1Seg)) {
  3986. return FALSE;
  3987. }
  3988. indexPat1 ++;
  3989. indexPat2 ++;
  3990. continue;
  3991. }
  3992. if (!pMatchSegmentW (pat1Seg, pat2Seg)) {
  3993. return FALSE;
  3994. }
  3995. indexPat1 ++;
  3996. indexPat2 ++;
  3997. }
  3998. //
  3999. // Fail when there is more pattern and pattern does not end in an asterisk
  4000. //
  4001. if ((indexPat1 < Pat1->SegmentCount) && IgnoreWackAtEnd) {
  4002. pat1Seg = &Pat1->Segment [indexPat1];
  4003. if ((pat1Seg->Type == SEGMENTTYPE_EXACTMATCH) &&
  4004. (StringMatchW (pat1Seg->Exact.LowerCasePhrase, L"\\"))
  4005. ) {
  4006. indexPat1 ++;
  4007. }
  4008. }
  4009. while (indexPat1 < Pat1->SegmentCount) {
  4010. pat1Seg = &Pat1->Segment [indexPat1];
  4011. if (pat1Seg->Type != SEGMENTTYPE_OPTIONAL) {
  4012. return FALSE;
  4013. }
  4014. indexPat1 ++;
  4015. }
  4016. if ((indexPat2 < Pat2->SegmentCount) && IgnoreWackAtEnd) {
  4017. pat2Seg = &Pat2->Segment [indexPat2];
  4018. if ((pat2Seg->Type == SEGMENTTYPE_EXACTMATCH) &&
  4019. (StringMatchW (pat2Seg->Exact.LowerCasePhrase, L"\\"))
  4020. ) {
  4021. indexPat2 ++;
  4022. }
  4023. }
  4024. while (indexPat2 < Pat2->SegmentCount) {
  4025. pat2Seg = &Pat2->Segment [indexPat2];
  4026. if (pat2Seg->Type != SEGMENTTYPE_OPTIONAL) {
  4027. return FALSE;
  4028. }
  4029. indexPat2 ++;
  4030. }
  4031. return TRUE;
  4032. }
  4033. BOOL
  4034. DoExplodedParsedPatternsIntersectExA (
  4035. IN PPARSEDPATTERNA Pat1,
  4036. IN PPARSEDPATTERNA Pat2,
  4037. IN BOOL IgnoreWackAtEnd
  4038. )
  4039. {
  4040. UINT u1, u2;
  4041. BOOL b = FALSE;
  4042. for (u1 = 0 ; u1 < Pat2->PatternCount ; u1++) {
  4043. for (u2 = 0 ; u2 < Pat1->PatternCount ; u2++) {
  4044. b = pDoOneParsedPatternIntersectA (
  4045. &Pat1->Pattern[u2],
  4046. 0,
  4047. &Pat2->Pattern[u1],
  4048. 0,
  4049. IgnoreWackAtEnd
  4050. );
  4051. if (b) return TRUE;
  4052. b = pDoOneParsedPatternIntersectA (
  4053. &Pat2->Pattern[u1],
  4054. 0,
  4055. &Pat1->Pattern[u2],
  4056. 0,
  4057. IgnoreWackAtEnd
  4058. );
  4059. if (b) return TRUE;
  4060. }
  4061. }
  4062. return FALSE;
  4063. }
  4064. BOOL
  4065. DoExplodedParsedPatternsIntersectExW (
  4066. IN PPARSEDPATTERNW Pat1,
  4067. IN PPARSEDPATTERNW Pat2,
  4068. IN BOOL IgnoreWackAtEnd
  4069. )
  4070. {
  4071. UINT u1, u2;
  4072. BOOL b = FALSE;
  4073. for (u1 = 0 ; u1 < Pat2->PatternCount ; u1++) {
  4074. for (u2 = 0 ; u2 < Pat1->PatternCount ; u2++) {
  4075. b = pDoOneParsedPatternIntersectW (
  4076. &Pat1->Pattern[u2],
  4077. 0,
  4078. &Pat2->Pattern[u1],
  4079. 0,
  4080. IgnoreWackAtEnd
  4081. );
  4082. if (b) return TRUE;
  4083. b = pDoOneParsedPatternIntersectW (
  4084. &Pat2->Pattern[u1],
  4085. 0,
  4086. &Pat1->Pattern[u2],
  4087. 0,
  4088. IgnoreWackAtEnd
  4089. );
  4090. if (b) return TRUE;
  4091. }
  4092. }
  4093. return FALSE;
  4094. }
  4095. PPARSEDPATTERNA
  4096. ExplodeParsedPatternExA (
  4097. IN PMHANDLE Pool, OPTIONAL
  4098. IN PPARSEDPATTERNA Pattern
  4099. )
  4100. {
  4101. PMHANDLE pool;
  4102. BOOL externalPool = FALSE;
  4103. PPARSEDPATTERNA pattern;
  4104. PPATTERNPROPSA oldProps, newProps;
  4105. PSEGMENTA oldSeg, newSeg;
  4106. UINT i, j, k, newPropsSize, charCountTmp, oldSegIndex, byteIndex;
  4107. BOOL result = TRUE;
  4108. if (Pool) {
  4109. externalPool = TRUE;
  4110. pool = Pool;
  4111. } else {
  4112. pool = PmCreateNamedPoolEx ("Parsed Pattern", 512);
  4113. }
  4114. __try {
  4115. pattern = (PPARSEDPATTERNA) PmGetAlignedMemory (pool, sizeof (PARSEDPATTERNA));
  4116. ZeroMemory (pattern, sizeof (PARSEDPATTERNA));
  4117. pattern->PatternCount = Pattern->PatternCount;
  4118. pattern->Pool = pool;
  4119. pattern->ExternalPool = externalPool;
  4120. pattern->Pattern = (PPATTERNPROPSA) PmGetAlignedMemory (
  4121. pool,
  4122. pattern->PatternCount * sizeof (PATTERNPROPSA)
  4123. );
  4124. for (i=0; i<pattern->PatternCount; i++) {
  4125. oldProps = &Pattern->Pattern[i];
  4126. newProps = &pattern->Pattern[i];
  4127. ZeroMemory (newProps, sizeof (PATTERNPROPSA));
  4128. // now let's walk oldProps to see how many segments we are
  4129. // going to need
  4130. newPropsSize = 0;
  4131. for (j=0; j<oldProps->SegmentCount; j++) {
  4132. oldSeg = &oldProps->Segment[j];
  4133. switch (oldSeg->Type) {
  4134. case SEGMENTTYPE_EXACTMATCH:
  4135. charCountTmp = CharCountA (oldSeg->Exact.LowerCasePhrase);
  4136. newPropsSize += (charCountTmp?charCountTmp:1);
  4137. break;
  4138. case SEGMENTTYPE_REQUIRED:
  4139. newPropsSize += oldSeg->Wildcard.MaxLen;
  4140. break;
  4141. case SEGMENTTYPE_OPTIONAL:
  4142. if (oldSeg->Wildcard.MaxLen) {
  4143. newPropsSize += oldSeg->Wildcard.MaxLen;
  4144. } else {
  4145. newPropsSize ++;
  4146. }
  4147. break;
  4148. default:
  4149. result = FALSE;
  4150. __leave;
  4151. }
  4152. }
  4153. // now we allocate the required segments
  4154. newProps->SegmentCount = newPropsSize;
  4155. newProps->Segment = (PSEGMENTA) PmGetAlignedMemory (
  4156. pool,
  4157. newProps->SegmentCount * sizeof (SEGMENTA)
  4158. );
  4159. // now let's walk oldProps again and fill newProps segments.
  4160. k = 0;
  4161. newSeg = &newProps->Segment[k];
  4162. for (j=0; j<oldProps->SegmentCount; j++) {
  4163. oldSeg = &oldProps->Segment[j];
  4164. ZeroMemory (newSeg, sizeof (SEGMENTA));
  4165. switch (oldSeg->Type) {
  4166. case SEGMENTTYPE_EXACTMATCH:
  4167. oldSegIndex = CharCountA (oldSeg->Exact.LowerCasePhrase);
  4168. byteIndex = oldSeg->Exact.PhraseBytes;
  4169. if (!oldSegIndex) {
  4170. ZeroMemory (newSeg, sizeof (SEGMENTA));
  4171. newSeg->Type = oldSeg->Type;
  4172. newSeg->Exact.LowerCasePhrase = (PCSTR) PmGetAlignedMemory (
  4173. pool, sizeof(CHAR)
  4174. );
  4175. ((PSTR)newSeg->Exact.LowerCasePhrase) [0] = 0;
  4176. newSeg->Exact.PhraseBytes = 0;
  4177. } else {
  4178. while (oldSegIndex) {
  4179. ZeroMemory (newSeg, sizeof (SEGMENTA));
  4180. newSeg->Type = oldSeg->Type;
  4181. newSeg->Exact.LowerCasePhrase = (PCSTR) PmGetAlignedMemory (
  4182. pool, 3 * sizeof(CHAR)
  4183. );
  4184. if (IsLeadByte (&oldSeg->Exact.LowerCasePhrase [oldSeg->Exact.PhraseBytes - byteIndex])) {
  4185. ((PSTR)newSeg->Exact.LowerCasePhrase)[0] = oldSeg->Exact.LowerCasePhrase [oldSeg->Exact.PhraseBytes - byteIndex];
  4186. byteIndex --;
  4187. ((PSTR)newSeg->Exact.LowerCasePhrase)[1] = oldSeg->Exact.LowerCasePhrase [oldSeg->Exact.PhraseBytes - byteIndex];
  4188. byteIndex --;
  4189. ((PSTR)newSeg->Exact.LowerCasePhrase)[2] = 0;
  4190. newSeg->Exact.PhraseBytes = 2;
  4191. } else {
  4192. ((PSTR)newSeg->Exact.LowerCasePhrase)[0] = oldSeg->Exact.LowerCasePhrase [oldSeg->Exact.PhraseBytes - byteIndex];
  4193. byteIndex --;
  4194. ((PSTR)newSeg->Exact.LowerCasePhrase)[1] = 0;
  4195. newSeg->Exact.PhraseBytes = 1;
  4196. }
  4197. oldSegIndex --;
  4198. k++;
  4199. newSeg = &newProps->Segment[k];
  4200. }
  4201. }
  4202. break;
  4203. case SEGMENTTYPE_REQUIRED:
  4204. oldSegIndex = oldSeg->Wildcard.MaxLen;
  4205. while (oldSegIndex) {
  4206. ZeroMemory (newSeg, sizeof (SEGMENTA));
  4207. newSeg->Type = oldSeg->Type;
  4208. newSeg->Wildcard.MaxLen = 1;
  4209. if (oldSeg->Wildcard.IncludeSet) {
  4210. newSeg->Wildcard.IncludeSet = PmDuplicateStringA (pool, oldSeg->Wildcard.IncludeSet);
  4211. }
  4212. if (oldSeg->Wildcard.ExcludeSet) {
  4213. newSeg->Wildcard.ExcludeSet = PmDuplicateStringA (pool, oldSeg->Wildcard.ExcludeSet);
  4214. }
  4215. oldSegIndex --;
  4216. k++;
  4217. newSeg = &newProps->Segment[k];
  4218. }
  4219. break;
  4220. case SEGMENTTYPE_OPTIONAL:
  4221. if (oldSeg->Wildcard.MaxLen) {
  4222. oldSegIndex = oldSeg->Wildcard.MaxLen;
  4223. while (oldSegIndex) {
  4224. ZeroMemory (newSeg, sizeof (SEGMENTA));
  4225. newSeg->Type = oldSeg->Type;
  4226. newSeg->Wildcard.MaxLen = 1;
  4227. if (oldSeg->Wildcard.IncludeSet) {
  4228. newSeg->Wildcard.IncludeSet = PmDuplicateStringA (pool, oldSeg->Wildcard.IncludeSet);
  4229. }
  4230. if (oldSeg->Wildcard.ExcludeSet) {
  4231. newSeg->Wildcard.ExcludeSet = PmDuplicateStringA (pool, oldSeg->Wildcard.ExcludeSet);
  4232. }
  4233. oldSegIndex --;
  4234. k++;
  4235. newSeg = &newProps->Segment[k];
  4236. }
  4237. } else {
  4238. ZeroMemory (newSeg, sizeof (SEGMENTA));
  4239. newSeg->Type = oldSeg->Type;
  4240. newSeg->Wildcard.MaxLen = oldSeg->Wildcard.MaxLen;
  4241. if (oldSeg->Wildcard.IncludeSet) {
  4242. newSeg->Wildcard.IncludeSet = PmDuplicateStringA (pool, oldSeg->Wildcard.IncludeSet);
  4243. }
  4244. if (oldSeg->Wildcard.ExcludeSet) {
  4245. newSeg->Wildcard.ExcludeSet = PmDuplicateStringA (pool, oldSeg->Wildcard.ExcludeSet);
  4246. }
  4247. k++;
  4248. newSeg = &newProps->Segment[k];
  4249. }
  4250. break;
  4251. default:
  4252. result = FALSE;
  4253. __leave;
  4254. }
  4255. }
  4256. }
  4257. }
  4258. __finally {
  4259. if (!result) {
  4260. PmDestroyPool (pool);
  4261. pattern = NULL;
  4262. }
  4263. }
  4264. return pattern;
  4265. }
  4266. PPARSEDPATTERNW
  4267. ExplodeParsedPatternExW (
  4268. IN PMHANDLE Pool, OPTIONAL
  4269. IN PPARSEDPATTERNW Pattern
  4270. )
  4271. {
  4272. PMHANDLE pool;
  4273. BOOL externalPool = FALSE;
  4274. PPARSEDPATTERNW pattern;
  4275. PPATTERNPROPSW oldProps, newProps;
  4276. PSEGMENTW oldSeg, newSeg;
  4277. UINT i, j, k, newPropsSize, charCountTmp, oldSegIndex;
  4278. BOOL result = TRUE;
  4279. if (Pool) {
  4280. externalPool = TRUE;
  4281. pool = Pool;
  4282. } else {
  4283. pool = PmCreateNamedPoolEx ("Parsed Pattern", 512);
  4284. }
  4285. __try {
  4286. pattern = (PPARSEDPATTERNW) PmGetAlignedMemory (pool, sizeof (PARSEDPATTERNW));
  4287. ZeroMemory (pattern, sizeof (PARSEDPATTERNW));
  4288. pattern->PatternCount = Pattern->PatternCount;
  4289. pattern->Pool = pool;
  4290. pattern->ExternalPool = externalPool;
  4291. pattern->Pattern = (PPATTERNPROPSW) PmGetAlignedMemory (
  4292. pool,
  4293. pattern->PatternCount * sizeof (PATTERNPROPSW)
  4294. );
  4295. for (i=0; i<pattern->PatternCount; i++) {
  4296. oldProps = &Pattern->Pattern[i];
  4297. newProps = &pattern->Pattern[i];
  4298. ZeroMemory (newProps, sizeof (PATTERNPROPSW));
  4299. // now let's walk oldProps to see how many segments we are
  4300. // going to need
  4301. newPropsSize = 0;
  4302. for (j=0; j<oldProps->SegmentCount; j++) {
  4303. oldSeg = &oldProps->Segment[j];
  4304. switch (oldSeg->Type) {
  4305. case SEGMENTTYPE_EXACTMATCH:
  4306. charCountTmp = CharCountW (oldSeg->Exact.LowerCasePhrase);
  4307. newPropsSize += (charCountTmp?charCountTmp:1);
  4308. break;
  4309. case SEGMENTTYPE_REQUIRED:
  4310. newPropsSize += oldSeg->Wildcard.MaxLen;
  4311. break;
  4312. case SEGMENTTYPE_OPTIONAL:
  4313. if (oldSeg->Wildcard.MaxLen) {
  4314. newPropsSize += oldSeg->Wildcard.MaxLen;
  4315. } else {
  4316. newPropsSize ++;
  4317. }
  4318. break;
  4319. default:
  4320. result = FALSE;
  4321. __leave;
  4322. }
  4323. }
  4324. // now we allocate the required segments
  4325. newProps->SegmentCount = newPropsSize;
  4326. newProps->Segment = (PSEGMENTW) PmGetAlignedMemory (
  4327. pool,
  4328. newProps->SegmentCount * sizeof (SEGMENTW)
  4329. );
  4330. // now let's walk oldProps again and fill newProps segments.
  4331. k = 0;
  4332. newSeg = &newProps->Segment[k];
  4333. for (j=0; j<oldProps->SegmentCount; j++) {
  4334. oldSeg = &oldProps->Segment[j];
  4335. ZeroMemory (newSeg, sizeof (SEGMENTW));
  4336. switch (oldSeg->Type) {
  4337. case SEGMENTTYPE_EXACTMATCH:
  4338. oldSegIndex = CharCountW (oldSeg->Exact.LowerCasePhrase);
  4339. if (!oldSegIndex) {
  4340. ZeroMemory (newSeg, sizeof (SEGMENTA));
  4341. newSeg->Type = oldSeg->Type;
  4342. newSeg->Exact.LowerCasePhrase = (PCWSTR) PmGetAlignedMemory (
  4343. pool, sizeof(WCHAR)
  4344. );
  4345. ((PWSTR)newSeg->Exact.LowerCasePhrase) [0] = 0;
  4346. newSeg->Exact.PhraseBytes = 0;
  4347. } else {
  4348. while (oldSegIndex) {
  4349. ZeroMemory (newSeg, sizeof (SEGMENTW));
  4350. newSeg->Type = oldSeg->Type;
  4351. newSeg->Exact.LowerCasePhrase = (PCWSTR) PmGetAlignedMemory (
  4352. pool, 2 * sizeof(WCHAR)
  4353. );
  4354. ((PWSTR)newSeg->Exact.LowerCasePhrase)[0] = oldSeg->Exact.LowerCasePhrase [(oldSeg->Exact.PhraseBytes / sizeof(WCHAR)) - oldSegIndex];
  4355. ((PWSTR)newSeg->Exact.LowerCasePhrase)[1] = 0;
  4356. oldSegIndex --;
  4357. k++;
  4358. newSeg = &newProps->Segment[k];
  4359. }
  4360. }
  4361. break;
  4362. case SEGMENTTYPE_REQUIRED:
  4363. oldSegIndex = oldSeg->Wildcard.MaxLen;
  4364. while (oldSegIndex) {
  4365. ZeroMemory (newSeg, sizeof (SEGMENTW));
  4366. newSeg->Type = oldSeg->Type;
  4367. newSeg->Wildcard.MaxLen = 1;
  4368. if (oldSeg->Wildcard.IncludeSet) {
  4369. newSeg->Wildcard.IncludeSet = PmDuplicateStringW (pool, oldSeg->Wildcard.IncludeSet);
  4370. }
  4371. if (oldSeg->Wildcard.ExcludeSet) {
  4372. newSeg->Wildcard.ExcludeSet = PmDuplicateStringW (pool, oldSeg->Wildcard.ExcludeSet);
  4373. }
  4374. oldSegIndex --;
  4375. k++;
  4376. newSeg = &newProps->Segment[k];
  4377. }
  4378. break;
  4379. case SEGMENTTYPE_OPTIONAL:
  4380. if (oldSeg->Wildcard.MaxLen) {
  4381. oldSegIndex = oldSeg->Wildcard.MaxLen;
  4382. while (oldSegIndex) {
  4383. ZeroMemory (newSeg, sizeof (SEGMENTW));
  4384. newSeg->Type = oldSeg->Type;
  4385. newSeg->Wildcard.MaxLen = 1;
  4386. if (oldSeg->Wildcard.IncludeSet) {
  4387. newSeg->Wildcard.IncludeSet = PmDuplicateStringW (pool, oldSeg->Wildcard.IncludeSet);
  4388. }
  4389. if (oldSeg->Wildcard.ExcludeSet) {
  4390. newSeg->Wildcard.ExcludeSet = PmDuplicateStringW (pool, oldSeg->Wildcard.ExcludeSet);
  4391. }
  4392. oldSegIndex --;
  4393. k++;
  4394. newSeg = &newProps->Segment[k];
  4395. }
  4396. } else {
  4397. ZeroMemory (newSeg, sizeof (SEGMENTW));
  4398. newSeg->Type = oldSeg->Type;
  4399. newSeg->Wildcard.MaxLen = oldSeg->Wildcard.MaxLen;
  4400. if (oldSeg->Wildcard.IncludeSet) {
  4401. newSeg->Wildcard.IncludeSet = PmDuplicateStringW (pool, oldSeg->Wildcard.IncludeSet);
  4402. }
  4403. if (oldSeg->Wildcard.ExcludeSet) {
  4404. newSeg->Wildcard.ExcludeSet = PmDuplicateStringW (pool, oldSeg->Wildcard.ExcludeSet);
  4405. }
  4406. k++;
  4407. newSeg = &newProps->Segment[k];
  4408. }
  4409. break;
  4410. default:
  4411. result = FALSE;
  4412. __leave;
  4413. }
  4414. }
  4415. }
  4416. }
  4417. __finally {
  4418. if (!result) {
  4419. PmDestroyPool (pool);
  4420. pattern = NULL;
  4421. }
  4422. }
  4423. return pattern;
  4424. }
  4425. /*++
  4426. Routine Description:
  4427. IsPatternContainedEx compares two patterns to see if one of them is
  4428. included in the other. Both patterns may contain any of the following
  4429. expressions:
  4430. * - Specifies zero or more characters
  4431. ? - Specifies any one character
  4432. *[set] - Specifies zero or more characters in set
  4433. ?[set] - Specifies any one character in set
  4434. *[n:set] - Specifies zero to n characters in set
  4435. ?[n:set] - Specifies exactly n characters in set
  4436. *[!(set)] - Specifies zero or more characters not in set
  4437. ?[!(set)] - Specifies one character not in set
  4438. *[n:!(set)] - Specifies zero to n characters not in set
  4439. ?[n:!(set)] - Specifies exactly n characters not in set
  4440. *[set1,!(set2)] - Specifies zero or more characters in set1 and
  4441. not in set2. It is assumed that set1 and set2
  4442. overlap.
  4443. ?[set1,!(set2)] - Specifies one character in set1 and not in set2.
  4444. *[n:set1,!(set2)] - Specifies zero to n characters in set1 and not
  4445. in set 2.
  4446. ?[n:set1,!(set2)] - Specifies exactly n characters in set1 and not
  4447. in set 2.
  4448. set, set1 and set2 are specified as follows:
  4449. a - Specifies a single character
  4450. a-b - Specifies a character range
  4451. a,b - Specifies two characters
  4452. a-b,c-d - Specifies two character ranges
  4453. a,b-c - Specifies a single character and a character range
  4454. etc...
  4455. Patterns can be joined by surrounding the entire expression in
  4456. greater than/less than braces.
  4457. Because of the syntax characters, the following characters must be
  4458. escaped by preceeding the character with a caret (^):
  4459. ^? ^[ ^- ^< ^! ^^
  4460. ^* ^] ^: ^> ^,
  4461. Here are some examples:
  4462. To specify any GUID:
  4463. {?[8:0-9,a-f]-?[4:0-9,a-f]-?[4:0-9,a-f]-?[4:0-9,a-f]-?[12:0-9,a-f]}
  4464. To specify a 32-bit hexadecimal number:
  4465. <0x*[8:0-9,a-f]><0*[7:0-9,a-f]h><?[1-9]*[7:0-9,a-f]h>
  4466. Arguments:
  4467. Container - A container pattern possibly containing wildcards
  4468. Contained - A contained pattern possibly containing wildcards
  4469. Return Value:
  4470. TRUE when the second pattern is contained in the first one, FALSE if not.
  4471. --*/
  4472. BOOL
  4473. IsPatternContainedExA (
  4474. IN PCSTR Container,
  4475. IN PCSTR Contained
  4476. )
  4477. {
  4478. PPARSEDPATTERNA container = NULL, contained = NULL;
  4479. PPARSEDPATTERNA expContainer = NULL, expContained = NULL;
  4480. BOOL result = FALSE;
  4481. __try {
  4482. container = CreateParsedPatternA (Container);
  4483. if (!container) {
  4484. __leave;
  4485. }
  4486. expContainer = ExplodeParsedPatternA (container);
  4487. if (!expContainer) {
  4488. __leave;
  4489. }
  4490. contained = CreateParsedPatternA (Contained);
  4491. if (!contained) {
  4492. __leave;
  4493. }
  4494. expContained = ExplodeParsedPatternA (contained);
  4495. if (!expContained) {
  4496. __leave;
  4497. }
  4498. result = IsExplodedParsedPatternContainedExA (expContainer, expContained, FALSE);
  4499. }
  4500. __finally {
  4501. if (expContained) {
  4502. DestroyParsedPatternA (expContained);
  4503. }
  4504. if (contained) {
  4505. DestroyParsedPatternA (contained);
  4506. }
  4507. if (expContainer) {
  4508. DestroyParsedPatternA (expContainer);
  4509. }
  4510. if (container) {
  4511. DestroyParsedPatternA (container);
  4512. }
  4513. }
  4514. return result;
  4515. }
  4516. BOOL
  4517. IsPatternContainedExW (
  4518. IN PCWSTR Container,
  4519. IN PCWSTR Contained
  4520. )
  4521. {
  4522. PPARSEDPATTERNW container = NULL, contained = NULL;
  4523. PPARSEDPATTERNW expContainer = NULL, expContained = NULL;
  4524. BOOL result = FALSE;
  4525. __try {
  4526. container = CreateParsedPatternW (Container);
  4527. if (!container) {
  4528. __leave;
  4529. }
  4530. expContainer = ExplodeParsedPatternW (container);
  4531. if (!expContainer) {
  4532. __leave;
  4533. }
  4534. contained = CreateParsedPatternW (Contained);
  4535. if (!contained) {
  4536. __leave;
  4537. }
  4538. expContained = ExplodeParsedPatternW (contained);
  4539. if (!expContained) {
  4540. __leave;
  4541. }
  4542. result = IsExplodedParsedPatternContainedExW (expContainer, expContained, FALSE);
  4543. }
  4544. __finally {
  4545. if (expContained) {
  4546. DestroyParsedPatternW (expContained);
  4547. }
  4548. if (contained) {
  4549. DestroyParsedPatternW (contained);
  4550. }
  4551. if (expContainer) {
  4552. DestroyParsedPatternW (expContainer);
  4553. }
  4554. if (container) {
  4555. DestroyParsedPatternW (container);
  4556. }
  4557. }
  4558. return result;
  4559. }
  4560. BOOL
  4561. IsParsedPatternContainedExA (
  4562. IN PPARSEDPATTERNA Container,
  4563. IN PPARSEDPATTERNA Contained
  4564. )
  4565. {
  4566. PPARSEDPATTERNA expContainer = NULL, expContained = NULL;
  4567. BOOL result = FALSE;
  4568. __try {
  4569. expContainer = ExplodeParsedPatternA (Container);
  4570. if (!expContainer) {
  4571. __leave;
  4572. }
  4573. expContained = ExplodeParsedPatternA (Contained);
  4574. if (!expContained) {
  4575. __leave;
  4576. }
  4577. result = IsExplodedParsedPatternContainedExA (expContainer, expContained, FALSE);
  4578. }
  4579. __finally {
  4580. if (expContained) {
  4581. DestroyParsedPatternA (expContained);
  4582. }
  4583. if (expContainer) {
  4584. DestroyParsedPatternA (expContainer);
  4585. }
  4586. }
  4587. return result;
  4588. }
  4589. BOOL
  4590. IsParsedPatternContainedExW (
  4591. IN PPARSEDPATTERNW Container,
  4592. IN PPARSEDPATTERNW Contained
  4593. )
  4594. {
  4595. PPARSEDPATTERNW expContainer = NULL, expContained = NULL;
  4596. BOOL result = FALSE;
  4597. __try {
  4598. expContainer = ExplodeParsedPatternW (Container);
  4599. if (!expContainer) {
  4600. __leave;
  4601. }
  4602. expContained = ExplodeParsedPatternW (Contained);
  4603. if (!expContained) {
  4604. __leave;
  4605. }
  4606. result = IsExplodedParsedPatternContainedExW (expContainer, expContained, FALSE);
  4607. }
  4608. __finally {
  4609. if (expContained) {
  4610. DestroyParsedPatternW (expContained);
  4611. }
  4612. if (expContainer) {
  4613. DestroyParsedPatternW (expContainer);
  4614. }
  4615. }
  4616. return result;
  4617. }
  4618. /*++
  4619. Routine Description:
  4620. pAppendCharToGrowBuffer copies the first character in a caller specified
  4621. string into the specified grow buffer. This function is used to build up a
  4622. string inside a grow buffer, copying character by character.
  4623. Arguments:
  4624. buf - Specifies the grow buffer to add the character to, receives the
  4625. character in its buffer
  4626. PtrToChar - Specifies a pointer to the character to copy
  4627. Return Value:
  4628. None.
  4629. --*/
  4630. VOID
  4631. pAppendCharToGrowBufferA (
  4632. IN OUT PGROWBUFFER Buf,
  4633. IN PCSTR PtrToChar
  4634. )
  4635. {
  4636. PBYTE p;
  4637. UINT Len;
  4638. if (IsLeadByte (PtrToChar)) {
  4639. Len = 2;
  4640. } else {
  4641. Len = 1;
  4642. }
  4643. p = GbGrow (Buf, Len);
  4644. CopyMemory (p, PtrToChar, (SIZE_T) Len);
  4645. }
  4646. VOID
  4647. pAppendCharToGrowBufferW (
  4648. IN OUT PGROWBUFFER Buf,
  4649. IN PCWSTR PtrToChar
  4650. )
  4651. {
  4652. PBYTE p;
  4653. p = GbGrow (Buf, sizeof(WCHAR));
  4654. CopyMemory (p, PtrToChar, sizeof(WCHAR));
  4655. }
  4656. #define BASESTATE_BEGIN 0
  4657. #define BASESTATE_END 1
  4658. #define BASESTATE_ERROR 2
  4659. #define BASESTATE_BEGIN_COMPOUND 3
  4660. #define BASESTATE_END_COMPOUND 4
  4661. #define BASESTATE_EXAMINE_PATTERN 5
  4662. #define BASESTATE_SKIP_PATTERN 6
  4663. PCSTR
  4664. GetPatternBaseExA (
  4665. IN PCSTR Pattern,
  4666. IN BOOL NodePattern
  4667. )
  4668. {
  4669. GROWBUFFER resultBuf = INIT_GROWBUFFER;
  4670. UINT state;
  4671. UINT lastWackIdx = 0;
  4672. UINT firstCharIdx = 0;
  4673. BOOL compoundPattern = FALSE;
  4674. MBCHAR ch = 0;
  4675. PSTR result = NULL;
  4676. state = BASESTATE_BEGIN;
  4677. for (;;) {
  4678. switch (state) {
  4679. case BASESTATE_BEGIN:
  4680. if (_mbsnextc (Pattern) == '<') {
  4681. compoundPattern = TRUE;
  4682. state = BASESTATE_BEGIN_COMPOUND;
  4683. } else {
  4684. state = BASESTATE_EXAMINE_PATTERN;
  4685. }
  4686. break;
  4687. case BASESTATE_BEGIN_COMPOUND:
  4688. while (_ismbcspace ((MBCHAR)(_mbsnextc (Pattern)))) {
  4689. Pattern = _mbsinc (Pattern);
  4690. }
  4691. if (*Pattern == 0) {
  4692. state = BASESTATE_END;
  4693. break;
  4694. }
  4695. if (_mbsnextc (Pattern) == '<') {
  4696. pAppendCharToGrowBufferA (&resultBuf, Pattern);
  4697. Pattern = _mbsinc (Pattern);
  4698. state = BASESTATE_EXAMINE_PATTERN;
  4699. } else {
  4700. state = BASESTATE_ERROR;
  4701. }
  4702. break;
  4703. case BASESTATE_END_COMPOUND:
  4704. pAppendCharToGrowBufferA (&resultBuf, Pattern);
  4705. Pattern = _mbsinc (Pattern);
  4706. state = BASESTATE_BEGIN_COMPOUND;
  4707. break;
  4708. case BASESTATE_EXAMINE_PATTERN:
  4709. ch = _mbsnextc (Pattern);
  4710. if (ch == '>' && compoundPattern) {
  4711. state = BASESTATE_END_COMPOUND;
  4712. break;
  4713. }
  4714. if (ch == 0) {
  4715. if (compoundPattern) {
  4716. state = BASESTATE_ERROR;
  4717. break;
  4718. }
  4719. state = BASESTATE_END;
  4720. break;
  4721. }
  4722. if ((ch == '*') || (ch == '?')) {
  4723. if (NodePattern) {
  4724. if (resultBuf.Buf) {
  4725. ((PSTR)resultBuf.Buf) [lastWackIdx / sizeof (CHAR)] = 0;
  4726. }
  4727. resultBuf.End = lastWackIdx;
  4728. } else {
  4729. if (resultBuf.Buf) {
  4730. ((PSTR)resultBuf.Buf) [firstCharIdx / sizeof (CHAR)] = 0;
  4731. }
  4732. resultBuf.End = firstCharIdx;
  4733. firstCharIdx = 0;
  4734. }
  4735. state = BASESTATE_SKIP_PATTERN;
  4736. break;
  4737. }
  4738. if (!NodePattern && !firstCharIdx) {
  4739. firstCharIdx = resultBuf.End;
  4740. }
  4741. if (ch == '\\') {
  4742. if (NodePattern) {
  4743. lastWackIdx = resultBuf.End;
  4744. }
  4745. }
  4746. if (ch == '^') {
  4747. pAppendCharToGrowBufferA (&resultBuf, Pattern);
  4748. Pattern = _mbsinc (Pattern);
  4749. }
  4750. pAppendCharToGrowBufferA (&resultBuf, Pattern);
  4751. Pattern = _mbsinc (Pattern);
  4752. break;
  4753. case BASESTATE_SKIP_PATTERN:
  4754. ch = _mbsnextc (Pattern);
  4755. if (ch == '>' && compoundPattern) {
  4756. state = BASESTATE_END_COMPOUND;
  4757. break;
  4758. }
  4759. if (ch == 0) {
  4760. if (compoundPattern) {
  4761. state = BASESTATE_ERROR;
  4762. break;
  4763. }
  4764. state = BASESTATE_END;
  4765. break;
  4766. }
  4767. Pattern = _mbsinc (Pattern);
  4768. break;
  4769. }
  4770. if ((state == BASESTATE_END) || (state == BASESTATE_ERROR)) {
  4771. break;
  4772. }
  4773. }
  4774. if (state == BASESTATE_END) {
  4775. if (resultBuf.End) {
  4776. ((PSTR)resultBuf.Buf) [resultBuf.End / sizeof (CHAR)] = 0;
  4777. result = DuplicatePathStringA ((PCSTR)resultBuf.Buf, 0);
  4778. }
  4779. }
  4780. GbFree (&resultBuf);
  4781. return result;
  4782. }
  4783. PCWSTR
  4784. GetPatternBaseExW (
  4785. IN PCWSTR Pattern,
  4786. IN BOOL NodePattern
  4787. )
  4788. {
  4789. GROWBUFFER resultBuf = INIT_GROWBUFFER;
  4790. UINT state;
  4791. UINT lastWackIdx = 0;
  4792. UINT firstCharIdx = 0;
  4793. BOOL compoundPattern = FALSE;
  4794. WCHAR ch = 0;
  4795. PWSTR result = NULL;
  4796. state = BASESTATE_BEGIN;
  4797. for (;;) {
  4798. switch (state) {
  4799. case BASESTATE_BEGIN:
  4800. if (*Pattern == L'<') {
  4801. compoundPattern = TRUE;
  4802. state = BASESTATE_BEGIN_COMPOUND;
  4803. } else {
  4804. state = BASESTATE_EXAMINE_PATTERN;
  4805. }
  4806. break;
  4807. case BASESTATE_BEGIN_COMPOUND:
  4808. while (*Pattern == L' ') {
  4809. Pattern ++;
  4810. }
  4811. if (*Pattern == 0) {
  4812. state = BASESTATE_END;
  4813. break;
  4814. }
  4815. if (*Pattern == L'<') {
  4816. pAppendCharToGrowBufferW (&resultBuf, Pattern);
  4817. Pattern ++;
  4818. state = BASESTATE_EXAMINE_PATTERN;
  4819. } else {
  4820. state = BASESTATE_ERROR;
  4821. }
  4822. break;
  4823. case BASESTATE_END_COMPOUND:
  4824. pAppendCharToGrowBufferW (&resultBuf, Pattern);
  4825. Pattern ++;
  4826. state = BASESTATE_BEGIN_COMPOUND;
  4827. break;
  4828. case BASESTATE_EXAMINE_PATTERN:
  4829. ch = *Pattern;
  4830. if (ch == L'>' && compoundPattern) {
  4831. state = BASESTATE_END_COMPOUND;
  4832. break;
  4833. }
  4834. if (ch == 0) {
  4835. if (compoundPattern) {
  4836. state = BASESTATE_ERROR;
  4837. break;
  4838. }
  4839. state = BASESTATE_END;
  4840. break;
  4841. }
  4842. if ((ch == L'*') || (ch == L'?')) {
  4843. if (NodePattern) {
  4844. if (resultBuf.Buf) {
  4845. ((PWSTR)resultBuf.Buf) [lastWackIdx / sizeof (WCHAR)] = 0;
  4846. }
  4847. resultBuf.End = lastWackIdx;
  4848. } else {
  4849. if (resultBuf.Buf) {
  4850. ((PWSTR)resultBuf.Buf) [firstCharIdx / sizeof (WCHAR)] = 0;
  4851. }
  4852. resultBuf.End = firstCharIdx;
  4853. firstCharIdx = 0;
  4854. }
  4855. state = BASESTATE_SKIP_PATTERN;
  4856. break;
  4857. }
  4858. if (!NodePattern && !firstCharIdx) {
  4859. firstCharIdx = resultBuf.End;
  4860. }
  4861. if (ch == L'\\') {
  4862. if (NodePattern) {
  4863. lastWackIdx = resultBuf.End;
  4864. }
  4865. }
  4866. if (ch == L'^') {
  4867. pAppendCharToGrowBufferW (&resultBuf, Pattern);
  4868. Pattern ++;
  4869. }
  4870. pAppendCharToGrowBufferW (&resultBuf, Pattern);
  4871. Pattern ++;
  4872. break;
  4873. case BASESTATE_SKIP_PATTERN:
  4874. ch = *Pattern;
  4875. if (ch == L'>' && compoundPattern) {
  4876. state = BASESTATE_END_COMPOUND;
  4877. break;
  4878. }
  4879. if (ch == 0) {
  4880. if (compoundPattern) {
  4881. state = BASESTATE_ERROR;
  4882. break;
  4883. }
  4884. state = BASESTATE_END;
  4885. break;
  4886. }
  4887. Pattern ++;
  4888. break;
  4889. }
  4890. if ((state == BASESTATE_END) || (state == BASESTATE_ERROR)) {
  4891. break;
  4892. }
  4893. }
  4894. if (state == BASESTATE_END) {
  4895. if (resultBuf.End) {
  4896. ((PWSTR)resultBuf.Buf) [resultBuf.End / sizeof (WCHAR)] = 0;
  4897. result = DuplicatePathStringW ((PCWSTR)resultBuf.Buf, 0);
  4898. }
  4899. }
  4900. GbFree (&resultBuf);
  4901. return result;
  4902. }
  4903. /*++
  4904. Routine Description:
  4905. RealCreateParsedPatternEx parses the expanded pattern string into a set of
  4906. structures. Parsing is considered expensive relative to testing the
  4907. pattern, so callers should avoid calling this function inside loops. See
  4908. IsPatternMatchEx for a good description of the pattern string syntax.
  4909. Arguments:
  4910. Pattern - Specifies the pattern string, which can include the extended
  4911. wildcard syntax.
  4912. Return Value:
  4913. A pointer to a parsed pattern structure, which the caller will use like a
  4914. handle, or NULL if a syntax error occurred.
  4915. --*/
  4916. PPARSEDPATTERNA
  4917. RealCreateParsedPatternExA (
  4918. IN PMHANDLE Pool, OPTIONAL
  4919. IN PCSTR Pattern
  4920. )
  4921. {
  4922. PMHANDLE pool;
  4923. BOOL externalPool = FALSE;
  4924. PPARSEDPATTERNA Struct;
  4925. PATTERNSTATE State;
  4926. BOOL CompoundPattern = FALSE;
  4927. GROWBUFFER ExactMatchBuf = INIT_GROWBUFFER;
  4928. GROWBUFFER SegmentArray = INIT_GROWBUFFER;
  4929. GROWBUFFER PatternArray = INIT_GROWBUFFER;
  4930. GROWBUFFER SetBuf = INIT_GROWBUFFER;
  4931. PPATTERNPROPSA CurrentPattern;
  4932. MBCHAR ch = 0;
  4933. PCSTR LookAhead;
  4934. PCSTR SetBegin = NULL;
  4935. PATTERNSTATE ReturnState = 0;
  4936. SEGMENTA Segment;
  4937. PSEGMENTA SegmentElement;
  4938. UINT MaxLen;
  4939. Segment.Type = SEGMENTTYPE_UNKNOWN;
  4940. if (Pool) {
  4941. externalPool = TRUE;
  4942. pool = Pool;
  4943. } else {
  4944. pool = PmCreateNamedPoolEx ("Parsed Pattern", 512);
  4945. }
  4946. Struct = (PPARSEDPATTERNA) PmGetAlignedMemory (pool, sizeof (PARSEDPATTERNA));
  4947. ZeroMemory (Struct, sizeof (PARSEDPATTERNA));
  4948. State = BEGIN_PATTERN;
  4949. for (;;) {
  4950. switch (State) {
  4951. case BEGIN_PATTERN:
  4952. //
  4953. // Here we test for either a compound pattern (one that
  4954. // is a brace-separated list), or a simple pattern (one
  4955. // that does not have a brace).
  4956. //
  4957. if (_mbsnextc (Pattern) == '<') {
  4958. CompoundPattern = TRUE;
  4959. State = BEGIN_COMPOUND_PATTERN;
  4960. } else if (*Pattern) {
  4961. State = BEGIN_PATTERN_EXPR;
  4962. } else {
  4963. State = PATTERN_DONE;
  4964. }
  4965. break;
  4966. case BEGIN_COMPOUND_PATTERN:
  4967. //
  4968. // We are looking for the start of a compound pattern.
  4969. // Space is allowed inbetween the patterns, but not
  4970. // at the start.
  4971. //
  4972. while (_ismbcspace ((MBCHAR)(_mbsnextc (Pattern)))) {
  4973. Pattern = _mbsinc (Pattern);
  4974. }
  4975. if (*Pattern == 0) {
  4976. State = PATTERN_DONE;
  4977. break;
  4978. }
  4979. if (_mbsnextc (Pattern) == '<') {
  4980. Pattern = _mbsinc (Pattern);
  4981. State = BEGIN_PATTERN_EXPR;
  4982. } else {
  4983. DEBUGMSGA ((DBG_ERROR, "Syntax error in pattern: %s", Pattern));
  4984. State = PATTERN_ERROR;
  4985. }
  4986. break;
  4987. case BEGIN_PATTERN_EXPR:
  4988. //
  4989. // We are now ready to condense the expression.
  4990. //
  4991. State = PARSE_CHAR_EXPR_OR_END;
  4992. ExactMatchBuf.End = 0;
  4993. SegmentArray.End = 0;
  4994. break;
  4995. case PARSE_END_FOUND:
  4996. State = END_PATTERN_EXPR;
  4997. if (ExactMatchBuf.End) {
  4998. ReturnState = State;
  4999. State = SAVE_EXACT_MATCH;
  5000. }
  5001. break;
  5002. case END_PATTERN_EXPR:
  5003. //
  5004. // Copy the segment array into the pool, reference the copy
  5005. // in the pattern array
  5006. //
  5007. if (SegmentArray.End) {
  5008. CurrentPattern = (PPATTERNPROPSA) GbGrow (&PatternArray, sizeof (PATTERNPROPSA));
  5009. CurrentPattern->Segment = (PSEGMENTA) PmGetAlignedMemory (pool, SegmentArray.End);
  5010. CurrentPattern->SegmentCount = SegmentArray.End / sizeof (SEGMENTA);
  5011. CopyMemory (
  5012. CurrentPattern->Segment,
  5013. SegmentArray.Buf,
  5014. (SIZE_T) SegmentArray.End
  5015. );
  5016. }
  5017. if (CompoundPattern && *Pattern) {
  5018. State = BEGIN_COMPOUND_PATTERN;
  5019. } else {
  5020. State = PATTERN_DONE;
  5021. }
  5022. break;
  5023. case PARSE_CHAR_EXPR_OR_END:
  5024. //
  5025. // We now accept the following:
  5026. //
  5027. // 1. The end of the string or end of a compound pattern
  5028. // 2. An escaped character
  5029. // 3. The start of an expression
  5030. // 4. A non-syntax character
  5031. //
  5032. ch = _mbsnextc (Pattern);
  5033. if (ch == '>' && CompoundPattern) {
  5034. //
  5035. // Case 1, we found the end of a compound pattern
  5036. //
  5037. Pattern = _mbsinc (Pattern);
  5038. State = PARSE_END_FOUND;
  5039. break;
  5040. }
  5041. if (*Pattern == 0) {
  5042. //
  5043. // Case 1, we found the end of the pattern
  5044. //
  5045. if (CompoundPattern) {
  5046. State = PATTERN_ERROR;
  5047. } else {
  5048. State = PARSE_END_FOUND;
  5049. }
  5050. break;
  5051. }
  5052. if (ch == '^') {
  5053. //
  5054. // Case 2, we found an escaped character, so transfer
  5055. // it to the buffer.
  5056. //
  5057. MYASSERT (
  5058. Segment.Type == SEGMENTTYPE_UNKNOWN ||
  5059. Segment.Type == SEGMENTTYPE_EXACTMATCH
  5060. );
  5061. Segment.Type = SEGMENTTYPE_EXACTMATCH;
  5062. Pattern = _mbsinc (Pattern);
  5063. pAppendCharToGrowBufferA (&ExactMatchBuf, Pattern);
  5064. Pattern = _mbsinc (Pattern);
  5065. break;
  5066. }
  5067. if (ch == '*' || ch == '?') {
  5068. //
  5069. // Case 3, we found an expression. Save the wildcard type
  5070. // and parse the optional args.
  5071. //
  5072. if (ExactMatchBuf.End) {
  5073. State = SAVE_EXACT_MATCH;
  5074. ReturnState = PARSE_CHAR_EXPR_OR_END;
  5075. break;
  5076. }
  5077. ZeroMemory (&Segment, sizeof (Segment));
  5078. if (ch == '*') {
  5079. Segment.Type = SEGMENTTYPE_OPTIONAL;
  5080. } else {
  5081. Segment.Type = SEGMENTTYPE_REQUIRED;
  5082. Segment.Wildcard.MaxLen = 1;
  5083. }
  5084. Pattern = _mbsinc (Pattern);
  5085. if (_mbsnextc (Pattern) == '[') {
  5086. Pattern = _mbsinc (Pattern);
  5087. State = LOOK_FOR_NUMBER;
  5088. } else {
  5089. ReturnState = PARSE_CHAR_EXPR_OR_END;
  5090. State = SAVE_SEGMENT;
  5091. }
  5092. break;
  5093. }
  5094. //
  5095. // Case 4, we don't know about this character, so just copy it
  5096. // and continue parsing.
  5097. //
  5098. pAppendCharToGrowBufferA (&ExactMatchBuf, Pattern);
  5099. Pattern = _mbsinc (Pattern);
  5100. break;
  5101. case SAVE_EXACT_MATCH:
  5102. //
  5103. // Put the string in ExactMatchBuf into a segment struct
  5104. //
  5105. pAppendCharToGrowBufferA (&ExactMatchBuf, "");
  5106. Segment.Exact.LowerCasePhrase = PmDuplicateStringA (
  5107. pool,
  5108. (PCSTR) ExactMatchBuf.Buf
  5109. );
  5110. Segment.Exact.PhraseBytes = ExactMatchBuf.End - sizeof (CHAR);
  5111. MYASSERT (Segment.Exact.LowerCasePhrase);
  5112. CharLowerA ((PSTR) Segment.Exact.LowerCasePhrase);
  5113. Segment.Type = SEGMENTTYPE_EXACTMATCH;
  5114. ExactMatchBuf.End = 0;
  5115. // FALL THROUGH!!
  5116. case SAVE_SEGMENT:
  5117. //
  5118. // Put the segment element into the segment array
  5119. //
  5120. SegmentElement = (PSEGMENTA) GbGrow (&SegmentArray, sizeof (SEGMENTA));
  5121. CopyMemory (SegmentElement, &Segment, sizeof (SEGMENTA));
  5122. Segment.Type = SEGMENTTYPE_UNKNOWN;
  5123. State = ReturnState;
  5124. break;
  5125. case LOOK_FOR_NUMBER:
  5126. //
  5127. // Here we are inside a bracket, and there is an optional
  5128. // numeric arg, which must be followed by a colon. Test
  5129. // that here.
  5130. //
  5131. LookAhead = Pattern;
  5132. MaxLen = 0;
  5133. while (*LookAhead >= '0' && *LookAhead <= '9') {
  5134. MaxLen = MaxLen * 10 + (*LookAhead - '0');
  5135. LookAhead++;
  5136. }
  5137. if (LookAhead > Pattern && _mbsnextc (LookAhead) == ':') {
  5138. Pattern = _mbsinc (LookAhead);
  5139. //
  5140. // Check for special case syntax error: ?[0:]
  5141. //
  5142. if (Segment.Type == SEGMENTTYPE_EXACTMATCH && !MaxLen) {
  5143. State = PATTERN_ERROR;
  5144. break;
  5145. }
  5146. Segment.Wildcard.MaxLen = MaxLen;
  5147. }
  5148. SetBegin = Pattern;
  5149. State = LOOK_FOR_INCLUDE;
  5150. SetBuf.End = 0;
  5151. break;
  5152. case LOOK_FOR_INCLUDE:
  5153. //
  5154. // Here we are inside a bracket, past an optional numeric
  5155. // arg. Now we look for all the include sets, which are
  5156. // optional. We have the following possibilities:
  5157. //
  5158. // 1. End of set
  5159. // 2. An exclude set that needs to be skipped
  5160. // 3. A valid include set
  5161. // 4. Error
  5162. //
  5163. // We look at SetBegin, and not Pattern.
  5164. //
  5165. MYASSERT (SetBegin);
  5166. ch = _mbsnextc (SetBegin);
  5167. if (ch == ']') {
  5168. //
  5169. // Case 1: end of set
  5170. //
  5171. if (SetBuf.End) {
  5172. pAppendCharToGrowBufferA (&SetBuf, "");
  5173. Segment.Wildcard.IncludeSet = PmDuplicateStringA (
  5174. pool,
  5175. (PCSTR) SetBuf.Buf
  5176. );
  5177. CharLowerA ((PSTR) Segment.Wildcard.IncludeSet);
  5178. } else {
  5179. Segment.Wildcard.IncludeSet = NULL;
  5180. }
  5181. SetBuf.End = 0;
  5182. State = LOOK_FOR_EXCLUDE;
  5183. SetBegin = Pattern;
  5184. break;
  5185. }
  5186. if (ch == '!') {
  5187. //
  5188. // Case 2: an exclude set
  5189. //
  5190. SetBegin = _mbsinc (SetBegin);
  5191. State = SKIP_EXCLUDE_SET;
  5192. ReturnState = LOOK_FOR_INCLUDE;
  5193. break;
  5194. }
  5195. if (*SetBegin == 0) { //lint !e613
  5196. State = PATTERN_ERROR;
  5197. break;
  5198. }
  5199. //
  5200. // Case 3: a valid include set.
  5201. //
  5202. State = CONDENSE_SET;
  5203. ReturnState = LOOK_FOR_INCLUDE;
  5204. break;
  5205. case LOOK_FOR_EXCLUDE:
  5206. //
  5207. // Here we are inside a bracket, past an optional numeric
  5208. // arg. All include sets are in the condensing buffer.
  5209. // Now we look for all the exclude sets, which are
  5210. // optional. We have the following possibilities:
  5211. //
  5212. // 1. End of set
  5213. // 2. A valid exclude set
  5214. // 3. An include set that needs to be skipped
  5215. // 4. Error
  5216. //
  5217. // We look at SetBegin, and not Pattern.
  5218. //
  5219. ch = _mbsnextc (SetBegin);
  5220. if (ch == ']') {
  5221. //
  5222. // Case 1: end of set; we're done with this expr
  5223. //
  5224. if (SetBuf.End) {
  5225. pAppendCharToGrowBufferA (&SetBuf, "");
  5226. Segment.Wildcard.ExcludeSet = PmDuplicateStringA (
  5227. pool,
  5228. (PCSTR) SetBuf.Buf
  5229. );
  5230. CharLowerA ((PSTR) Segment.Wildcard.ExcludeSet);
  5231. } else {
  5232. Segment.Wildcard.ExcludeSet = NULL;
  5233. }
  5234. SetBuf.End = 0;
  5235. State = SAVE_SEGMENT;
  5236. ReturnState = PARSE_CHAR_EXPR_OR_END;
  5237. Pattern = _mbsinc (SetBegin);
  5238. break;
  5239. }
  5240. if (ch == '!') {
  5241. //
  5242. // Case 2: a valid exclude set; save it
  5243. //
  5244. SetBegin = _mbsinc (SetBegin);
  5245. if (_mbsnextc (SetBegin) != '(') {
  5246. State = PATTERN_ERROR;
  5247. break;
  5248. }
  5249. SetBegin = _mbsinc (SetBegin);
  5250. State = CONDENSE_SET;
  5251. ReturnState = LOOK_FOR_EXCLUDE;
  5252. break;
  5253. }
  5254. if (*SetBegin == 0) { //lint !e613
  5255. State = PATTERN_ERROR;
  5256. break;
  5257. }
  5258. //
  5259. // Case 3: an include set that needs to be skipped.
  5260. //
  5261. State = SKIP_INCLUDE_SET;
  5262. ReturnState = LOOK_FOR_EXCLUDE;
  5263. break;
  5264. case CONDENSE_SET:
  5265. //
  5266. // Here SetBegin points to a set range, and it is our
  5267. // job to copy the range into the set buffer, and
  5268. // return back to the previous state.
  5269. //
  5270. //
  5271. // Copy the character at SetBegin
  5272. //
  5273. if (_mbsnextc (SetBegin) == '^') {
  5274. SetBegin = _mbsinc (SetBegin);
  5275. if (*SetBegin == 0) {
  5276. State = PATTERN_ERROR;
  5277. break;
  5278. }
  5279. }
  5280. pAppendCharToGrowBufferA (&SetBuf, SetBegin);
  5281. //
  5282. // Check if this is a range or not
  5283. //
  5284. LookAhead = _mbsinc (SetBegin);
  5285. if (_mbsnextc (LookAhead) == '-') {
  5286. //
  5287. // Range, copy the character after the dash
  5288. //
  5289. SetBegin = _mbsinc (LookAhead);
  5290. if (*SetBegin == 0) {
  5291. State = PATTERN_ERROR;
  5292. break;
  5293. }
  5294. if (_mbsnextc (SetBegin) == '^') {
  5295. SetBegin = _mbsinc (SetBegin);
  5296. if (*SetBegin == 0) {
  5297. State = PATTERN_ERROR;
  5298. break;
  5299. }
  5300. }
  5301. pAppendCharToGrowBufferA (&SetBuf, SetBegin);
  5302. } else {
  5303. //
  5304. // A single character, copy the character again
  5305. //
  5306. pAppendCharToGrowBufferA (&SetBuf, SetBegin);
  5307. }
  5308. SetBegin = _mbsinc (SetBegin);
  5309. ch = _mbsnextc (SetBegin);
  5310. //
  5311. // If this is an exclude set, we must have a closing paren
  5312. // or a comma
  5313. //
  5314. State = ReturnState;
  5315. if (ReturnState == LOOK_FOR_EXCLUDE) {
  5316. if (ch == ')') {
  5317. SetBegin = _mbsinc (SetBegin);
  5318. ch = _mbsnextc (SetBegin);
  5319. } else if (ch != ',') {
  5320. State = PATTERN_ERROR;
  5321. } else {
  5322. //
  5323. // Continue condensing the next part of this exclude set
  5324. //
  5325. State = CONDENSE_SET;
  5326. }
  5327. }
  5328. //
  5329. // We either need a comma or a close brace
  5330. //
  5331. if (ch == ',') {
  5332. SetBegin = _mbsinc (SetBegin);
  5333. } else if (ch != ']') {
  5334. State = PATTERN_ERROR;
  5335. }
  5336. break;
  5337. case SKIP_EXCLUDE_SET:
  5338. //
  5339. // Skip over the parenthesis group, assuming it is syntatically
  5340. // correct, and return to the previous state.
  5341. //
  5342. if (_mbsnextc (SetBegin) != '(') {
  5343. State = PATTERN_ERROR;
  5344. break;
  5345. }
  5346. SetBegin = _mbsinc (SetBegin);
  5347. while (*SetBegin) {
  5348. if (_mbsnextc (SetBegin) == '^') {
  5349. SetBegin = _mbsinc (SetBegin);
  5350. } else if (_mbsnextc (SetBegin) == ')') {
  5351. break;
  5352. }
  5353. if (IsLeadByte (SetBegin)) {
  5354. SetBegin += 2;
  5355. } else {
  5356. SetBegin += 1;
  5357. }
  5358. }
  5359. if (*SetBegin == 0) {
  5360. State = PATTERN_ERROR;
  5361. break;
  5362. }
  5363. SetBegin = _mbsinc (SetBegin);
  5364. //
  5365. // Now we are either at a comma or a close brace
  5366. //
  5367. ch = _mbsnextc (SetBegin);
  5368. State = ReturnState;
  5369. if (ch == ',') {
  5370. SetBegin = _mbsinc (SetBegin);
  5371. } else if (ch != ']') {
  5372. State = PATTERN_ERROR;
  5373. }
  5374. break;
  5375. case SKIP_INCLUDE_SET:
  5376. //
  5377. // Skip to the next comma or closing brace. We know it is
  5378. // syntatically correct by now.
  5379. //
  5380. ch = 0;
  5381. while (*SetBegin) { //lint !e613
  5382. ch = _mbsnextc (SetBegin);
  5383. if (ch == '^') {
  5384. SetBegin = _mbsinc (SetBegin);
  5385. } else if (ch == ',' || ch == ']') {
  5386. break;
  5387. }
  5388. SetBegin = _mbsinc (SetBegin);
  5389. }
  5390. MYASSERT (*SetBegin); //lint !e794
  5391. if (ch == ',') {
  5392. SetBegin = _mbsinc (SetBegin);
  5393. }
  5394. State = ReturnState;
  5395. break;
  5396. } //lint !e787
  5397. if (State == PATTERN_DONE || State == PATTERN_ERROR) {
  5398. break;
  5399. }
  5400. }
  5401. GbFree (&ExactMatchBuf);
  5402. GbFree (&SetBuf);
  5403. GbFree (&SegmentArray);
  5404. if (State == PATTERN_ERROR) {
  5405. GbFree (&PatternArray);
  5406. if (!externalPool) {
  5407. PmDestroyPool (Pool);
  5408. }
  5409. return NULL;
  5410. }
  5411. if (PatternArray.End == 0) {
  5412. //build an empty parsed pattern
  5413. GbFree (&PatternArray);
  5414. Struct->PatternCount = 1;
  5415. Struct->Pool = pool;
  5416. Struct->ExternalPool = externalPool;
  5417. Struct->Pattern = (PPATTERNPROPSA) PmGetAlignedMemory (
  5418. pool,
  5419. sizeof (PATTERNPROPSA)
  5420. );
  5421. Struct->Pattern[0].SegmentCount = 1;
  5422. Struct->Pattern[0].Segment = (PSEGMENTA) PmGetAlignedMemory (
  5423. pool,
  5424. sizeof (SEGMENTA)
  5425. );
  5426. Struct->Pattern[0].Segment[0].Type = SEGMENTTYPE_EXACTMATCH;
  5427. Struct->Pattern[0].Segment[0].Exact.LowerCasePhrase = PmDuplicateStringA (pool, "");
  5428. Struct->Pattern[0].Segment[0].Exact.PhraseBytes = 0;
  5429. return Struct;
  5430. }
  5431. //
  5432. // Copy the fully parsed pattern array into the return struct
  5433. //
  5434. Struct->Pattern = (PPATTERNPROPSA) PmGetAlignedMemory (
  5435. pool,
  5436. PatternArray.End
  5437. );
  5438. CopyMemory (Struct->Pattern, PatternArray.Buf, (SIZE_T) PatternArray.End);
  5439. Struct->PatternCount = PatternArray.End / sizeof (PATTERNPROPSA);
  5440. Struct->Pool = pool;
  5441. Struct->ExternalPool = externalPool;
  5442. GbFree (&PatternArray);
  5443. return Struct;
  5444. }
  5445. PPARSEDPATTERNW
  5446. RealCreateParsedPatternExW (
  5447. IN PMHANDLE Pool, OPTIONAL
  5448. IN PCWSTR Pattern
  5449. )
  5450. {
  5451. PMHANDLE pool;
  5452. BOOL externalPool = FALSE;
  5453. PPARSEDPATTERNW Struct;
  5454. PATTERNSTATE State;
  5455. BOOL CompoundPattern = FALSE;
  5456. GROWBUFFER ExactMatchBuf = INIT_GROWBUFFER;
  5457. GROWBUFFER SegmentArray = INIT_GROWBUFFER;
  5458. GROWBUFFER PatternArray = INIT_GROWBUFFER;
  5459. GROWBUFFER SetBuf = INIT_GROWBUFFER;
  5460. PPATTERNPROPSW CurrentPattern;
  5461. WCHAR ch = 0;
  5462. PCWSTR LookAhead;
  5463. PCWSTR SetBegin = NULL;
  5464. PATTERNSTATE ReturnState = 0;
  5465. SEGMENTW Segment;
  5466. PSEGMENTW SegmentElement;
  5467. UINT MaxLen;
  5468. Segment.Type = SEGMENTTYPE_UNKNOWN;
  5469. if (Pool) {
  5470. externalPool = TRUE;
  5471. pool = Pool;
  5472. } else {
  5473. pool = PmCreateNamedPoolEx ("Parsed Pattern", 512);
  5474. }
  5475. Struct = (PPARSEDPATTERNW) PmGetAlignedMemory (pool, sizeof (PARSEDPATTERNW));
  5476. ZeroMemory (Struct, sizeof (PARSEDPATTERNW));
  5477. State = BEGIN_PATTERN;
  5478. for (;;) {
  5479. switch (State) {
  5480. case BEGIN_PATTERN:
  5481. //
  5482. // Here we test for either a compound pattern (one that
  5483. // is a brace-separated list), or a simple pattern (one
  5484. // that does not have a brace).
  5485. //
  5486. if (*Pattern == L'<') {
  5487. CompoundPattern = TRUE;
  5488. State = BEGIN_COMPOUND_PATTERN;
  5489. } else if (*Pattern) {
  5490. State = BEGIN_PATTERN_EXPR;
  5491. } else {
  5492. State = PATTERN_DONE;
  5493. }
  5494. break;
  5495. case BEGIN_COMPOUND_PATTERN:
  5496. //
  5497. // We are looking for the start of a compound pattern.
  5498. // Space is allowed inbetween the patterns, but not
  5499. // at the start.
  5500. //
  5501. while (iswspace (*Pattern)) {
  5502. Pattern++;
  5503. }
  5504. if (*Pattern == 0) {
  5505. State = PATTERN_DONE;
  5506. break;
  5507. }
  5508. if (*Pattern == L'<') {
  5509. Pattern++;
  5510. State = BEGIN_PATTERN_EXPR;
  5511. } else {
  5512. DEBUGMSGW ((DBG_ERROR, "Syntax error in pattern: %s", Pattern));
  5513. State = PATTERN_ERROR;
  5514. }
  5515. break;
  5516. case BEGIN_PATTERN_EXPR:
  5517. //
  5518. // We are now ready to condense the expression.
  5519. //
  5520. State = PARSE_CHAR_EXPR_OR_END;
  5521. ExactMatchBuf.End = 0;
  5522. SegmentArray.End = 0;
  5523. break;
  5524. case PARSE_END_FOUND:
  5525. State = END_PATTERN_EXPR;
  5526. if (ExactMatchBuf.End) {
  5527. ReturnState = State;
  5528. State = SAVE_EXACT_MATCH;
  5529. }
  5530. break;
  5531. case END_PATTERN_EXPR:
  5532. //
  5533. // Copy the segment array into the pool, reference the copy
  5534. // in the pattern array
  5535. //
  5536. if (SegmentArray.End) {
  5537. CurrentPattern = (PPATTERNPROPSW) GbGrow (&PatternArray, sizeof (PATTERNPROPSW));
  5538. CurrentPattern->Segment = (PSEGMENTW) PmGetAlignedMemory (pool, SegmentArray.End);
  5539. CurrentPattern->SegmentCount = SegmentArray.End / sizeof (SEGMENTW);
  5540. CopyMemory (
  5541. CurrentPattern->Segment,
  5542. SegmentArray.Buf,
  5543. (SIZE_T) SegmentArray.End
  5544. );
  5545. }
  5546. if (CompoundPattern && *Pattern) {
  5547. State = BEGIN_COMPOUND_PATTERN;
  5548. } else {
  5549. State = PATTERN_DONE;
  5550. }
  5551. break;
  5552. case PARSE_CHAR_EXPR_OR_END:
  5553. //
  5554. // We now accept the following:
  5555. //
  5556. // 1. The end of the string or end of a compound pattern
  5557. // 2. An escaped character
  5558. // 3. The start of an expression
  5559. // 4. A non-syntax character
  5560. //
  5561. ch = *Pattern;
  5562. if (ch == L'>' && CompoundPattern) {
  5563. //
  5564. // Case 1, we found the end of a compound pattern
  5565. //
  5566. Pattern++;
  5567. State = PARSE_END_FOUND;
  5568. break;
  5569. }
  5570. if (*Pattern == 0) {
  5571. //
  5572. // Case 1, we found the end of the pattern
  5573. //
  5574. if (CompoundPattern) {
  5575. State = PATTERN_ERROR;
  5576. } else {
  5577. State = PARSE_END_FOUND;
  5578. }
  5579. break;
  5580. }
  5581. if (ch == L'^') {
  5582. //
  5583. // Case 2, we found an escaped character, so transfer
  5584. // it to the buffer.
  5585. //
  5586. MYASSERT (
  5587. Segment.Type == SEGMENTTYPE_UNKNOWN ||
  5588. Segment.Type == SEGMENTTYPE_EXACTMATCH
  5589. );
  5590. Segment.Type = SEGMENTTYPE_EXACTMATCH;
  5591. Pattern++;
  5592. pAppendCharToGrowBufferW (&ExactMatchBuf, Pattern);
  5593. Pattern++;
  5594. break;
  5595. }
  5596. if (ch == L'*' || ch == L'?') {
  5597. //
  5598. // Case 3, we found an expression. Save the wildcard type
  5599. // and parse the optional args.
  5600. //
  5601. if (ExactMatchBuf.End) {
  5602. State = SAVE_EXACT_MATCH;
  5603. ReturnState = PARSE_CHAR_EXPR_OR_END;
  5604. break;
  5605. }
  5606. ZeroMemory (&Segment, sizeof (Segment));
  5607. if (ch == L'*') {
  5608. Segment.Type = SEGMENTTYPE_OPTIONAL;
  5609. } else {
  5610. Segment.Type = SEGMENTTYPE_REQUIRED;
  5611. Segment.Wildcard.MaxLen = 1;
  5612. }
  5613. Pattern++;
  5614. if (*Pattern == L'[') {
  5615. Pattern++;
  5616. State = LOOK_FOR_NUMBER;
  5617. } else {
  5618. ReturnState = PARSE_CHAR_EXPR_OR_END;
  5619. State = SAVE_SEGMENT;
  5620. }
  5621. break;
  5622. }
  5623. //
  5624. // Case 4, we don't know about this character, so just copy it
  5625. // and continue parsing.
  5626. //
  5627. pAppendCharToGrowBufferW (&ExactMatchBuf, Pattern);
  5628. Pattern++;
  5629. break;
  5630. case SAVE_EXACT_MATCH:
  5631. //
  5632. // Put the string in ExactMatchBuf into a segment struct
  5633. //
  5634. pAppendCharToGrowBufferW (&ExactMatchBuf, L"");
  5635. Segment.Exact.LowerCasePhrase = PmDuplicateStringW (
  5636. pool,
  5637. (PCWSTR) ExactMatchBuf.Buf
  5638. ); //lint !e64
  5639. Segment.Exact.PhraseBytes = ExactMatchBuf.End - sizeof (WCHAR);
  5640. MYASSERT (Segment.Exact.LowerCasePhrase);
  5641. CharLowerW ((PWSTR) Segment.Exact.LowerCasePhrase);
  5642. Segment.Type = SEGMENTTYPE_EXACTMATCH;
  5643. ExactMatchBuf.End = 0;
  5644. // FALL THROUGH!!
  5645. case SAVE_SEGMENT:
  5646. //
  5647. // Put the segment element into the segment array
  5648. //
  5649. SegmentElement = (PSEGMENTW) GbGrow (&SegmentArray, sizeof (SEGMENTW));
  5650. CopyMemory (SegmentElement, &Segment, sizeof (SEGMENTW));
  5651. Segment.Type = SEGMENTTYPE_UNKNOWN;
  5652. State = ReturnState;
  5653. break;
  5654. case LOOK_FOR_NUMBER:
  5655. //
  5656. // Here we are inside a bracket, and there is an optional
  5657. // numeric arg, which must be followed by a colon. Test
  5658. // that here.
  5659. //
  5660. LookAhead = Pattern;
  5661. MaxLen = 0;
  5662. while (*LookAhead >= L'0' && *LookAhead <= L'9') {
  5663. MaxLen = MaxLen * 10 + (*LookAhead - L'0');
  5664. LookAhead++;
  5665. }
  5666. if (LookAhead > Pattern && *LookAhead == L':') {
  5667. Pattern = LookAhead + 1;
  5668. //
  5669. // Check for special case syntax error: ?[0:]
  5670. //
  5671. if (Segment.Type == SEGMENTTYPE_EXACTMATCH && !MaxLen) {
  5672. State = PATTERN_ERROR;
  5673. break;
  5674. }
  5675. Segment.Wildcard.MaxLen = MaxLen;
  5676. }
  5677. SetBegin = Pattern;
  5678. State = LOOK_FOR_INCLUDE;
  5679. SetBuf.End = 0;
  5680. break;
  5681. case LOOK_FOR_INCLUDE:
  5682. //
  5683. // Here we are inside a bracket, past an optional numeric
  5684. // arg. Now we look for all the include sets, which are
  5685. // optional. We have the following possibilities:
  5686. //
  5687. // 1. End of set
  5688. // 2. An exclude set that needs to be skipped
  5689. // 3. A valid include set
  5690. // 4. Error
  5691. //
  5692. // We look at SetBegin, and not Pattern.
  5693. //
  5694. if (!SetBegin) {
  5695. State = PATTERN_ERROR;
  5696. break;
  5697. }
  5698. ch = *SetBegin;
  5699. if (ch == L']') {
  5700. //
  5701. // Case 1: end of set
  5702. //
  5703. if (SetBuf.End) {
  5704. pAppendCharToGrowBufferW (&SetBuf, L"");
  5705. Segment.Wildcard.IncludeSet = PmDuplicateStringW (
  5706. pool,
  5707. (PCWSTR) SetBuf.Buf
  5708. ); //lint !e64
  5709. CharLowerW ((PWSTR) Segment.Wildcard.IncludeSet);
  5710. } else {
  5711. Segment.Wildcard.IncludeSet = NULL;
  5712. }
  5713. SetBuf.End = 0;
  5714. State = LOOK_FOR_EXCLUDE;
  5715. SetBegin = Pattern;
  5716. break;
  5717. }
  5718. if (ch == L'!') {
  5719. //
  5720. // Case 2: an exclude set
  5721. //
  5722. SetBegin++;
  5723. State = SKIP_EXCLUDE_SET;
  5724. ReturnState = LOOK_FOR_INCLUDE;
  5725. break;
  5726. }
  5727. if (*SetBegin == 0) {
  5728. State = PATTERN_ERROR;
  5729. break;
  5730. }
  5731. //
  5732. // Case 3: a valid include set.
  5733. //
  5734. State = CONDENSE_SET;
  5735. ReturnState = LOOK_FOR_INCLUDE;
  5736. break;
  5737. case LOOK_FOR_EXCLUDE:
  5738. //
  5739. // Here we are inside a bracket, past an optional numeric
  5740. // arg. All include sets are in the condensing buffer.
  5741. // Now we look for all the exclude sets, which are
  5742. // optional. We have the following possibilities:
  5743. //
  5744. // 1. End of set
  5745. // 2. A valid exclude set
  5746. // 3. An include set that needs to be skipped
  5747. // 4. Error
  5748. //
  5749. // We look at SetBegin, and not Pattern.
  5750. //
  5751. if (!SetBegin) {
  5752. State = PATTERN_ERROR;
  5753. break;
  5754. }
  5755. ch = *SetBegin;
  5756. if (ch == L']') {
  5757. //
  5758. // Case 1: end of set; we're done with this expr
  5759. //
  5760. if (SetBuf.End) {
  5761. pAppendCharToGrowBufferW (&SetBuf, L"");
  5762. Segment.Wildcard.ExcludeSet = PmDuplicateStringW (
  5763. pool,
  5764. (PCWSTR) SetBuf.Buf
  5765. ); //lint !e64
  5766. CharLowerW ((PWSTR) Segment.Wildcard.ExcludeSet);
  5767. } else {
  5768. Segment.Wildcard.ExcludeSet = NULL;
  5769. }
  5770. SetBuf.End = 0;
  5771. State = SAVE_SEGMENT;
  5772. ReturnState = PARSE_CHAR_EXPR_OR_END;
  5773. Pattern = SetBegin + 1;
  5774. break;
  5775. }
  5776. if (ch == L'!') {
  5777. //
  5778. // Case 2: a valid exclude set; save it
  5779. //
  5780. SetBegin++; //lint !e613
  5781. if (*SetBegin != L'(') {
  5782. State = PATTERN_ERROR;
  5783. break;
  5784. }
  5785. SetBegin++;
  5786. State = CONDENSE_SET;
  5787. ReturnState = LOOK_FOR_EXCLUDE;
  5788. break;
  5789. }
  5790. if (*SetBegin == 0) {
  5791. State = PATTERN_ERROR;
  5792. break;
  5793. }
  5794. //
  5795. // Case 3: an include set that needs to be skipped.
  5796. //
  5797. State = SKIP_INCLUDE_SET;
  5798. ReturnState = LOOK_FOR_EXCLUDE;
  5799. break;
  5800. case CONDENSE_SET:
  5801. //
  5802. // Here SetBegin points to a set range, and it is our
  5803. // job to copy the range into the set buffer, and
  5804. // return back to the previous state.
  5805. //
  5806. //
  5807. // Copy the character at SetBegin
  5808. //
  5809. if (!SetBegin) {
  5810. State = PATTERN_ERROR;
  5811. break;
  5812. }
  5813. if (*SetBegin == L'^') {
  5814. SetBegin++;
  5815. if (*SetBegin == 0) {
  5816. State = PATTERN_ERROR;
  5817. break;
  5818. }
  5819. }
  5820. pAppendCharToGrowBufferW (&SetBuf, SetBegin);
  5821. //
  5822. // Check if this is a range or not
  5823. //
  5824. LookAhead = SetBegin + 1;
  5825. if (*LookAhead == L'-') {
  5826. //
  5827. // Range, copy the character after the dash
  5828. //
  5829. SetBegin = LookAhead + 1;
  5830. if (*SetBegin == 0) {
  5831. State = PATTERN_ERROR;
  5832. break;
  5833. }
  5834. if (*SetBegin == L'^') {
  5835. SetBegin++;
  5836. if (*SetBegin == 0) {
  5837. State = PATTERN_ERROR;
  5838. break;
  5839. }
  5840. }
  5841. pAppendCharToGrowBufferW (&SetBuf, SetBegin);
  5842. } else {
  5843. //
  5844. // A single character, copy the character again
  5845. //
  5846. pAppendCharToGrowBufferW (&SetBuf, SetBegin);
  5847. }
  5848. SetBegin++;
  5849. ch = *SetBegin;
  5850. //
  5851. // If this is an exclude set, we must have a closing paren
  5852. // or a comma
  5853. //
  5854. State = ReturnState;
  5855. if (ReturnState == LOOK_FOR_EXCLUDE) {
  5856. if (ch == L')') {
  5857. SetBegin++;
  5858. ch = *SetBegin;
  5859. } else if (ch != L',') {
  5860. State = PATTERN_ERROR;
  5861. } else {
  5862. //
  5863. // Continue condensing the next part of this exclude set
  5864. //
  5865. State = CONDENSE_SET;
  5866. }
  5867. }
  5868. //
  5869. // We either need a comma or a close brace
  5870. //
  5871. if (ch == L',') {
  5872. SetBegin++;
  5873. } else if (ch != L']') {
  5874. State = PATTERN_ERROR;
  5875. }
  5876. break;
  5877. case SKIP_EXCLUDE_SET:
  5878. //
  5879. // Skip over the parenthesis group, assuming it is syntatically
  5880. // correct, and return to the previous state.
  5881. //
  5882. if (!SetBegin) {
  5883. State = PATTERN_ERROR;
  5884. break;
  5885. }
  5886. if (*SetBegin != L'(') {
  5887. State = PATTERN_ERROR;
  5888. break;
  5889. }
  5890. SetBegin++;
  5891. while (*SetBegin) {
  5892. if (*SetBegin == L'^') {
  5893. SetBegin++;
  5894. } else if (*SetBegin == L')') {
  5895. break;
  5896. }
  5897. SetBegin++;
  5898. }
  5899. if (*SetBegin == 0) {
  5900. State = PATTERN_ERROR;
  5901. break;
  5902. }
  5903. SetBegin++;
  5904. //
  5905. // Now we are either at a comma or a close brace
  5906. //
  5907. ch = *SetBegin;
  5908. State = ReturnState;
  5909. if (ch == L',') {
  5910. SetBegin++;
  5911. } else if (ch != L']') {
  5912. State = PATTERN_ERROR;
  5913. }
  5914. break;
  5915. case SKIP_INCLUDE_SET:
  5916. //
  5917. // Skip to the next comma or closing brace. We know it is
  5918. // syntatically correct by now.
  5919. //
  5920. if (!SetBegin) {
  5921. State = PATTERN_ERROR;
  5922. break;
  5923. }
  5924. ch = 0;
  5925. while (*SetBegin) {
  5926. ch = *SetBegin;
  5927. if (ch == L'^') {
  5928. SetBegin++; //lint !e613
  5929. } else if (ch == L',' || ch == L']') {
  5930. break;
  5931. }
  5932. SetBegin++;
  5933. }
  5934. MYASSERT (*SetBegin);
  5935. if (ch == L',') {
  5936. SetBegin++;
  5937. }
  5938. State = ReturnState;
  5939. break;
  5940. } //lint !e787
  5941. if (State == PATTERN_DONE || State == PATTERN_ERROR) {
  5942. break;
  5943. }
  5944. }
  5945. GbFree (&ExactMatchBuf);
  5946. GbFree (&SetBuf);
  5947. GbFree (&SegmentArray);
  5948. if (State == PATTERN_ERROR) {
  5949. GbFree (&PatternArray);
  5950. if (!externalPool) {
  5951. PmDestroyPool (pool);
  5952. }
  5953. return NULL;
  5954. }
  5955. if (PatternArray.End == 0) {
  5956. //build an empty parsed pattern
  5957. GbFree (&PatternArray);
  5958. Struct->PatternCount = 1;
  5959. Struct->Pool = pool;
  5960. Struct->ExternalPool = externalPool;
  5961. Struct->Pattern = (PPATTERNPROPSW) PmGetAlignedMemory (
  5962. pool,
  5963. sizeof (PATTERNPROPSW)
  5964. );
  5965. Struct->Pattern[0].SegmentCount = 1;
  5966. Struct->Pattern[0].Segment = (PSEGMENTW) PmGetAlignedMemory (
  5967. pool,
  5968. sizeof (SEGMENTW)
  5969. );
  5970. Struct->Pattern[0].Segment[0].Type = SEGMENTTYPE_EXACTMATCH;
  5971. Struct->Pattern[0].Segment[0].Exact.LowerCasePhrase = PmDuplicateStringW (pool, L"");
  5972. Struct->Pattern[0].Segment[0].Exact.PhraseBytes = 0;
  5973. return Struct;
  5974. }
  5975. //
  5976. // Copy the fully parsed pattern array into the return struct
  5977. //
  5978. Struct->Pattern = (PPATTERNPROPSW) PmGetAlignedMemory (
  5979. pool,
  5980. PatternArray.End
  5981. );
  5982. CopyMemory (Struct->Pattern, PatternArray.Buf, (SIZE_T) PatternArray.End);
  5983. Struct->PatternCount = PatternArray.End / sizeof (PATTERNPROPSW);
  5984. Struct->Pool = pool;
  5985. Struct->ExternalPool = externalPool;
  5986. GbFree (&PatternArray);
  5987. return Struct;
  5988. }
  5989. BOOL
  5990. WildCharsPatternA (
  5991. IN PPARSEDPATTERNA ParsedPattern
  5992. )
  5993. {
  5994. UINT i,j;
  5995. if (!ParsedPattern) {
  5996. return FALSE;
  5997. }
  5998. for (i=0; i<ParsedPattern->PatternCount; i++) {
  5999. if (ParsedPattern->Pattern[i].SegmentCount < 1) {
  6000. return TRUE;
  6001. }
  6002. for (j=0; j<ParsedPattern->Pattern[i].SegmentCount; j++) {
  6003. if ((ParsedPattern->Pattern[i].Segment[j].Type == SEGMENTTYPE_OPTIONAL) ||
  6004. (ParsedPattern->Pattern[i].Segment[j].Type == SEGMENTTYPE_REQUIRED)
  6005. ) {
  6006. return TRUE;
  6007. }
  6008. }
  6009. }
  6010. return FALSE;
  6011. }
  6012. BOOL
  6013. WildCharsPatternW (
  6014. IN PPARSEDPATTERNW ParsedPattern
  6015. )
  6016. {
  6017. UINT i,j;
  6018. if (!ParsedPattern) {
  6019. return FALSE;
  6020. }
  6021. for (i=0; i<ParsedPattern->PatternCount; i++) {
  6022. if (ParsedPattern->Pattern[i].SegmentCount < 1) {
  6023. return TRUE;
  6024. }
  6025. for (j=0; j<ParsedPattern->Pattern[i].SegmentCount; j++) {
  6026. if ((ParsedPattern->Pattern[i].Segment[j].Type == SEGMENTTYPE_OPTIONAL) ||
  6027. (ParsedPattern->Pattern[i].Segment[j].Type == SEGMENTTYPE_REQUIRED)
  6028. ) {
  6029. return TRUE;
  6030. }
  6031. }
  6032. }
  6033. return FALSE;
  6034. }
  6035. BOOL
  6036. ParsedPatternTrimLastCharA (
  6037. IN OUT PPARSEDPATTERNA ParsedPattern
  6038. )
  6039. {
  6040. if (!ParsedPatternHasRootA (ParsedPattern)) {
  6041. return FALSE;
  6042. }
  6043. ParsedPattern->Pattern->Segment[0].Exact.PhraseBytes -= DWSIZEOF (CHAR);
  6044. *(PSTR)((PBYTE)ParsedPattern->Pattern->Segment[0].Exact.LowerCasePhrase +
  6045. ParsedPattern->Pattern->Segment[0].Exact.PhraseBytes) = 0;
  6046. return TRUE;
  6047. }
  6048. BOOL
  6049. ParsedPatternTrimLastCharW (
  6050. IN OUT PPARSEDPATTERNW ParsedPattern
  6051. )
  6052. {
  6053. if (!ParsedPatternHasRootW (ParsedPattern)) {
  6054. return FALSE;
  6055. }
  6056. ParsedPattern->Pattern->Segment[0].Exact.PhraseBytes -= DWSIZEOF (WCHAR);
  6057. *(PWSTR)((PBYTE)ParsedPattern->Pattern->Segment[0].Exact.LowerCasePhrase +
  6058. ParsedPattern->Pattern->Segment[0].Exact.PhraseBytes) = 0;
  6059. return TRUE;
  6060. }
  6061. VOID
  6062. UBINTtoHexA (
  6063. IN UBINT Number,
  6064. OUT PSTR String
  6065. )
  6066. {
  6067. #ifdef IA64
  6068. sprintf (String, "0x%08X%08X", (DWORD)(Number >> 32), (DWORD)Number);
  6069. #else
  6070. sprintf (String, "0x00000000%08X", Number);
  6071. #endif
  6072. }
  6073. VOID
  6074. UBINTtoHexW (
  6075. IN UBINT Number,
  6076. OUT PWSTR String
  6077. )
  6078. {
  6079. #ifdef IA64
  6080. swprintf (String, L"0x%08X%08X", (DWORD)(Number >> 32), (DWORD)Number);
  6081. #else
  6082. swprintf (String, L"0x00000000%08X", Number);
  6083. #endif
  6084. }
  6085. VOID
  6086. UBINTtoDecA (
  6087. IN UBINT Number,
  6088. OUT PSTR String
  6089. )
  6090. {
  6091. #ifdef IA64
  6092. sprintf (String, "%I64u", Number);
  6093. #else
  6094. sprintf (String, "%lu", Number);
  6095. #endif
  6096. }
  6097. VOID
  6098. UBINTtoDecW (
  6099. IN UBINT Number,
  6100. OUT PWSTR String
  6101. )
  6102. {
  6103. #ifdef IA64
  6104. swprintf (String, L"%I64u", Number);
  6105. #else
  6106. swprintf (String, L"%lu", Number);
  6107. #endif
  6108. }
  6109. VOID
  6110. BINTtoDecA (
  6111. IN BINT Number,
  6112. OUT PSTR String
  6113. )
  6114. {
  6115. #ifdef IA64
  6116. sprintf (String, "%I64d", Number);
  6117. #else
  6118. sprintf (String, "%ld", Number);
  6119. #endif
  6120. }
  6121. VOID
  6122. BINTtoDecW (
  6123. IN BINT Number,
  6124. OUT PWSTR String
  6125. )
  6126. {
  6127. #ifdef IA64
  6128. swprintf (String, L"%I64d", Number);
  6129. #else
  6130. swprintf (String, L"%ld", Number);
  6131. #endif
  6132. }
  6133. VOID
  6134. PrintPattern (
  6135. IN PCSTR PatStr,
  6136. IN PPARSEDPATTERNA Struct
  6137. )
  6138. /*++
  6139. Routine Description:
  6140. PrintPattern is used for debugging the pattern parsing and testing
  6141. functions.
  6142. Arguments:
  6143. PatStr - Specifies the original pattern string (which is printed as a
  6144. heading)
  6145. Struct - Specifies the parsed pattern struct
  6146. Return Value:
  6147. None.
  6148. --*/
  6149. {
  6150. CHAR poolStr [sizeof (UBINT) * 2 + 2 + 1];
  6151. UINT u, v;
  6152. printf ("Pattern: %s\n\n", PatStr);
  6153. if (!Struct) {
  6154. printf ("Invalid Pattern\n\n");
  6155. return;
  6156. }
  6157. printf ("PatternCount: %u\n", Struct->PatternCount);
  6158. UBINTtoHexA ((UBINT)Struct->Pool, poolStr);
  6159. printf ("Pool: %s\n", poolStr);
  6160. for (u = 0 ; u < Struct->PatternCount ; u++) {
  6161. printf (" Segment Count: %u\n", Struct->Pattern[u].SegmentCount);
  6162. for (v = 0 ; v < Struct->Pattern->SegmentCount ; v++) {
  6163. printf (" Type: ");
  6164. switch (Struct->Pattern[u].Segment[v].Type) {
  6165. case SEGMENTTYPE_EXACTMATCH:
  6166. printf ("SEGMENTTYPE_EXACTMATCH\n");
  6167. printf (" String: %s\n", Struct->Pattern[u].Segment[v].Exact.LowerCasePhrase);
  6168. printf (" Bytes: %u\n", Struct->Pattern[u].Segment[v].Exact.PhraseBytes);
  6169. break;
  6170. case SEGMENTTYPE_OPTIONAL:
  6171. printf ("SEGMENTTYPE_OPTIONAL\n");
  6172. printf (" MaxLen: %u\n", Struct->Pattern[u].Segment[v].Wildcard.MaxLen);
  6173. printf (" IncludeSet: %s\n", Struct->Pattern[u].Segment[v].Wildcard.IncludeSet);
  6174. printf (" ExcludeSet: %s\n", Struct->Pattern[u].Segment[v].Wildcard.ExcludeSet);
  6175. break;
  6176. case SEGMENTTYPE_REQUIRED:
  6177. printf ("SEGMENTTYPE_REQUIRED\n");
  6178. printf (" MaxLen: %u\n", Struct->Pattern[u].Segment[v].Wildcard.MaxLen);
  6179. printf (" IncludeSet: %s\n", Struct->Pattern[u].Segment[v].Wildcard.IncludeSet);
  6180. printf (" ExcludeSet: %s\n", Struct->Pattern[u].Segment[v].Wildcard.ExcludeSet);
  6181. break;
  6182. } //lint !e744
  6183. }
  6184. }
  6185. printf ("\n");
  6186. }
  6187. /*++
  6188. Routine Description:
  6189. TestParsedPattern finds the end of the string to test and calls
  6190. TestParsedPatternAB.
  6191. Arguments:
  6192. ParsedPattern - Specifies the parsed pattern structure as returned by
  6193. CreateParsedPattern
  6194. StringToTest - Specifies the string to test against the pattern
  6195. Return Value:
  6196. TRUE if the string fits the pattern, FALSE if it does not
  6197. --*/
  6198. BOOL
  6199. TestParsedPatternA (
  6200. IN PPARSEDPATTERNA ParsedPattern,
  6201. IN PCSTR StringToTest
  6202. )
  6203. {
  6204. PCSTR EndPlusOne = GetEndOfStringA (StringToTest);
  6205. return TestParsedPatternABA (ParsedPattern, StringToTest, EndPlusOne);
  6206. }
  6207. BOOL
  6208. TestParsedPatternW (
  6209. IN PPARSEDPATTERNW ParsedPattern,
  6210. IN PCWSTR StringToTest
  6211. )
  6212. {
  6213. PCWSTR EndPlusOne = GetEndOfStringW (StringToTest);
  6214. return TestParsedPatternABW (ParsedPattern, StringToTest, EndPlusOne);
  6215. }
  6216. /*++
  6217. Routine Description:
  6218. pTestSet tests a character against an include and exclude set. The sets are
  6219. formatted in pairs of characters, where the first character in the pair is
  6220. the low range, and the second character in the pair is the high range. The
  6221. specified character will automatically be lower-cased, and all whitespace
  6222. characters are tested against the space character (ascii 32).
  6223. Arguments:
  6224. ch - Specifies the character to test. This character is converted
  6225. to lower case before the test.
  6226. IncludeSet - Specifies the set of characters that ch must be a member of.
  6227. If NULL is specified, then the include set is all characters.
  6228. ExcludeSet - Specifies the range of characters that ch cannot be a member
  6229. of. If NULL is specified, then no characters are excluded.
  6230. Return Value:
  6231. TRUE if ch is in the include set and not in the exclude set; FALSE
  6232. otherwise.
  6233. --*/
  6234. BOOL
  6235. pTestSetA (
  6236. IN MBCHAR ch,
  6237. IN PCSTR IncludeSet, OPTIONAL
  6238. IN PCSTR ExcludeSet OPTIONAL
  6239. )
  6240. {
  6241. MBCHAR LowChar, HighChar;
  6242. BOOL b = TRUE;
  6243. if (_ismbcspace ((MBCHAR)ch)) {
  6244. if (ch != ' ') {
  6245. if (pTestSetA (' ', IncludeSet, ExcludeSet)) {
  6246. return TRUE;
  6247. }
  6248. }
  6249. } else {
  6250. ch = OURTOLOWER (ch);
  6251. }
  6252. if (IncludeSet) {
  6253. b = FALSE;
  6254. while (*IncludeSet) {
  6255. LowChar = _mbsnextc (IncludeSet);
  6256. IncludeSet = _mbsinc (IncludeSet);
  6257. HighChar = _mbsnextc (IncludeSet);
  6258. IncludeSet = _mbsinc (IncludeSet);
  6259. if (ch >= LowChar && ch <= HighChar) {
  6260. b = TRUE;
  6261. break;
  6262. }
  6263. }
  6264. }
  6265. if (b && ExcludeSet) {
  6266. while (*ExcludeSet) {
  6267. LowChar = _mbsnextc (ExcludeSet);
  6268. ExcludeSet = _mbsinc (ExcludeSet);
  6269. HighChar = _mbsnextc (ExcludeSet);
  6270. ExcludeSet = _mbsinc (ExcludeSet);
  6271. if (ch >= LowChar && ch <= HighChar) {
  6272. b = FALSE;
  6273. break;
  6274. }
  6275. }
  6276. }
  6277. return b;
  6278. }
  6279. BOOL
  6280. pTestSetW (
  6281. IN WCHAR ch,
  6282. IN PCWSTR IncludeSet, OPTIONAL
  6283. IN PCWSTR ExcludeSet OPTIONAL
  6284. )
  6285. {
  6286. WCHAR LowChar, HighChar;
  6287. BOOL b = TRUE;
  6288. if (iswspace (ch)) {
  6289. if (ch != L' ') {
  6290. if (pTestSetW (L' ', IncludeSet, ExcludeSet)) {
  6291. return TRUE;
  6292. }
  6293. }
  6294. } else {
  6295. ch = towlower (ch);
  6296. }
  6297. if (IncludeSet) {
  6298. b = FALSE;
  6299. while (*IncludeSet) {
  6300. LowChar = *IncludeSet++;
  6301. HighChar = *IncludeSet++;
  6302. if (ch >= LowChar && ch <= HighChar) {
  6303. b = TRUE;
  6304. break;
  6305. }
  6306. }
  6307. }
  6308. if (b && ExcludeSet) {
  6309. while (*ExcludeSet) {
  6310. LowChar = *ExcludeSet++;
  6311. HighChar = *ExcludeSet++;
  6312. if (ch >= LowChar && ch <= HighChar) {
  6313. b = FALSE;
  6314. break;
  6315. }
  6316. }
  6317. }
  6318. return b;
  6319. }
  6320. /*++
  6321. Routine Description:
  6322. pTestOnePatternAB tests a string against a parsed pattern. It loops through
  6323. each segment in the pattern, and calls itself recursively in certain
  6324. circumstances.
  6325. Arguments:
  6326. Pattern - Specifies the parsed pattern, as returned from
  6327. CreateParsedPattern
  6328. StartSeg - Specifies the segment within Pattern to start testing. This
  6329. is used for recursion and outside callers should pass in 0.
  6330. StringToTest - Specifies the string to test against Pattern. In recursion,
  6331. this member will be a pointer to the start of the sub string
  6332. to test.
  6333. EndPlusOne - Specifies one character beyond the end of the string. This
  6334. typically points to the nul terminator.
  6335. Return Value:
  6336. TRUE if the string between StringToTest and EndPlusOne fits Pattern. FALSE
  6337. otherwise.
  6338. --*/
  6339. BOOL
  6340. pTestOnePatternABA (
  6341. IN PPATTERNPROPSA Pattern,
  6342. IN UINT StartSeg,
  6343. IN PCSTR StringToTest,
  6344. IN PCSTR EndPlusOne
  6345. )
  6346. {
  6347. UINT u;
  6348. PSEGMENTA Segment;
  6349. MBCHAR ch1, ch2;
  6350. PCSTR q;
  6351. PCSTR TempEnd;
  6352. UINT BytesLeft;
  6353. UINT Chars;
  6354. for (u = StartSeg ; u < Pattern->SegmentCount ; u++) {
  6355. Segment = &Pattern->Segment[u];
  6356. switch (Segment->Type) {
  6357. case SEGMENTTYPE_EXACTMATCH:
  6358. //
  6359. // Check if the exact match is long enough, or if
  6360. // the remaining string must match
  6361. //
  6362. BytesLeft = (UINT)((PBYTE) EndPlusOne - (PBYTE) StringToTest);
  6363. if (u + 1 == Pattern->SegmentCount) {
  6364. if (BytesLeft != Segment->Exact.PhraseBytes) {
  6365. return FALSE;
  6366. }
  6367. } else if (BytesLeft < Segment->Exact.PhraseBytes) {
  6368. return FALSE;
  6369. }
  6370. //
  6371. // Compare the strings
  6372. //
  6373. q = Segment->Exact.LowerCasePhrase;
  6374. TempEnd = (PCSTR) ((PBYTE) q + Segment->Exact.PhraseBytes);
  6375. ch1 = 0;
  6376. ch2 = 0;
  6377. while (q < TempEnd) {
  6378. ch1 = _mbsnextc (StringToTest);
  6379. ch2 = _mbsnextc (q);
  6380. ch1 = OURTOLOWER (ch1);
  6381. if (ch1 != ch2) {
  6382. if (ch2 == ' ') {
  6383. if (!_ismbcspace ((MBCHAR)ch1)) {
  6384. break;
  6385. }
  6386. } else {
  6387. break;
  6388. }
  6389. }
  6390. q = _mbsinc (q);
  6391. StringToTest = _mbsinc (StringToTest);
  6392. }
  6393. if (ch1 != ch2) {
  6394. return FALSE;
  6395. }
  6396. //
  6397. // Continue onto next segment
  6398. //
  6399. break;
  6400. case SEGMENTTYPE_REQUIRED:
  6401. MYASSERT (Segment->Wildcard.MaxLen > 0);
  6402. //
  6403. // Verify there are the correct number of characters
  6404. // in the specified char set
  6405. //
  6406. Chars = Segment->Wildcard.MaxLen;
  6407. if (Segment->Wildcard.IncludeSet || Segment->Wildcard.ExcludeSet) {
  6408. while (StringToTest < EndPlusOne && Chars > 0) {
  6409. if (!pTestSetA (
  6410. _mbsnextc (StringToTest),
  6411. Segment->Wildcard.IncludeSet,
  6412. Segment->Wildcard.ExcludeSet
  6413. )) {
  6414. return FALSE;
  6415. }
  6416. Chars--;
  6417. StringToTest = _mbsinc (StringToTest);
  6418. }
  6419. } else {
  6420. while (StringToTest < EndPlusOne && Chars > 0) {
  6421. Chars--;
  6422. StringToTest = _mbsinc (StringToTest);
  6423. }
  6424. }
  6425. if (Chars) {
  6426. return FALSE;
  6427. }
  6428. if (u + 1 == Pattern->SegmentCount) {
  6429. if (*StringToTest) {
  6430. return FALSE;
  6431. }
  6432. }
  6433. //
  6434. // Continue onto next segment
  6435. //
  6436. break;
  6437. case SEGMENTTYPE_OPTIONAL:
  6438. if (Segment->Wildcard.MaxLen == 0) {
  6439. //
  6440. // Last segment is "anything"
  6441. //
  6442. if (u + 1 == Pattern->SegmentCount &&
  6443. !Segment->Wildcard.IncludeSet &&
  6444. !Segment->Wildcard.ExcludeSet
  6445. ) {
  6446. return TRUE;
  6447. }
  6448. }
  6449. //
  6450. // Find end of optional text
  6451. //
  6452. TempEnd = StringToTest;
  6453. Chars = Segment->Wildcard.MaxLen;
  6454. if (Segment->Wildcard.IncludeSet || Segment->Wildcard.ExcludeSet) {
  6455. if (Chars) {
  6456. while (TempEnd < EndPlusOne && Chars > 0) {
  6457. if (!pTestSetA (
  6458. _mbsnextc (TempEnd),
  6459. Segment->Wildcard.IncludeSet,
  6460. Segment->Wildcard.ExcludeSet
  6461. )) {
  6462. break;
  6463. }
  6464. TempEnd = _mbsinc (TempEnd);
  6465. Chars--;
  6466. }
  6467. } else {
  6468. while (TempEnd < EndPlusOne) {
  6469. if (!pTestSetA (
  6470. _mbsnextc (TempEnd),
  6471. Segment->Wildcard.IncludeSet,
  6472. Segment->Wildcard.ExcludeSet
  6473. )) {
  6474. break;
  6475. }
  6476. TempEnd = _mbsinc (TempEnd);
  6477. }
  6478. }
  6479. } else if (Chars) {
  6480. while (TempEnd < EndPlusOne && Chars > 0) {
  6481. TempEnd = _mbsinc (TempEnd);
  6482. Chars--;
  6483. }
  6484. } else {
  6485. TempEnd = EndPlusOne;
  6486. }
  6487. //
  6488. // If this is the last segment, then match only when
  6489. // the remaining text fits
  6490. //
  6491. if (u + 1 == Pattern->SegmentCount) {
  6492. return TempEnd >= EndPlusOne;
  6493. }
  6494. //
  6495. // Because other segments exist, we must check recursively
  6496. //
  6497. do {
  6498. if (pTestOnePatternABA (Pattern, u + 1, StringToTest, EndPlusOne)) {
  6499. return TRUE;
  6500. }
  6501. StringToTest = _mbsinc (StringToTest);
  6502. } while (StringToTest <= TempEnd);
  6503. //
  6504. // No match
  6505. //
  6506. return FALSE;
  6507. } //lint !e744
  6508. }
  6509. return TRUE;
  6510. }
  6511. BOOL
  6512. pTestOnePatternABW (
  6513. IN PPATTERNPROPSW Pattern,
  6514. IN UINT StartSeg,
  6515. IN PCWSTR StringToTest,
  6516. IN PCWSTR EndPlusOne
  6517. )
  6518. {
  6519. UINT u;
  6520. PSEGMENTW Segment;
  6521. WCHAR ch1, ch2;
  6522. PCWSTR q;
  6523. PCWSTR TempEnd;
  6524. UINT BytesLeft;
  6525. UINT Chars;
  6526. for (u = StartSeg ; u < Pattern->SegmentCount ; u++) {
  6527. Segment = &Pattern->Segment[u];
  6528. switch (Segment->Type) {
  6529. case SEGMENTTYPE_EXACTMATCH:
  6530. //
  6531. // Check if the exact match is long enough, or if
  6532. // the remaining string must match
  6533. //
  6534. BytesLeft = (UINT)((PBYTE) EndPlusOne - (PBYTE) StringToTest);
  6535. if (u + 1 == Pattern->SegmentCount) {
  6536. if (BytesLeft != Segment->Exact.PhraseBytes) {
  6537. return FALSE;
  6538. }
  6539. } else if (BytesLeft < Segment->Exact.PhraseBytes) {
  6540. return FALSE;
  6541. }
  6542. //
  6543. // Compare the strings
  6544. //
  6545. q = Segment->Exact.LowerCasePhrase; //lint !e64
  6546. TempEnd = (PCWSTR) ((PBYTE) q + Segment->Exact.PhraseBytes);
  6547. ch1 = 0;
  6548. ch2 = 0;
  6549. while (q < TempEnd) {
  6550. ch1 = towlower (*StringToTest);
  6551. ch2 = *q;
  6552. if (ch1 != ch2) {
  6553. if (ch2 == L' ') {
  6554. if (!iswspace (ch1)) {
  6555. break;
  6556. }
  6557. } else {
  6558. break;
  6559. }
  6560. }
  6561. q++;
  6562. StringToTest++;
  6563. }
  6564. if (ch1 != ch2) {
  6565. return FALSE;
  6566. }
  6567. //
  6568. // Continue onto next segment
  6569. //
  6570. break;
  6571. case SEGMENTTYPE_REQUIRED:
  6572. MYASSERT (Segment->Wildcard.MaxLen > 0);
  6573. //
  6574. // Verify there are the correct number of characters
  6575. // in the specified char set
  6576. //
  6577. Chars = Segment->Wildcard.MaxLen;
  6578. if (Segment->Wildcard.IncludeSet || Segment->Wildcard.ExcludeSet) {
  6579. while (StringToTest < EndPlusOne && Chars > 0) {
  6580. if (!pTestSetW (
  6581. *StringToTest,
  6582. Segment->Wildcard.IncludeSet, //lint !e64
  6583. Segment->Wildcard.ExcludeSet
  6584. )) { //lint !e64
  6585. return FALSE;
  6586. }
  6587. Chars--;
  6588. StringToTest++;
  6589. }
  6590. if (Chars) {
  6591. return FALSE;
  6592. }
  6593. } else {
  6594. StringToTest += Chars;
  6595. if (StringToTest > EndPlusOne) {
  6596. return FALSE;
  6597. }
  6598. }
  6599. if (u + 1 == Pattern->SegmentCount) {
  6600. if (*StringToTest) {
  6601. return FALSE;
  6602. }
  6603. }
  6604. //
  6605. // Continue onto next segment
  6606. //
  6607. break;
  6608. case SEGMENTTYPE_OPTIONAL:
  6609. if (Segment->Wildcard.MaxLen == 0) {
  6610. //
  6611. // Last segment is "anything"
  6612. //
  6613. if (u + 1 == Pattern->SegmentCount &&
  6614. !Segment->Wildcard.IncludeSet &&
  6615. !Segment->Wildcard.ExcludeSet
  6616. ) {
  6617. return TRUE;
  6618. }
  6619. }
  6620. //
  6621. // Find end of optional text
  6622. //
  6623. TempEnd = StringToTest;
  6624. Chars = Segment->Wildcard.MaxLen;
  6625. if (Segment->Wildcard.IncludeSet || Segment->Wildcard.ExcludeSet) {
  6626. if (Chars) {
  6627. while (TempEnd < EndPlusOne && Chars > 0) {
  6628. if (!pTestSetW (
  6629. *TempEnd,
  6630. Segment->Wildcard.IncludeSet, //lint !e64
  6631. Segment->Wildcard.ExcludeSet
  6632. )) { //lint !e64
  6633. break;
  6634. }
  6635. TempEnd++;
  6636. Chars--;
  6637. }
  6638. } else {
  6639. while (TempEnd < EndPlusOne) {
  6640. if (!pTestSetW (
  6641. *TempEnd,
  6642. Segment->Wildcard.IncludeSet, //lint !e64
  6643. Segment->Wildcard.ExcludeSet
  6644. )) { //lint !e64
  6645. break;
  6646. }
  6647. TempEnd++;
  6648. }
  6649. }
  6650. } else if (Chars) {
  6651. TempEnd += Chars;
  6652. if (TempEnd > EndPlusOne) {
  6653. TempEnd = EndPlusOne;
  6654. }
  6655. } else {
  6656. TempEnd = EndPlusOne;
  6657. }
  6658. //
  6659. // If this is the last segment, then match only when
  6660. // the remaining text fits
  6661. //
  6662. if (u + 1 == Pattern->SegmentCount) {
  6663. return TempEnd >= EndPlusOne;
  6664. }
  6665. //
  6666. // Because other segments exist, we must check recursively
  6667. //
  6668. do {
  6669. if (pTestOnePatternABW (Pattern, u + 1, StringToTest, EndPlusOne)) {
  6670. return TRUE;
  6671. }
  6672. StringToTest++;
  6673. } while (StringToTest <= TempEnd);
  6674. //
  6675. // No match
  6676. //
  6677. return FALSE;
  6678. } //lint !e744
  6679. }
  6680. return TRUE;
  6681. }
  6682. /*++
  6683. Routine Description:
  6684. TestParsedPattternAB loops through all the patterns in ParsedPattern,
  6685. testing the specified string against each. The loop stops at the first
  6686. match.
  6687. Arguments:
  6688. ParsedPattern - Specifies the parsed pattern, as returned from
  6689. CreateParsedPattern
  6690. StringToTest - Specifies the start of the string to test.
  6691. EndPlusOne - Specifies a pointer to the first character after the end of
  6692. the string. This often points to the nul at the end of the
  6693. string. A nul must not exist in between StringToTest and
  6694. EndPlusOne; a nul can only be at *EndPlusOne. A nul is not
  6695. required.
  6696. Return Value:
  6697. TRUE if the string specified between StringToTest and EndPlusOne matches
  6698. Pattern. FALSE otherwise.
  6699. --*/
  6700. BOOL
  6701. TestParsedPatternABA (
  6702. IN PPARSEDPATTERNA ParsedPattern,
  6703. IN PCSTR StringToTest,
  6704. IN PCSTR EndPlusOne
  6705. )
  6706. {
  6707. UINT u;
  6708. BOOL b = FALSE;
  6709. if (!ParsedPattern) {
  6710. return FALSE;
  6711. }
  6712. if (!StringToTest) {
  6713. return FALSE;
  6714. }
  6715. for (u = 0 ; u < ParsedPattern->PatternCount ; u++) {
  6716. b = pTestOnePatternABA (
  6717. &ParsedPattern->Pattern[u],
  6718. 0,
  6719. StringToTest,
  6720. EndPlusOne
  6721. );
  6722. if (b) {
  6723. break;
  6724. }
  6725. }
  6726. return b;
  6727. }
  6728. BOOL
  6729. TestParsedPatternABW (
  6730. IN PPARSEDPATTERNW ParsedPattern,
  6731. IN PCWSTR StringToTest,
  6732. IN PCWSTR EndPlusOne
  6733. )
  6734. {
  6735. UINT u;
  6736. BOOL b = FALSE;
  6737. if (!ParsedPattern) {
  6738. return FALSE;
  6739. }
  6740. if (!StringToTest) {
  6741. return FALSE;
  6742. }
  6743. for (u = 0 ; u < ParsedPattern->PatternCount ; u++) {
  6744. b = pTestOnePatternABW (
  6745. &ParsedPattern->Pattern[u],
  6746. 0,
  6747. StringToTest,
  6748. EndPlusOne
  6749. );
  6750. if (b) {
  6751. break;
  6752. }
  6753. }
  6754. return b;
  6755. }
  6756. /*++
  6757. Routine Description:
  6758. DestroyParsedPattern cleans up a pattern allocated from CreateParsedPattern.
  6759. Arguments:
  6760. ParsedPattern - Specifies the value returned from CreateParsedPattern.
  6761. Return Value:
  6762. None.
  6763. --*/
  6764. VOID
  6765. DestroyParsedPatternA (
  6766. IN PPARSEDPATTERNA ParsedPattern
  6767. )
  6768. {
  6769. if (ParsedPattern && (!ParsedPattern->ExternalPool)) {
  6770. PmEmptyPool (ParsedPattern->Pool);
  6771. PmDestroyPool (ParsedPattern->Pool);
  6772. }
  6773. }
  6774. VOID
  6775. DestroyParsedPatternW (
  6776. IN PPARSEDPATTERNW ParsedPattern
  6777. )
  6778. {
  6779. if (ParsedPattern && (!ParsedPattern->ExternalPool)) {
  6780. PmEmptyPool (ParsedPattern->Pool);
  6781. PmDestroyPool (ParsedPattern->Pool);
  6782. }
  6783. }
  6784. /*++
  6785. Routine Description:
  6786. DecodeParsedPattern decodes all exact-matches sub-strings of the given pattern.
  6787. Arguments:
  6788. ParsedPattern - Specifies the parsed pattern.
  6789. Return Value:
  6790. None.
  6791. --*/
  6792. VOID
  6793. DecodeParsedPatternA (
  6794. IN PPARSEDPATTERNA ParsedPattern
  6795. )
  6796. {
  6797. UINT u;
  6798. UINT v;
  6799. PSTR phrase;
  6800. for (u = 0; u < ParsedPattern->PatternCount; u++) {
  6801. for (v = 0; v < ParsedPattern->Pattern[u].SegmentCount; v++) {
  6802. if (ParsedPattern->Pattern[u].Segment[v].Type == SEGMENTTYPE_EXACTMATCH) {
  6803. phrase = (PSTR)ParsedPattern->Pattern[u].Segment[v].Exact.LowerCasePhrase;
  6804. DecodeRuleCharsA (phrase, phrase);
  6805. ParsedPattern->Pattern[u].Segment[v].Exact.PhraseBytes = ByteCountA (phrase);
  6806. }
  6807. }
  6808. }
  6809. }
  6810. VOID
  6811. DecodeParsedPatternW (
  6812. IN PPARSEDPATTERNW ParsedPattern
  6813. )
  6814. {
  6815. UINT u;
  6816. UINT v;
  6817. PWSTR phrase;
  6818. for (u = 0; u < ParsedPattern->PatternCount; u++) {
  6819. for (v = 0; v < ParsedPattern->Pattern[u].SegmentCount; v++) {
  6820. if (ParsedPattern->Pattern[u].Segment[v].Type == SEGMENTTYPE_EXACTMATCH) {
  6821. phrase = (PWSTR)ParsedPattern->Pattern[u].Segment[v].Exact.LowerCasePhrase;
  6822. DecodeRuleCharsW (phrase, phrase);
  6823. ParsedPattern->Pattern[u].Segment[v].Exact.PhraseBytes = ByteCountW (phrase);
  6824. }
  6825. }
  6826. }
  6827. }
  6828. /*++
  6829. Routine Description:
  6830. GetParsedPatternMinMaxSize returns the minimum and the maximum size (in bytes)
  6831. of a string that would match the given parsed pattern.
  6832. Arguments:
  6833. ParsedPattern - Specifies the parsed pattern
  6834. MinSize - Receives the minimum size of a string that would match the pattern
  6835. MaxSize - Receives the maximum size of a string that would match the pattern
  6836. Return Value:
  6837. None.
  6838. --*/
  6839. VOID
  6840. GetParsedPatternMinMaxSizeA (
  6841. IN PPARSEDPATTERNA ParsedPattern,
  6842. OUT PDWORD MinSize,
  6843. OUT PDWORD MaxSize
  6844. )
  6845. {
  6846. UINT u;
  6847. UINT v;
  6848. DWORD pmin;
  6849. DWORD pmax;
  6850. DWORD smin;
  6851. DWORD smax;
  6852. *MinSize = *MaxSize = 0;
  6853. for (u = 0; u < ParsedPattern->PatternCount; u++) {
  6854. pmin = pmax = 0;
  6855. for (v = 0; v < ParsedPattern->Pattern[u].SegmentCount; v++) {
  6856. switch (ParsedPattern->Pattern[u].Segment[v].Type) {
  6857. case SEGMENTTYPE_EXACTMATCH:
  6858. smin = smax = ParsedPattern->Pattern[u].Segment[v].Exact.PhraseBytes;
  6859. break;
  6860. case SEGMENTTYPE_OPTIONAL:
  6861. smin = 0;
  6862. if (ParsedPattern->Pattern[u].Segment[v].Wildcard.MaxLen) {
  6863. smax = ParsedPattern->Pattern[u].Segment[v].Wildcard.MaxLen * DWSIZEOF (CHAR);
  6864. } else {
  6865. smax = DWORD_MAX;
  6866. }
  6867. break;
  6868. case SEGMENTTYPE_REQUIRED:
  6869. MYASSERT (ParsedPattern->Pattern[u].Segment[v].Wildcard.MaxLen > 0);
  6870. smin = smax = ParsedPattern->Pattern[u].Segment[v].Wildcard.MaxLen * DWSIZEOF (CHAR);
  6871. break;
  6872. default:
  6873. MYASSERT (FALSE); //lint !e506
  6874. smin = smax = 0;
  6875. }
  6876. pmin += smin;
  6877. if (pmax < DWORD_MAX) {
  6878. if (smax < DWORD_MAX) {
  6879. pmax += smax;
  6880. } else {
  6881. pmax = DWORD_MAX;
  6882. }
  6883. }
  6884. }
  6885. if (pmin < *MinSize) {
  6886. *MinSize = pmin;
  6887. }
  6888. if (pmax > *MaxSize) {
  6889. *MaxSize = pmax;
  6890. }
  6891. }
  6892. }
  6893. VOID
  6894. GetParsedPatternMinMaxSizeW (
  6895. IN PPARSEDPATTERNW ParsedPattern,
  6896. OUT PDWORD MinSize,
  6897. OUT PDWORD MaxSize
  6898. )
  6899. {
  6900. UINT u;
  6901. UINT v;
  6902. DWORD pmin;
  6903. DWORD pmax;
  6904. DWORD smin;
  6905. DWORD smax;
  6906. *MinSize = *MaxSize = 0;
  6907. for (u = 0; u < ParsedPattern->PatternCount; u++) {
  6908. pmin = pmax = 0;
  6909. for (v = 0; v < ParsedPattern->Pattern[u].SegmentCount; v++) {
  6910. switch (ParsedPattern->Pattern[u].Segment[v].Type) {
  6911. case SEGMENTTYPE_EXACTMATCH:
  6912. smin = smax = ParsedPattern->Pattern[u].Segment[v].Exact.PhraseBytes;
  6913. break;
  6914. case SEGMENTTYPE_OPTIONAL:
  6915. smin = 0;
  6916. if (ParsedPattern->Pattern[u].Segment[v].Wildcard.MaxLen) {
  6917. smax = ParsedPattern->Pattern[u].Segment[v].Wildcard.MaxLen * DWSIZEOF (WCHAR);
  6918. } else {
  6919. smax = DWORD_MAX;
  6920. }
  6921. break;
  6922. case SEGMENTTYPE_REQUIRED:
  6923. MYASSERT (ParsedPattern->Pattern[u].Segment[v].Wildcard.MaxLen > 0);
  6924. smin = smax = ParsedPattern->Pattern[u].Segment[v].Wildcard.MaxLen * DWSIZEOF (WCHAR);
  6925. break;
  6926. default:
  6927. MYASSERT (FALSE); //lint !e506
  6928. smin = smax = 0;
  6929. }
  6930. pmin += smin;
  6931. if (pmax < DWORD_MAX) {
  6932. if (smax < DWORD_MAX) {
  6933. pmax += smax;
  6934. } else {
  6935. pmax = DWORD_MAX;
  6936. }
  6937. }
  6938. }
  6939. if (pmin < *MinSize) {
  6940. *MinSize = pmin;
  6941. }
  6942. if (pmax > *MaxSize) {
  6943. *MaxSize = pmax;
  6944. }
  6945. }
  6946. }
  6947. /*++
  6948. Routine Description:
  6949. PatternIncludesPattern decides if a given pattern includes another pattern,
  6950. meaning that any string that would match the second will match the first.
  6951. Arguments:
  6952. IncludingPattern - Specifies the first parsed pattern
  6953. IncludedPattern - Specifies the second parsed pattern
  6954. Return Value:
  6955. TRUE if the first pattern includes the second
  6956. --*/
  6957. BOOL
  6958. PatternIncludesPatternA (
  6959. IN PPARSEDPATTERNA IncludingPattern,
  6960. IN PPARSEDPATTERNA IncludedPattern
  6961. )
  6962. {
  6963. PPATTERNPROPSA pp1;
  6964. PPATTERNPROPSA pp2;
  6965. PSEGMENTA ps1;
  6966. PSEGMENTA ps2;
  6967. DWORD min1;
  6968. DWORD max1;
  6969. DWORD min2;
  6970. DWORD max2;
  6971. //
  6972. // only deal with simple patterns for now (PatternCount == 1)
  6973. //
  6974. if (IncludingPattern->PatternCount > 1 || IncludedPattern->PatternCount > 1) {
  6975. DEBUGMSGA ((DBG_ERROR, "PatternIncludesPatternA: multiple patterns not supported yet"));
  6976. return FALSE;
  6977. }
  6978. //
  6979. // test the usual cases first, quickly
  6980. //
  6981. pp1 = IncludingPattern->Pattern;
  6982. MYASSERT (pp1);
  6983. if (pp1->SegmentCount == 1 && ParsedPatternSegmentIsPureOptionalA (pp1->Segment)) {
  6984. return TRUE;
  6985. }
  6986. pp2 = IncludedPattern->Pattern;
  6987. MYASSERT (pp2);
  6988. if (pp2->SegmentCount == 1 && ParsedPatternSegmentIsPureOptionalA (pp2->Segment)) {
  6989. return FALSE;
  6990. }
  6991. if (pp1->SegmentCount == 1) {
  6992. ps1 = pp1->Segment;
  6993. if (ps1->Type == SEGMENTTYPE_EXACTMATCH) {
  6994. if (pp2->SegmentCount == 1) {
  6995. ps2 = pp2->Segment;
  6996. if (ps2->Type == SEGMENTTYPE_EXACTMATCH) {
  6997. return ps1->Exact.PhraseBytes == ps2->Exact.PhraseBytes &&
  6998. StringMatchA (ps1->Exact.LowerCasePhrase, ps2->Exact.LowerCasePhrase);
  6999. }
  7000. }
  7001. }
  7002. } else if (pp1->SegmentCount == 2) {
  7003. ps1 = pp1->Segment;
  7004. if (ps1->Type == SEGMENTTYPE_EXACTMATCH) {
  7005. if (ParsedPatternSegmentIsPureOptionalA (pp1->Segment + 1)) {
  7006. if (pp2->SegmentCount == 1) {
  7007. ps2 = pp2->Segment;
  7008. if (ps2->Type == SEGMENTTYPE_EXACTMATCH) {
  7009. return ps1->Exact.PhraseBytes <= ps2->Exact.PhraseBytes &&
  7010. StringMatchByteCountA (
  7011. ps1->Exact.LowerCasePhrase,
  7012. ps2->Exact.LowerCasePhrase,
  7013. ps1->Exact.PhraseBytes
  7014. );
  7015. }
  7016. } else if (pp2->SegmentCount == 2) {
  7017. ps2 = pp2->Segment;
  7018. if (ps2->Type == SEGMENTTYPE_EXACTMATCH) {
  7019. if (ParsedPatternSegmentIsPureOptionalA (pp2->Segment + 1)) {
  7020. return ps1->Exact.PhraseBytes <= ps2->Exact.PhraseBytes &&
  7021. StringMatchByteCountA (
  7022. ps1->Exact.LowerCasePhrase,
  7023. ps2->Exact.LowerCasePhrase,
  7024. ps1->Exact.PhraseBytes
  7025. );
  7026. }
  7027. }
  7028. }
  7029. }
  7030. }
  7031. }
  7032. GetParsedPatternMinMaxSizeA (IncludingPattern, &min1, &max1);
  7033. GetParsedPatternMinMaxSizeA (IncludedPattern, &min2, &max2);
  7034. if (min2 < min1 || max2 > max1) {
  7035. return FALSE;
  7036. }
  7037. //
  7038. // NTRAID#NTBUG9-153305-2000/08/01-jimschm Not implemented yet
  7039. //
  7040. return FALSE;
  7041. }
  7042. BOOL
  7043. PatternIncludesPatternW (
  7044. IN PPARSEDPATTERNW IncludingPattern,
  7045. IN PPARSEDPATTERNW IncludedPattern
  7046. )
  7047. {
  7048. PPATTERNPROPSW pp1;
  7049. PPATTERNPROPSW pp2;
  7050. PSEGMENTW ps1;
  7051. PSEGMENTW ps2;
  7052. DWORD min1;
  7053. DWORD max1;
  7054. DWORD min2;
  7055. DWORD max2;
  7056. //
  7057. // only deal with simple patterns for now (PatternCount == 1)
  7058. //
  7059. if (IncludingPattern->PatternCount > 1 || IncludedPattern->PatternCount > 1) {
  7060. DEBUGMSGW ((DBG_ERROR, "PatternIncludesPatternW: multiple patterns not supported yet"));
  7061. return FALSE;
  7062. }
  7063. //
  7064. // test the usual cases first, quickly
  7065. //
  7066. pp1 = IncludingPattern->Pattern;
  7067. MYASSERT (pp1);
  7068. if (pp1->SegmentCount == 1 && ParsedPatternSegmentIsPureOptionalW (pp1->Segment)) {
  7069. return TRUE;
  7070. }
  7071. pp2 = IncludedPattern->Pattern;
  7072. MYASSERT (pp2);
  7073. if (pp2->SegmentCount == 1 && ParsedPatternSegmentIsPureOptionalW (pp2->Segment)) {
  7074. return FALSE;
  7075. }
  7076. if (pp1->SegmentCount == 1) {
  7077. ps1 = pp1->Segment;
  7078. if (ps1->Type == SEGMENTTYPE_EXACTMATCH) {
  7079. if (pp2->SegmentCount == 1) {
  7080. ps2 = pp2->Segment;
  7081. if (ps2->Type == SEGMENTTYPE_EXACTMATCH) {
  7082. return ps1->Exact.PhraseBytes == ps2->Exact.PhraseBytes &&
  7083. StringMatchW (ps1->Exact.LowerCasePhrase, ps2->Exact.LowerCasePhrase); //lint !e64
  7084. }
  7085. }
  7086. }
  7087. } else if (pp1->SegmentCount == 2) {
  7088. ps1 = pp1->Segment;
  7089. if (ps1->Type == SEGMENTTYPE_EXACTMATCH) {
  7090. if (ParsedPatternSegmentIsPureOptionalW (pp1->Segment + 1)) {
  7091. if (pp2->SegmentCount == 1) {
  7092. ps2 = pp2->Segment;
  7093. if (ps2->Type == SEGMENTTYPE_EXACTMATCH) {
  7094. return ps1->Exact.PhraseBytes <= ps2->Exact.PhraseBytes &&
  7095. StringMatchByteCountW (
  7096. ps1->Exact.LowerCasePhrase,
  7097. ps2->Exact.LowerCasePhrase,
  7098. ps1->Exact.PhraseBytes
  7099. ); //lint !e64
  7100. }
  7101. } else if (pp2->SegmentCount == 2) {
  7102. ps2 = pp2->Segment;
  7103. if (ps2->Type == SEGMENTTYPE_EXACTMATCH) {
  7104. if (ParsedPatternSegmentIsPureOptionalW (pp2->Segment + 1)) {
  7105. return ps1->Exact.PhraseBytes <= ps2->Exact.PhraseBytes &&
  7106. StringMatchByteCountW (
  7107. ps1->Exact.LowerCasePhrase,
  7108. ps2->Exact.LowerCasePhrase,
  7109. ps1->Exact.PhraseBytes
  7110. ); //lint !e64
  7111. }
  7112. }
  7113. }
  7114. }
  7115. }
  7116. }
  7117. GetParsedPatternMinMaxSizeW (IncludingPattern, &min1, &max1);
  7118. GetParsedPatternMinMaxSizeW (IncludedPattern, &min2, &max2);
  7119. if (min2 < min1 || max2 > max1) {
  7120. return FALSE;
  7121. }
  7122. //
  7123. // NTRAID#NTBUG9-153305-2000/08/01-jimschm not implemented yet
  7124. //
  7125. return FALSE;
  7126. }
  7127. VOID
  7128. _copymbchar (
  7129. OUT PSTR sz1,
  7130. IN PCSTR sz2
  7131. )
  7132. /*++
  7133. Routine Description:
  7134. _copymbchar transfers the character at sz2 to sz1, which may be one or
  7135. two bytes long.
  7136. Arguments:
  7137. sz1 - The destination string
  7138. sz2 - The source string
  7139. Return Value:
  7140. none
  7141. --*/
  7142. {
  7143. if (IsLeadByte (sz2)) {
  7144. sz1[1] = sz2[1];
  7145. }
  7146. *sz1 = *sz2;
  7147. }
  7148. /*++
  7149. Routine Description:
  7150. _tcsctrim removes character c from the end of str if it exists. It removes
  7151. only one character at the most.
  7152. Arguments:
  7153. str - A pointer to the string that may have character c at the end
  7154. c - The character that may be at the end of the string
  7155. Return Value:
  7156. TRUE if character c was at the end of the string, or FALSE if it was not.
  7157. --*/
  7158. BOOL
  7159. _mbsctrim (
  7160. OUT PSTR str,
  7161. IN MBCHAR c
  7162. )
  7163. {
  7164. PSTR end;
  7165. end = GetEndOfStringA (str);
  7166. end = _mbsdec2 (str, end);
  7167. if (end && _mbsnextc (end) == c) {
  7168. *end = 0;
  7169. return TRUE;
  7170. }
  7171. return FALSE;
  7172. }
  7173. BOOL
  7174. _wcsctrim (
  7175. OUT PWSTR str,
  7176. IN WCHAR c
  7177. )
  7178. {
  7179. PWSTR end;
  7180. end = GetEndOfStringW (str);
  7181. end == str ? end = NULL : end--;
  7182. if (end && *end == c) {
  7183. *end = 0;
  7184. return TRUE;
  7185. }
  7186. return FALSE;
  7187. }
  7188. /*++
  7189. Routine Description:
  7190. The FreeStringResourceEx functions are used to free a recently used
  7191. string that is not being passed back to the caller. In almost all
  7192. cases, this string is at the end of our array of pointers, so we can
  7193. efficiently search sequentially in reverse order. If the pointer is
  7194. not the last element of the array, it is first swapped with the real
  7195. last element of the array so the array size is reduced.
  7196. Arguments:
  7197. AllocTable - The GROWBUFFER table that holds the list of previously
  7198. allocated strings (return values of ParseMessageEx or
  7199. GetResourceStringEx).
  7200. String - A pointer to the string that is in AllocTable
  7201. Return Value:
  7202. none
  7203. --*/
  7204. VOID
  7205. FreeStringResourceExA (
  7206. IN PGROWBUFFER AllocTable,
  7207. IN PCSTR String
  7208. )
  7209. {
  7210. PCSTR *ptr, *end, *start;
  7211. if (!String) {
  7212. return;
  7213. }
  7214. //
  7215. // Locate string (search sequentially in reverse order)
  7216. //
  7217. if (AllocTable->End < sizeof (PCSTR)) {
  7218. DEBUGMSG ((DBG_ERROR, "FreeStringResourceA: Attempt to free address %x (%s); address table empty", String, String));
  7219. return;
  7220. }
  7221. start = (PCSTR *) AllocTable->Buf;
  7222. end = (PCSTR *) (AllocTable->Buf + AllocTable->End - sizeof (PCSTR));
  7223. ptr = end;
  7224. while (ptr >= start) {
  7225. if (*ptr == String) {
  7226. break;
  7227. }
  7228. ptr--;
  7229. }
  7230. //
  7231. // String not found case
  7232. //
  7233. if (ptr < start) {
  7234. DEBUGMSG ((DBG_ERROR, "FreeStringResourceA: Attempt to free address %x (%s); address not found in table", String, String));
  7235. return;
  7236. }
  7237. //
  7238. // Free LocalAlloc'd memory
  7239. //
  7240. LocalFree ((HLOCAL) String);
  7241. //
  7242. // If this element is not the end, copy real end to the ptr
  7243. //
  7244. if (ptr < end) {
  7245. *ptr = *end;
  7246. }
  7247. //
  7248. // Shrink buffer size
  7249. //
  7250. AllocTable->End -= sizeof (PCSTR);
  7251. }
  7252. VOID
  7253. FreeStringResourcePtrExA (
  7254. IN PGROWBUFFER AllocTable,
  7255. IN OUT PCSTR * String
  7256. )
  7257. {
  7258. if (NULL != *String) {
  7259. FreeStringResourceExA(AllocTable, *String);
  7260. *String = NULL;
  7261. }
  7262. }
  7263. VOID
  7264. FreeStringResourceExW (
  7265. IN PGROWBUFFER AllocTable,
  7266. IN PCWSTR String
  7267. )
  7268. {
  7269. FreeStringResourceExA (AllocTable, (PCSTR) String);
  7270. }
  7271. VOID
  7272. FreeStringResourcePtrExW (
  7273. IN PGROWBUFFER AllocTable,
  7274. IN OUT PCWSTR * String
  7275. )
  7276. {
  7277. if (NULL != *String) {
  7278. FreeStringResourceExW(AllocTable, *String);
  7279. *String = NULL;
  7280. }
  7281. }
  7282. /*++
  7283. Routine Description:
  7284. The pAddStringResource function is used to track pointers allocated
  7285. by FormatMessage. They are added to an array (maintained in a GROWBUFFER
  7286. structure). This table of pointers is used by FreeStringResource or
  7287. StringResourceFree.
  7288. Arguments:
  7289. String - A pointer to a LocalAlloc'd string (the return value of
  7290. FormatMessage). This string is added to a table of allocated
  7291. strings.
  7292. Return Value:
  7293. none
  7294. --*/
  7295. VOID
  7296. pAddStringResource (
  7297. IN PGROWBUFFER GrowBuf,
  7298. IN PCSTR String
  7299. )
  7300. {
  7301. PCSTR *ptr;
  7302. ptr = (PCSTR *) GbGrow (GrowBuf, sizeof (PCSTR));
  7303. if (ptr) {
  7304. *ptr = String;
  7305. }
  7306. ELSE_DEBUGMSG ((DBG_ERROR, "pAddStringResource: GrowBuffer failure caused memory leak"));
  7307. }
  7308. /*++
  7309. Routine Description:
  7310. pFreeAllStringResourcesEx frees all strings currently listed in AllocTable.
  7311. This function allows the caller to wait until all processing is done
  7312. to clean up string resources that may have been allocated.
  7313. Arguments:
  7314. none
  7315. Return Value:
  7316. none
  7317. --*/
  7318. VOID
  7319. pFreeAllStringResourcesEx (
  7320. IN PGROWBUFFER AllocTable
  7321. )
  7322. {
  7323. PCSTR *ptr, *start, *end;
  7324. if (AllocTable->End) {
  7325. start = (PCSTR *) AllocTable->Buf;
  7326. end = (PCSTR *) (AllocTable->Buf + AllocTable->End);
  7327. for (ptr = start ; ptr < end ; ptr++) {
  7328. LocalFree ((HLOCAL) (*ptr));
  7329. }
  7330. }
  7331. GbFree (AllocTable);
  7332. }
  7333. /*++
  7334. Routine Description:
  7335. CreateAllocTable creates a GROWBUFFER structure that can be used with
  7336. ParseMessageEx, GetStringResourceEx, FreeStringResourceEx and
  7337. pFreeAllStringResourcesEx. Call this function to recieve a private
  7338. allocation table to pass to these functions. Call DestroyAllocTable
  7339. to clean up.
  7340. Arguments:
  7341. none
  7342. Return Value:
  7343. A pointer to a GROWBUFFER structure, or NULL if a memory allocation failed.
  7344. --*/
  7345. PGROWBUFFER
  7346. RealCreateAllocTable (
  7347. VOID
  7348. )
  7349. {
  7350. PGROWBUFFER allocTable;
  7351. GROWBUFFER tempForInit = INIT_GROWBUFFER;
  7352. allocTable = (PGROWBUFFER) MemAlloc (g_hHeap, 0, sizeof (GROWBUFFER));
  7353. CopyMemory (allocTable, &tempForInit, sizeof (GROWBUFFER));
  7354. return allocTable;
  7355. }
  7356. /*++
  7357. Routine Description:
  7358. DestroyAllocTable cleans up all memory associated with an AllocTable.
  7359. Arguments:
  7360. AllocTable - A pointer to a GROWBUFFER structure allocated by CreateAllocTable
  7361. Return Value:
  7362. none
  7363. --*/
  7364. VOID
  7365. DestroyAllocTable (
  7366. OUT PGROWBUFFER AllocTable
  7367. )
  7368. {
  7369. MYASSERT (AllocTable);
  7370. pFreeAllStringResourcesEx (AllocTable);
  7371. MemFree (g_hHeap, 0, AllocTable);
  7372. }
  7373. /*++
  7374. Routine Description:
  7375. BeginMessageProcessing enters a guarded section of code that plans to use the
  7376. ParseMessage and GetStringResource functions, but needs cleanup at the end
  7377. of processing.
  7378. EndMessageProcessing destroys all memory allocated within the message processing
  7379. block, and leaves the guarded section.
  7380. Arguments:
  7381. none
  7382. Return Value:
  7383. BeginMessageProcessing returns FALSE if an out-of-memory condition occurrs.
  7384. --*/
  7385. BOOL
  7386. BeginMessageProcessing (
  7387. VOID
  7388. )
  7389. {
  7390. if (!TryEnterOurCriticalSection (&g_MessageCs)) {
  7391. DEBUGMSG ((DBG_ERROR, "Thread attempting to enter BeginMessageProcessing while another"
  7392. "thread is processing messages as well."));
  7393. EnterOurCriticalSection (&g_MessageCs);
  7394. }
  7395. g_LastAllocTable = g_ShortTermAllocTable;
  7396. g_ShortTermAllocTable = CreateAllocTable();
  7397. MYASSERT (g_ShortTermAllocTable);
  7398. return TRUE;
  7399. }
  7400. VOID
  7401. EndMessageProcessing (
  7402. VOID
  7403. )
  7404. {
  7405. if (TryEnterOurCriticalSection (&g_MessageCs)) {
  7406. DEBUGMSG ((DBG_ERROR, "Thread attempting to end message processing when it hasn't been started"));
  7407. LeaveOurCriticalSection (&g_MessageCs);
  7408. return;
  7409. }
  7410. DestroyAllocTable (g_ShortTermAllocTable);
  7411. g_ShortTermAllocTable = g_LastAllocTable;
  7412. LeaveOurCriticalSection (&g_MessageCs);
  7413. }
  7414. /*++
  7415. Routine Description:
  7416. ParseMessage is used to obtain a string from the executable's message table
  7417. and parse it with FormatMessage. An array of arguments can be passed by
  7418. the caller. FormatMessage will replace %1 with the first element of the
  7419. array, %2 with the second element, and so on. The array does not need to
  7420. be terminated, and if a message string uses %n, element n must be non-NULL.
  7421. Arguments:
  7422. Template - A string indicating which message to extract, or a WORD value
  7423. cast as a string. (ParseMessageID does this cast via a macro.)
  7424. ArgArray - Optional array of string pointers, where the meaning depends on
  7425. the message string. A reference in the message string to %n
  7426. requires element n of ArgArray to be a valid string pointer.
  7427. Return Value:
  7428. Pointer to the string allocated. Call StringResourceFree to free all
  7429. allocated strings (a one-time cleanup for all strings). The pointer may
  7430. be NULL if the resource does not exist or is empty.
  7431. --*/
  7432. PCSTR
  7433. ParseMessageExA (
  7434. IN PGROWBUFFER AllocTable,
  7435. IN PCSTR Template,
  7436. IN PCSTR ArgArray[]
  7437. )
  7438. {
  7439. PSTR MsgBuf;
  7440. DWORD rc;
  7441. if (SHIFTRIGHT16 ((UBINT)Template)) {
  7442. //
  7443. // From string
  7444. //
  7445. rc = FormatMessageA (
  7446. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  7447. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  7448. FORMAT_MESSAGE_FROM_STRING,
  7449. (LPVOID) Template,
  7450. 0,
  7451. 0,
  7452. (LPVOID) &MsgBuf,
  7453. 0,
  7454. (va_list *) ArgArray
  7455. );
  7456. } else {
  7457. //
  7458. // From resource
  7459. //
  7460. rc = FormatMessageA (
  7461. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  7462. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  7463. FORMAT_MESSAGE_FROM_HMODULE,
  7464. (LPVOID) g_hInst,
  7465. (DWORD)((UBINT)Template),
  7466. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  7467. (LPVOID) &MsgBuf,
  7468. 0,
  7469. (va_list *) ArgArray
  7470. );
  7471. }
  7472. if (rc > 0) {
  7473. pAddStringResource (AllocTable, MsgBuf);
  7474. return MsgBuf;
  7475. }
  7476. return NULL;
  7477. }
  7478. PCWSTR
  7479. ParseMessageExW (
  7480. IN PGROWBUFFER AllocTable,
  7481. IN PCWSTR Template,
  7482. IN PCWSTR ArgArray[]
  7483. )
  7484. {
  7485. PWSTR MsgBuf;
  7486. DWORD rc;
  7487. if (SHIFTRIGHT16 ((UBINT)Template)) {
  7488. //
  7489. // From string
  7490. //
  7491. rc = FormatMessageW (
  7492. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  7493. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  7494. FORMAT_MESSAGE_FROM_STRING,
  7495. (LPVOID) Template,
  7496. 0,
  7497. 0,
  7498. (LPVOID) &MsgBuf,
  7499. 0,
  7500. (va_list *) ArgArray
  7501. );
  7502. } else {
  7503. //
  7504. // From resource
  7505. //
  7506. rc = FormatMessageW (
  7507. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  7508. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  7509. FORMAT_MESSAGE_FROM_HMODULE,
  7510. (LPVOID) g_hInst,
  7511. (DWORD)(UBINT)Template,
  7512. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  7513. (LPVOID) &MsgBuf,
  7514. 0,
  7515. (va_list *) ArgArray
  7516. );
  7517. }
  7518. if (rc > 0) {
  7519. pAddStringResource (AllocTable, (PCSTR) MsgBuf);
  7520. return MsgBuf;
  7521. }
  7522. return NULL;
  7523. }
  7524. /*++
  7525. Routine Description:
  7526. GetStringResourceEx is an argument-less wrapper of ParseMessageEx. It allows
  7527. the caller to specify a message ID and recieve a pointer to the string if
  7528. it exists, and a table to track FormatMessage's allocations.
  7529. Arguments:
  7530. AllocTable - A pointer to a GROWBUFFER structure that is used to maintain
  7531. the handles of allocated strings
  7532. ID - The ID of the message resource to retrieve
  7533. Return Value:
  7534. Pointer to the string allocated. The return pointer may
  7535. be NULL if the resource does not exist or is empty.
  7536. Call FreeStringResource or DestroyAllocTable to clean up AllocTable.
  7537. --*/
  7538. PCSTR
  7539. GetStringResourceExA (
  7540. IN OUT PGROWBUFFER AllocTable,
  7541. IN UINT ID
  7542. )
  7543. {
  7544. return ParseMessageExA (AllocTable, (PSTR) (WORD) ID, NULL);
  7545. }
  7546. PCWSTR
  7547. GetStringResourceExW (
  7548. IN OUT PGROWBUFFER AllocTable,
  7549. IN UINT ID
  7550. )
  7551. {
  7552. return ParseMessageExW (AllocTable, (PWSTR) (WORD) ID, NULL);
  7553. }
  7554. /*++
  7555. Routine Description:
  7556. ParseMessageInWnd is used to exchange a string in a window with one from
  7557. the executable's message table. It is provided for dialog box initialization,
  7558. where a field in the dialog box requires dynamic data. The dialog box
  7559. resource should contain a control with its window text set to the message
  7560. string. Upon processing WM_INITDIALOG, the code should call ParseMessageInWnd,
  7561. supplying the necessary ArgArray, so the dialog box is initialized with
  7562. a dynamic message.
  7563. Arguments:
  7564. hwnd - The handle of a window whose title contains the message string ID
  7565. ArgArray - Optional array of string pointers, where the meaning depends on
  7566. the message string. A reference in the message string to %n
  7567. requires element n of ArgArray to be a valid string pointer.
  7568. Return Value:
  7569. none
  7570. --*/
  7571. VOID
  7572. ParseMessageInWndA (
  7573. IN HWND Hwnd,
  7574. IN PCSTR ArgArray[]
  7575. )
  7576. {
  7577. CHAR buffer[512];
  7578. PCSTR parsedMsg;
  7579. GetWindowTextA (Hwnd, buffer, 512);
  7580. parsedMsg = ParseMessageA (buffer, ArgArray);
  7581. if (parsedMsg) {
  7582. SetWindowTextA (Hwnd, parsedMsg);
  7583. FreeStringResourceA (parsedMsg);
  7584. }
  7585. }
  7586. VOID
  7587. ParseMessageInWndW (
  7588. IN HWND hwnd,
  7589. IN PCWSTR ArgArray[]
  7590. )
  7591. {
  7592. WCHAR buffer[512];
  7593. PCWSTR parsedMsg;
  7594. GetWindowTextW (hwnd, buffer, 512);
  7595. parsedMsg = ParseMessageW (buffer, ArgArray);
  7596. if (parsedMsg) {
  7597. SetWindowTextW (hwnd, parsedMsg);
  7598. FreeStringResourceW (parsedMsg);
  7599. }
  7600. }
  7601. /*++
  7602. Routine Description:
  7603. ResourceMessageBox is used to display a message based on a message resource
  7604. ID.
  7605. Arguments:
  7606. HwndOwner - The handle of the owner of the message box to be displayed
  7607. ID - The identifier of the message resource
  7608. Flags - MessageBox flags (MB_OK, etc.)
  7609. ArgArray - Optional array of string pointers, where the meaning depends on
  7610. the message string. A reference in the message string to %n
  7611. requires element n of ArgArray to be a valid string pointer.
  7612. Return Value:
  7613. The return value of MessageBox (MB_YES, etc.)
  7614. --*/
  7615. INT
  7616. ResourceMessageBoxA (
  7617. IN HWND HwndOwner,
  7618. IN UINT ID,
  7619. IN UINT Flags,
  7620. IN PCSTR ArgArray[]
  7621. )
  7622. {
  7623. PCSTR message;
  7624. PCSTR title;
  7625. int rc;
  7626. message = ParseMessageA ((PSTR)(UBINT)ID, ArgArray);
  7627. if (!message)
  7628. return -1;
  7629. title = GetStringResourceA (MSG_MESSAGEBOX_TITLE);
  7630. rc = MessageBoxA (HwndOwner, message, title, Flags);
  7631. FreeStringResourceA (message);
  7632. if (title) {
  7633. FreeStringResourceA (title);
  7634. }
  7635. return rc;
  7636. }
  7637. INT
  7638. ResourceMessageBoxW (
  7639. IN HWND HwndOwner,
  7640. IN UINT ID,
  7641. IN UINT Flags,
  7642. IN PCWSTR ArgArray[]
  7643. )
  7644. {
  7645. PCWSTR message;
  7646. PCWSTR title;
  7647. int rc;
  7648. message = ParseMessageW ((PWSTR)(UBINT)ID, ArgArray);
  7649. if (!message)
  7650. return -1;
  7651. title = GetStringResourceW (MSG_MESSAGEBOX_TITLE);
  7652. rc = MessageBoxW (HwndOwner, message, title, Flags);
  7653. FreeStringResourceW (message);
  7654. if (title) {
  7655. FreeStringResourceW (title);
  7656. }
  7657. return rc;
  7658. }
  7659. BOOL
  7660. StringReplaceA (
  7661. IN PSTR Buffer,
  7662. IN DWORD MaxSize,
  7663. IN PSTR ReplaceStartPos,
  7664. IN PSTR ReplaceEndPos,
  7665. IN PCSTR NewString
  7666. )
  7667. {
  7668. BOOL rf = FALSE;
  7669. DWORD oldSubStringLength;
  7670. DWORD newSubStringLength;
  7671. DWORD currentStringLength;
  7672. LONG offset;
  7673. PSTR movePosition;
  7674. //
  7675. // Check assumptions.
  7676. //
  7677. MYASSERT(Buffer);
  7678. MYASSERT(ReplaceStartPos && ReplaceStartPos >= Buffer);
  7679. MYASSERT(ReplaceEndPos && ReplaceEndPos >= ReplaceStartPos); //lint !e613
  7680. MYASSERT(NewString);
  7681. //
  7682. // Compute sizes.
  7683. //
  7684. oldSubStringLength = (DWORD)((UBINT)ReplaceEndPos - (UBINT)ReplaceStartPos);
  7685. newSubStringLength = ByteCountA(NewString);
  7686. currentStringLength = SizeOfStringA(Buffer) + 1;
  7687. offset = (LONG)newSubStringLength - (LONG)oldSubStringLength;
  7688. //
  7689. // Make sure there is enough room in the buffer to perform the replace
  7690. // operation.
  7691. //
  7692. if ((LONG)currentStringLength + offset > (LONG)MaxSize) {
  7693. DEBUGMSG((DBG_WARNING,"ERROR: Buffer to small to perform string replacement."));
  7694. rf = FALSE;
  7695. } else {
  7696. //
  7697. // Shift the rest of the buffer to adjust it to the size of the new string.
  7698. //
  7699. if (newSubStringLength > oldSubStringLength) {
  7700. //
  7701. // right shift.
  7702. //
  7703. for (movePosition = Buffer + currentStringLength;
  7704. (UBINT)movePosition >= (UBINT)ReplaceStartPos + oldSubStringLength;
  7705. movePosition--) {
  7706. *(movePosition + offset) = *movePosition;
  7707. }
  7708. } else {
  7709. //
  7710. // left or no shift.
  7711. //
  7712. for(movePosition = ReplaceStartPos + newSubStringLength; //lint !e613
  7713. movePosition < Buffer + currentStringLength;
  7714. movePosition++) {
  7715. *movePosition = *(movePosition - offset);
  7716. }
  7717. }
  7718. //
  7719. // Now, copy in the string.
  7720. //
  7721. CopyMemory (ReplaceStartPos, NewString, newSubStringLength); //lint !e668
  7722. //
  7723. // String replacement completed successfully.
  7724. //
  7725. rf = TRUE;
  7726. }
  7727. return rf;
  7728. }
  7729. BOOL
  7730. StringReplaceW (
  7731. IN PWSTR Buffer,
  7732. IN DWORD MaxSize,
  7733. IN PWSTR ReplaceStartPos,
  7734. IN PWSTR ReplaceEndPos,
  7735. IN PCWSTR NewString
  7736. )
  7737. {
  7738. BOOL rf = FALSE;
  7739. DWORD oldSubStringLength;
  7740. DWORD newSubStringLength;
  7741. DWORD currentStringLength;
  7742. LONG offset;
  7743. PWSTR movePosition;
  7744. //
  7745. // Check assumptions.
  7746. //
  7747. MYASSERT(Buffer);
  7748. MYASSERT(ReplaceStartPos && ReplaceStartPos >= Buffer);
  7749. MYASSERT(ReplaceEndPos && ReplaceEndPos >= ReplaceStartPos); //lint !e613
  7750. MYASSERT(NewString);
  7751. //
  7752. // Compute sizes.
  7753. //
  7754. oldSubStringLength = (DWORD)((UBINT)ReplaceEndPos - (UBINT)ReplaceStartPos);
  7755. newSubStringLength = CharCountW(NewString);
  7756. currentStringLength = CharCountW(Buffer) + 1;
  7757. offset = (LONG)newSubStringLength - (LONG)oldSubStringLength;
  7758. //
  7759. // Make sure there is enough room in the buffer to perform the replace
  7760. // operation.
  7761. //
  7762. if ((LONG)currentStringLength + offset > (LONG)MaxSize) {
  7763. DEBUGMSG((DBG_WARNING,"ERROR: Buffer to small to perform string replacement."));
  7764. rf = FALSE;
  7765. } else {
  7766. //
  7767. // Shift the rest of the buffer to adjust it to the size of the new string.
  7768. //
  7769. if (newSubStringLength > oldSubStringLength) {
  7770. //
  7771. // right shift.
  7772. //
  7773. for (movePosition = Buffer + currentStringLength;
  7774. (UBINT)movePosition >= (UBINT)ReplaceStartPos + oldSubStringLength;
  7775. movePosition--) {
  7776. *(movePosition + offset) = *movePosition;
  7777. }
  7778. } else {
  7779. //
  7780. // left or no shift.
  7781. //
  7782. for (movePosition = ReplaceStartPos + newSubStringLength; //lint !e613
  7783. movePosition < Buffer + currentStringLength;
  7784. movePosition++) {
  7785. *movePosition = *(movePosition - offset);
  7786. }
  7787. }
  7788. //
  7789. // Now, copy in the string.
  7790. //
  7791. wcsncpy(ReplaceStartPos,NewString,newSubStringLength);
  7792. //
  7793. // String replacement completed successfully.
  7794. //
  7795. rf = TRUE;
  7796. }
  7797. return rf;
  7798. }
  7799. /*++
  7800. Routine Description:
  7801. AddInfSectionToHashTable enumerates the specified section and adds each
  7802. item to the string table. An optional callback allows data to be associated
  7803. with each item.
  7804. Arguments:
  7805. Table - Specifies the table that receives new entries
  7806. InfFile - Specifies an open INF handle of the file to read
  7807. Section - Specifies the INF section name to enumerate
  7808. Field - Specifies which field to extract text from. If the field
  7809. exists, it is added to the string table.
  7810. Callback - Specifies optional callback to be called before adding to
  7811. the string table. The callback supplies additional data.
  7812. CallbackParam - Data passed to the callback
  7813. Return Value:
  7814. TRUE if the INF file was processed successfullly, or FALSE if an error
  7815. occurred.
  7816. --*/
  7817. BOOL
  7818. AddInfSectionToHashTableA (
  7819. IN OUT HASHTABLE Table,
  7820. IN HINF InfFile,
  7821. IN PCSTR Section,
  7822. IN DWORD Field,
  7823. IN ADDINFSECTION_PROCA Callback,
  7824. IN PVOID CallbackData
  7825. )
  7826. {
  7827. INFCONTEXT ic;
  7828. LONG rc;
  7829. HASHTABLE ht;
  7830. DWORD reqSize;
  7831. DWORD currentSize = 0;
  7832. PSTR newBuffer, buffer = NULL;
  7833. PVOID data;
  7834. UINT dataSize;
  7835. BOOL b = FALSE;
  7836. //
  7837. // On NT, Setup API is compiled with UNICODE, so the string table
  7838. // functions are UNICODE only.
  7839. //
  7840. if (ISNT()) {
  7841. SetLastError (ERROR_CALL_NOT_IMPLEMENTED);
  7842. return FALSE;
  7843. }
  7844. if (SetupFindFirstLineA (InfFile, Section, NULL, &ic)) {
  7845. do {
  7846. if (!SetupGetStringFieldA (&ic, Field, NULL, 0, &reqSize)) {
  7847. continue;
  7848. }
  7849. if (reqSize > currentSize) {
  7850. reqSize = ((reqSize / 1024) + 1) * 1024;
  7851. if (buffer) {
  7852. newBuffer = (PSTR) MemReAlloc (g_hHeap, 0, buffer, reqSize);
  7853. } else {
  7854. newBuffer = (PSTR) MemAlloc (g_hHeap, 0, reqSize);
  7855. }
  7856. if (!newBuffer) {
  7857. goto cleanup;
  7858. }
  7859. buffer = newBuffer;
  7860. currentSize = reqSize;
  7861. }
  7862. if (!SetupGetStringFieldA (&ic, Field, buffer, currentSize, NULL)) {
  7863. DEBUGMSG ((DBG_ERROR, "AddInfSectionToHashTable: SetupGetStringField failed unexpectedly"));
  7864. continue;
  7865. }
  7866. data = NULL;
  7867. dataSize = 0;
  7868. if (Callback) {
  7869. rc = Callback (buffer, &data, &dataSize, CallbackData);
  7870. if (rc == CALLBACK_STOP) {
  7871. goto cleanup;
  7872. }
  7873. if (rc == CALLBACK_SKIP) {
  7874. continue;
  7875. }
  7876. }
  7877. ht = HtAddStringExA (
  7878. Table,
  7879. buffer,
  7880. data,
  7881. CASE_INSENSITIVE
  7882. );
  7883. if (!ht) {
  7884. goto cleanup;
  7885. }
  7886. } while (SetupFindNextLine (&ic, &ic));
  7887. }
  7888. b = TRUE;
  7889. cleanup:
  7890. if (buffer) {
  7891. PushError();
  7892. MemFree (g_hHeap, 0, buffer);
  7893. PopError();
  7894. }
  7895. return b;
  7896. }
  7897. BOOL
  7898. AddInfSectionToHashTableW (
  7899. IN OUT HASHTABLE Table,
  7900. IN HINF InfFile,
  7901. IN PCWSTR Section,
  7902. IN DWORD Field,
  7903. IN ADDINFSECTION_PROCW Callback,
  7904. IN PVOID CallbackData
  7905. )
  7906. {
  7907. INFCONTEXT ic;
  7908. HASHTABLE ht;
  7909. LONG rc;
  7910. DWORD reqSize;
  7911. DWORD currentSize = 0;
  7912. PWSTR newBuffer, buffer = NULL;
  7913. PVOID data;
  7914. UINT dataSize;
  7915. BOOL b = FALSE;
  7916. //
  7917. // On Win9x, Setup API is compiled with ANSI, so the string table
  7918. // functions are ANSI only.
  7919. //
  7920. if (ISWIN9X()) {
  7921. SetLastError (ERROR_CALL_NOT_IMPLEMENTED);
  7922. return FALSE;
  7923. }
  7924. if (SetupFindFirstLineW (InfFile, Section, NULL, &ic)) {
  7925. do {
  7926. if (!SetupGetStringFieldW (&ic, Field, NULL, 0, &reqSize)) {
  7927. continue;
  7928. }
  7929. if (reqSize > currentSize) {
  7930. reqSize = ((reqSize / 1024) + 1) * 1024;
  7931. if (buffer) {
  7932. newBuffer = (PWSTR) MemReAlloc (g_hHeap, 0, buffer, reqSize);
  7933. } else {
  7934. newBuffer = (PWSTR) MemAlloc (g_hHeap, 0, reqSize);
  7935. }
  7936. if (!newBuffer) {
  7937. goto cleanup;
  7938. }
  7939. buffer = newBuffer;
  7940. currentSize = reqSize;
  7941. }
  7942. if (!SetupGetStringFieldW (&ic, Field, buffer, currentSize, NULL)) {
  7943. DEBUGMSG ((DBG_ERROR, "AddInfSectionToHashTable: SetupGetStringField failed unexpectedly"));
  7944. continue;
  7945. }
  7946. data = NULL;
  7947. dataSize = 0;
  7948. if (Callback) {
  7949. rc = Callback (buffer, &data, &dataSize, CallbackData);
  7950. if (rc == CALLBACK_STOP) {
  7951. goto cleanup;
  7952. }
  7953. if (rc == CALLBACK_SKIP) {
  7954. continue;
  7955. }
  7956. }
  7957. ht = HtAddStringExW (
  7958. Table,
  7959. buffer,
  7960. data,
  7961. CASE_INSENSITIVE
  7962. );
  7963. if (!ht) {
  7964. goto cleanup;
  7965. }
  7966. } while (SetupFindNextLine (&ic, &ic));
  7967. }
  7968. b = TRUE;
  7969. cleanup:
  7970. if (buffer) {
  7971. PushError();
  7972. MemFree (g_hHeap, 0, buffer);
  7973. PopError();
  7974. }
  7975. return b;
  7976. }
  7977. /*++
  7978. Routine Description:
  7979. Finds the last wack in the path and returns a pointer to the next
  7980. character. If no wack is found, returns a pointer to the full
  7981. string.
  7982. Arguments:
  7983. PathSpec - Specifies the path that has a file at the end of it
  7984. Return Value:
  7985. A pointer to the file name in the path.
  7986. --*/
  7987. PCSTR
  7988. GetFileNameFromPathA (
  7989. IN PCSTR PathSpec
  7990. )
  7991. {
  7992. PCSTR p;
  7993. p = _mbsrchr (PathSpec, '\\');
  7994. if (p) {
  7995. p = _mbsinc (p);
  7996. } else {
  7997. p = PathSpec;
  7998. }
  7999. return p;
  8000. }
  8001. PCWSTR
  8002. GetFileNameFromPathW (
  8003. IN PCWSTR PathSpec
  8004. )
  8005. {
  8006. PCWSTR p;
  8007. p = wcsrchr (PathSpec, L'\\');
  8008. if (p) {
  8009. p++;
  8010. } else {
  8011. p = PathSpec;
  8012. }
  8013. return p;
  8014. }
  8015. /*++
  8016. Routine Description:
  8017. Finds the last wack in the path and then the last point from the remaining path
  8018. returning a pointer to the next character. If no point is found, returns a null pointer.
  8019. Arguments:
  8020. PathSpec - Specifies the path that has a file at the end of it
  8021. Return Value:
  8022. A pointer to the file extension, excluding the dot, or NULL if no extension exists.
  8023. --*/
  8024. PCSTR
  8025. GetFileExtensionFromPathA (
  8026. IN PCSTR PathSpec
  8027. )
  8028. {
  8029. PCSTR p;
  8030. PCSTR ReturnPtr = NULL;
  8031. p = PathSpec;
  8032. while (*p) {
  8033. if (*p == '.') {
  8034. ReturnPtr = p + 1;
  8035. } else if (*p == '\\') {
  8036. ReturnPtr = NULL;
  8037. }
  8038. p = _mbsinc (p);
  8039. }
  8040. return ReturnPtr;
  8041. }
  8042. PCWSTR
  8043. GetFileExtensionFromPathW (
  8044. IN PCWSTR PathSpec
  8045. )
  8046. {
  8047. PCWSTR p;
  8048. PCWSTR ReturnPtr = NULL;
  8049. p = PathSpec;
  8050. while (*p) {
  8051. if (*p == L'.') {
  8052. ReturnPtr = p + 1;
  8053. } else if (*p == L'\\') {
  8054. ReturnPtr = NULL;
  8055. }
  8056. p++;
  8057. }
  8058. return ReturnPtr;
  8059. }
  8060. /*++
  8061. Routine Description:
  8062. GetDotExtensionFromPath finds the last wack in the path and then the last dot from
  8063. the remaining path, returning a pointer to the dot. If no dot is found, returns the
  8064. end of the string.
  8065. Arguments:
  8066. PathSpec - Specifies the path that has a file at the end of it
  8067. Return Value:
  8068. A pointer to the file extension, including the dot, or the end of the string if
  8069. no extension exists.
  8070. --*/
  8071. PCSTR
  8072. GetDotExtensionFromPathA (
  8073. IN PCSTR PathSpec
  8074. )
  8075. {
  8076. PCSTR p;
  8077. PCSTR ReturnPtr = NULL;
  8078. p = PathSpec;
  8079. while (*p) {
  8080. if (*p == '.') {
  8081. ReturnPtr = p;
  8082. } else if (*p == '\\') {
  8083. ReturnPtr = NULL;
  8084. }
  8085. p = _mbsinc (p);
  8086. }
  8087. if (!ReturnPtr) {
  8088. return p;
  8089. }
  8090. return ReturnPtr;
  8091. }
  8092. PCWSTR
  8093. GetDotExtensionFromPathW (
  8094. IN PCWSTR PathSpec
  8095. )
  8096. {
  8097. PCWSTR p;
  8098. PCWSTR ReturnPtr = NULL;
  8099. p = PathSpec;
  8100. while (*p) {
  8101. if (*p == L'.') {
  8102. ReturnPtr = p;
  8103. } else if (*p == L'\\') {
  8104. ReturnPtr = NULL;
  8105. }
  8106. p++;
  8107. }
  8108. if (!ReturnPtr) {
  8109. return p;
  8110. }
  8111. return ReturnPtr;
  8112. }
  8113. /*++
  8114. Routine Description:
  8115. CountInstancesOfChar returns the number of occurances Char
  8116. is found in String.
  8117. Arguments:
  8118. String - Specifies the text that may or may not contain
  8119. search text
  8120. Char - Specifies the char to count
  8121. Return Value:
  8122. The number of times Char appears in String.
  8123. --*/
  8124. UINT
  8125. CountInstancesOfCharA (
  8126. IN PCSTR String,
  8127. IN MBCHAR Char
  8128. )
  8129. {
  8130. UINT count;
  8131. count = 0;
  8132. while (*String) {
  8133. if (_mbsnextc (String) == Char) {
  8134. count++;
  8135. }
  8136. String = _mbsinc (String);
  8137. }
  8138. return count;
  8139. }
  8140. UINT
  8141. CountInstancesOfCharW (
  8142. IN PCWSTR String,
  8143. IN WCHAR Char
  8144. )
  8145. {
  8146. UINT count;
  8147. count = 0;
  8148. while (*String) {
  8149. if (*String == Char) {
  8150. count++;
  8151. }
  8152. String++;
  8153. }
  8154. return count;
  8155. }
  8156. /*++
  8157. Routine Description:
  8158. CountInstancesOfCharI returns the number of occurances Char
  8159. is found in String. The comparison is case-insenetive.
  8160. Arguments:
  8161. String - Specifies the text that may or may not contain
  8162. search text
  8163. Char - Specifies the char to count
  8164. Return Value:
  8165. The number of times Char appears in String.
  8166. --*/
  8167. UINT
  8168. CountInstancesOfCharIA (
  8169. IN PCSTR String,
  8170. IN MBCHAR Char
  8171. )
  8172. {
  8173. UINT count;
  8174. Char = (MBCHAR)OURTOLOWER ((INT)Char);
  8175. count = 0;
  8176. while (*String) {
  8177. if ((MBCHAR) OURTOLOWER ((INT)_mbsnextc (String)) == Char) {
  8178. count++;
  8179. }
  8180. String = _mbsinc (String);
  8181. }
  8182. return count;
  8183. }
  8184. UINT
  8185. CountInstancesOfCharIW (
  8186. IN PCWSTR String,
  8187. IN WCHAR Char
  8188. )
  8189. {
  8190. UINT count;
  8191. Char = towlower (Char);
  8192. count = 0;
  8193. while (*String) {
  8194. if (towlower (*String) == Char) {
  8195. count++;
  8196. }
  8197. String++;
  8198. }
  8199. return count;
  8200. }
  8201. /*++
  8202. Routine Description:
  8203. Searches the string counting the number of occurances of
  8204. SearchString exist in SourceString.
  8205. Arguments:
  8206. SourceString - Specifies the text that may or may not contain
  8207. search text
  8208. SearchString - Specifies the text phrase to count
  8209. Return Value:
  8210. The number of times SearchString appears in SourceString.
  8211. --*/
  8212. UINT
  8213. CountInstancesOfSubStringA (
  8214. IN PCSTR SourceString,
  8215. IN PCSTR SearchString
  8216. )
  8217. {
  8218. PCSTR p;
  8219. UINT count;
  8220. UINT searchBytes;
  8221. count = 0;
  8222. p = SourceString;
  8223. searchBytes = ByteCountA (SearchString);
  8224. while (p = _mbsistr (p, SearchString)) { //lint !e720
  8225. count++;
  8226. p += searchBytes;
  8227. }
  8228. return count;
  8229. }
  8230. UINT
  8231. CountInstancesOfSubStringW (
  8232. IN PCWSTR SourceString,
  8233. IN PCWSTR SearchString
  8234. )
  8235. {
  8236. PCWSTR p;
  8237. UINT count;
  8238. UINT SearchChars;
  8239. count = 0;
  8240. p = SourceString;
  8241. SearchChars = CharCountW (SearchString);
  8242. while (p = _wcsistr (p, SearchString)) { //lint !e720
  8243. count++;
  8244. p += SearchChars;
  8245. }
  8246. return count;
  8247. }
  8248. /*++
  8249. Routine Description:
  8250. Searches and replaces all occurances of SearchString with
  8251. ReplaceString.
  8252. Arguments:
  8253. SourceString - String that contiains zero or more instances
  8254. of the search text
  8255. SearchString - String to search for. Cannot be zero-length or NULL.
  8256. ReplaceString - String to replace. Can be zero-length but cannot
  8257. be NULL.
  8258. Return Value:
  8259. A pointer to the pool-allocated string, or NULL if no instances
  8260. of SearchString were found in SourceString. Free the non-NULL
  8261. pointer with FreePathString.
  8262. --*/
  8263. PCSTR
  8264. StringSearchAndReplaceA (
  8265. IN PCSTR SourceString,
  8266. IN PCSTR SearchString,
  8267. IN PCSTR ReplaceString
  8268. )
  8269. {
  8270. PSTR newString;
  8271. PBYTE p, q;
  8272. PBYTE dest;
  8273. UINT count;
  8274. UINT size;
  8275. UINT searchBytes;
  8276. UINT replaceBytes;
  8277. UINT untouchedBytes;
  8278. //
  8279. // count occurances within the string
  8280. //
  8281. count = CountInstancesOfSubStringA (
  8282. SourceString,
  8283. SearchString
  8284. );
  8285. if (!count) {
  8286. return NULL;
  8287. }
  8288. searchBytes = ByteCountA (SearchString);
  8289. replaceBytes = ByteCountA (ReplaceString);
  8290. MYASSERT (searchBytes);
  8291. size = SizeOfStringA (SourceString) -
  8292. count * searchBytes +
  8293. count * replaceBytes;
  8294. newString = (PSTR) PmGetAlignedMemory (g_PathsPool, size);
  8295. if (!newString) {
  8296. return NULL;
  8297. }
  8298. p = (PBYTE) SourceString;
  8299. dest = (PBYTE) newString;
  8300. while (q = (PBYTE) _mbsistr ((PCSTR) p, SearchString)) { //lint !e720
  8301. untouchedBytes = (DWORD)(q - p);
  8302. if (untouchedBytes) {
  8303. CopyMemory (dest, p, (SIZE_T) untouchedBytes);
  8304. dest += untouchedBytes;
  8305. }
  8306. if (replaceBytes) {
  8307. CopyMemory (dest, (PBYTE) ReplaceString, (SIZE_T) replaceBytes);
  8308. dest += replaceBytes;
  8309. }
  8310. p = q + searchBytes;
  8311. }
  8312. StringCopyA ((PSTR) dest, (PSTR) p);
  8313. return newString;
  8314. }
  8315. PCWSTR
  8316. StringSearchAndReplaceW (
  8317. IN PCWSTR SourceString,
  8318. IN PCWSTR SearchString,
  8319. IN PCWSTR ReplaceString
  8320. )
  8321. {
  8322. PWSTR newString;
  8323. PBYTE p, q;
  8324. PBYTE dest;
  8325. UINT count;
  8326. UINT size;
  8327. UINT searchBytes;
  8328. UINT replaceBytes;
  8329. UINT untouchedBytes;
  8330. //
  8331. // count occurances within the string
  8332. //
  8333. count = CountInstancesOfSubStringW (
  8334. SourceString,
  8335. SearchString
  8336. );
  8337. if (!count) {
  8338. return NULL;
  8339. }
  8340. searchBytes = ByteCountW (SearchString);
  8341. replaceBytes = ByteCountW (ReplaceString);
  8342. MYASSERT (searchBytes);
  8343. size = SizeOfStringW (SourceString) -
  8344. count * searchBytes +
  8345. count * replaceBytes;
  8346. newString = (PWSTR) PmGetAlignedMemory (g_PathsPool, size);
  8347. if (!newString) {
  8348. return NULL;
  8349. }
  8350. p = (PBYTE) SourceString;
  8351. dest = (PBYTE) newString;
  8352. while (q = (PBYTE) _wcsistr ((PCWSTR) p, SearchString)) { //lint !e720
  8353. untouchedBytes = (DWORD)(q - p);
  8354. if (untouchedBytes) {
  8355. CopyMemory (dest, p, (SIZE_T) untouchedBytes);
  8356. dest += untouchedBytes;
  8357. }
  8358. if (replaceBytes) {
  8359. CopyMemory (dest, (PBYTE) ReplaceString, (SIZE_T) replaceBytes);
  8360. dest += replaceBytes;
  8361. }
  8362. p = q + searchBytes;
  8363. }
  8364. StringCopyW ((PWSTR) dest, (PWSTR) p);
  8365. return newString;
  8366. }
  8367. PSTR *
  8368. CommandLineToArgvA (
  8369. IN PCSTR CmdLine,
  8370. OUT PUINT NumArgs
  8371. )
  8372. /*++
  8373. Routine Description:
  8374. CommandLineToArgvA implements an ANSI version of the Win32 function
  8375. CommandLineToArgvW.
  8376. Arguments:
  8377. CmdLine - A pointer to the complete command line, including the
  8378. module name. This is the same string returned by
  8379. GetCommandLineA().
  8380. NumArgs - Receives the number of arguments allocated, identical to
  8381. main's argc parameter. That is, NumArgs is equal to
  8382. the number of command line arguments plus one for the
  8383. command itself.
  8384. Return Value:
  8385. A pointer to an array of string pointers, one per argument. The
  8386. command line arguments are placed in separate nul-terminated strings.
  8387. The caller must free the memory using a single call to GlobalFree or
  8388. LocalFree.
  8389. --*/
  8390. {
  8391. PCSTR start, end;
  8392. BOOL QuoteMode;
  8393. MBCHAR ch = 0;
  8394. UINT Pass;
  8395. UINT ArgStrSize;
  8396. UINT Args;
  8397. PSTR ArgStrEnd = NULL; // filled in on pass one, used on pass two
  8398. PSTR *ArgPtrArray = NULL; // filled in on pass one, used on pass two
  8399. //
  8400. // count args on first pass, then allocate memory and create arg string
  8401. //
  8402. ArgStrSize = 0;
  8403. Pass = 0;
  8404. do {
  8405. // Init loop
  8406. Pass++;
  8407. Args = 0;
  8408. start = CmdLine;
  8409. // Skip leading space
  8410. while (_ismbcspace ((MBCHAR)(*start))) {
  8411. start++;
  8412. }
  8413. while (*start) {
  8414. // Look for quote mode
  8415. if (*start == '\"') {
  8416. QuoteMode = TRUE;
  8417. start++;
  8418. } else {
  8419. QuoteMode = FALSE;
  8420. }
  8421. // Find end of arg
  8422. end = start;
  8423. while (*end) {
  8424. ch = _mbsnextc (end);
  8425. if (QuoteMode) {
  8426. if (ch == '\"') {
  8427. break;
  8428. }
  8429. } else {
  8430. if (_ismbcspace ((MBCHAR)ch)) {
  8431. break;
  8432. }
  8433. }
  8434. end = _mbsinc (end);
  8435. }
  8436. // If Pass 1, add string size
  8437. if (Pass == 1) {
  8438. ArgStrSize += (UINT)((UBINT)end - (UBINT)start) + 1;
  8439. }
  8440. // If Pass 2, copy strings to buffer
  8441. else {
  8442. MYASSERT (ArgStrEnd);
  8443. MYASSERT (ArgPtrArray);
  8444. ArgPtrArray[Args] = ArgStrEnd; //lint !e613
  8445. StringCopyABA (ArgStrEnd, start, end);
  8446. ArgStrEnd = GetEndOfStringA (ArgStrEnd); //lint !e668
  8447. ArgStrEnd++; //lint !e613
  8448. }
  8449. // Set start to next arg
  8450. Args++;
  8451. if (QuoteMode && ch == '\"') {
  8452. end = _mbsinc (end);
  8453. }
  8454. start = end;
  8455. while (_ismbcspace ((MBCHAR)(*start))) {
  8456. start++;
  8457. }
  8458. }
  8459. // If Pass 1, allocate strings
  8460. if (Pass == 1) {
  8461. if (Args) {
  8462. ArgPtrArray = (PSTR *) GlobalAlloc (
  8463. GPTR,
  8464. (UINT)(sizeof (PSTR) * Args + ArgStrSize)
  8465. );
  8466. if (!ArgPtrArray) {
  8467. return NULL;
  8468. }
  8469. ArgStrEnd = (PSTR) (&ArgPtrArray[Args]);
  8470. } else {
  8471. return NULL;
  8472. }
  8473. }
  8474. } while (Pass < 2);
  8475. *NumArgs = Args;
  8476. return ArgPtrArray;
  8477. }
  8478. BOOL
  8479. EnumNextMultiSzA (
  8480. IN OUT PMULTISZ_ENUMA MultiSzEnum
  8481. )
  8482. {
  8483. if (!MultiSzEnum->CurrentString || !(*MultiSzEnum->CurrentString)) {
  8484. return FALSE;
  8485. }
  8486. MultiSzEnum->CurrentString = GetEndOfStringA (MultiSzEnum->CurrentString) + 1; //lint !e613
  8487. return (MultiSzEnum->CurrentString [0] != 0);
  8488. }
  8489. BOOL
  8490. EnumFirstMultiSzA (
  8491. OUT PMULTISZ_ENUMA MultiSzEnum,
  8492. IN PCSTR MultiSzStr
  8493. )
  8494. {
  8495. if ((MultiSzStr == NULL) || (MultiSzStr [0] == 0)) {
  8496. return FALSE;
  8497. }
  8498. MultiSzEnum->Buffer = MultiSzStr;
  8499. MultiSzEnum->CurrentString = MultiSzStr;
  8500. return TRUE;
  8501. }
  8502. BOOL
  8503. EnumNextMultiSzW (
  8504. IN OUT PMULTISZ_ENUMW MultiSzEnum
  8505. )
  8506. {
  8507. if (!MultiSzEnum->CurrentString || !(*MultiSzEnum->CurrentString)) {
  8508. return FALSE;
  8509. }
  8510. MultiSzEnum->CurrentString = GetEndOfStringW (MultiSzEnum->CurrentString) + 1;
  8511. return (MultiSzEnum->CurrentString [0] != 0);
  8512. }
  8513. BOOL
  8514. EnumFirstMultiSzW (
  8515. OUT PMULTISZ_ENUMW MultiSzEnum,
  8516. IN PCWSTR MultiSzStr
  8517. )
  8518. {
  8519. if ((MultiSzStr == NULL) || (MultiSzStr [0] == 0)) {
  8520. return FALSE;
  8521. }
  8522. MultiSzEnum->Buffer = MultiSzStr;
  8523. MultiSzEnum->CurrentString = MultiSzStr;
  8524. return TRUE;
  8525. }
  8526. BOOL
  8527. IsStrInMultiSzA (
  8528. IN PCSTR String,
  8529. IN PCSTR MultiSz
  8530. )
  8531. {
  8532. BOOL result = FALSE;
  8533. MULTISZ_ENUMA multiSzEnum;
  8534. if (EnumFirstMultiSzA (&multiSzEnum, MultiSz)) {
  8535. do {
  8536. if (StringIMatchA (String, multiSzEnum.CurrentString)) {
  8537. result = TRUE;
  8538. break;
  8539. }
  8540. } while (EnumNextMultiSzA (&multiSzEnum));
  8541. }
  8542. return result;
  8543. }
  8544. BOOL
  8545. IsStrInMultiSzW (
  8546. IN PCWSTR String,
  8547. IN PCWSTR MultiSz
  8548. )
  8549. {
  8550. BOOL result = FALSE;
  8551. MULTISZ_ENUMW multiSzEnum;
  8552. if (EnumFirstMultiSzW (&multiSzEnum, MultiSz)) {
  8553. do {
  8554. if (StringIMatchW (String, multiSzEnum.CurrentString)) {
  8555. result = TRUE;
  8556. break;
  8557. }
  8558. } while (EnumNextMultiSzW (&multiSzEnum));
  8559. }
  8560. return result;
  8561. }
  8562. PSTR
  8563. GetPrevCharA (
  8564. IN PCSTR StartStr,
  8565. IN PCSTR CurrPtr,
  8566. IN MBCHAR SearchChar
  8567. )
  8568. {
  8569. PCSTR ptr = CurrPtr;
  8570. for (;;) {
  8571. ptr = _mbsdec2 (StartStr, ptr);
  8572. if (!ptr) {
  8573. return NULL;
  8574. }
  8575. if (_mbsnextc (ptr) == SearchChar) {
  8576. return (PSTR) ptr;
  8577. }
  8578. }
  8579. }
  8580. PWSTR
  8581. GetPrevCharW (
  8582. IN PCWSTR StartStr,
  8583. IN PCWSTR CurrPtr,
  8584. IN WCHAR SearchChar
  8585. )
  8586. {
  8587. PCWSTR ptr = CurrPtr;
  8588. while (ptr > StartStr) {
  8589. ptr--;
  8590. if (*ptr == SearchChar) {
  8591. return (PWSTR) ptr;
  8592. }
  8593. }
  8594. return NULL;
  8595. }
  8596. VOID
  8597. ToggleWacksA (
  8598. IN PSTR Line,
  8599. IN BOOL Operation
  8600. )
  8601. {
  8602. CHAR curChar;
  8603. CHAR newChar;
  8604. PSTR p = Line;
  8605. curChar = Operation ? WACK_REPLACE_CHAR : '\\';
  8606. newChar = Operation ? '\\' : WACK_REPLACE_CHAR;
  8607. do {
  8608. p = _mbschr (p, curChar);
  8609. if (p) {
  8610. *p = newChar;
  8611. p = _mbsinc (p);
  8612. }
  8613. } while (p);
  8614. }
  8615. VOID
  8616. ToggleWacksW (
  8617. IN PWSTR Line,
  8618. IN BOOL Operation
  8619. )
  8620. {
  8621. WCHAR curChar;
  8622. WCHAR newChar;
  8623. PWSTR p = Line;
  8624. curChar = Operation ? WACK_REPLACE_CHAR : L'\\';
  8625. newChar = Operation ? L'\\' : WACK_REPLACE_CHAR;
  8626. do {
  8627. p = wcschr (p, curChar);
  8628. if (p) {
  8629. *p = newChar;
  8630. p++;
  8631. }
  8632. } while (p);
  8633. }
  8634. PSTR
  8635. pGoBackA (
  8636. IN PSTR LastChar,
  8637. IN PSTR FirstChar,
  8638. IN UINT NumWacks
  8639. )
  8640. {
  8641. LastChar = _mbsdec2 (FirstChar, LastChar);
  8642. while (NumWacks && (LastChar >= FirstChar)) {
  8643. if (_mbsnextc (LastChar) == '\\') {
  8644. NumWacks --;
  8645. }
  8646. LastChar = _mbsdec2 (FirstChar, LastChar);
  8647. }
  8648. if (NumWacks) {
  8649. return NULL;
  8650. }
  8651. return LastChar + 2;
  8652. }
  8653. PWSTR
  8654. pGoBackW (
  8655. IN PWSTR LastChar,
  8656. IN PWSTR FirstChar,
  8657. IN UINT NumWacks
  8658. )
  8659. {
  8660. LastChar --;
  8661. while (NumWacks && (LastChar >= FirstChar)) {
  8662. if (*LastChar == L'\\') {
  8663. NumWacks --;
  8664. }
  8665. LastChar --;
  8666. }
  8667. if (NumWacks) {
  8668. return NULL;
  8669. }
  8670. return LastChar + 2;
  8671. }
  8672. UINT
  8673. pCountDotsA (
  8674. IN PCSTR PathSeg
  8675. )
  8676. {
  8677. UINT numDots = 0;
  8678. while (PathSeg && *PathSeg) {
  8679. if (_mbsnextc (PathSeg) != '.') {
  8680. return 0;
  8681. }
  8682. numDots ++;
  8683. PathSeg = _mbsinc (PathSeg);
  8684. }
  8685. return numDots;
  8686. }
  8687. UINT
  8688. pCountDotsW (
  8689. IN PCWSTR PathSeg
  8690. )
  8691. {
  8692. UINT numDots = 0;
  8693. while (PathSeg && *PathSeg) {
  8694. if (*PathSeg != L'.') {
  8695. return 0;
  8696. }
  8697. numDots ++;
  8698. PathSeg ++;
  8699. }
  8700. return numDots;
  8701. }
  8702. PCSTR
  8703. SanitizePathA (
  8704. IN PCSTR FileSpec
  8705. )
  8706. {
  8707. CHAR pathSeg [MAX_MBCHAR_PATH];
  8708. PCSTR wackPtr;
  8709. UINT dotNr;
  8710. PSTR newPath = DuplicatePathStringA (FileSpec, 0);
  8711. PSTR newPathPtr = newPath;
  8712. BOOL firstPass = TRUE;
  8713. do {
  8714. wackPtr = _mbschr (FileSpec, '\\');
  8715. if (wackPtr) {
  8716. if (firstPass && (wackPtr == FileSpec)) {
  8717. // this one starts with a wack, let's see if we have double wacks
  8718. wackPtr = _mbsinc (wackPtr);
  8719. if (!wackPtr) {
  8720. FreePathStringA (newPath);
  8721. return NULL;
  8722. }
  8723. if (_mbsnextc (wackPtr) == '\\') {
  8724. // this one starts with a double wack
  8725. wackPtr = _mbsinc (wackPtr);
  8726. if (!wackPtr) {
  8727. FreePathStringA (newPath);
  8728. return NULL;
  8729. }
  8730. wackPtr = _mbschr (wackPtr, '\\');
  8731. } else {
  8732. wackPtr = _mbschr (wackPtr, '\\');
  8733. }
  8734. }
  8735. firstPass = FALSE;
  8736. if (wackPtr) {
  8737. StringCopyByteCountABA (
  8738. pathSeg,
  8739. FileSpec,
  8740. wackPtr,
  8741. MAX_MBCHAR_PATH
  8742. );
  8743. FileSpec = _mbsinc (wackPtr);
  8744. } else {
  8745. StringCopyByteCountABA (pathSeg, FileSpec, GetEndOfStringA (FileSpec), MAX_MBCHAR_PATH);
  8746. }
  8747. } else {
  8748. StringCopyByteCountABA (pathSeg, FileSpec, GetEndOfStringA (FileSpec), MAX_MBCHAR_PATH);
  8749. }
  8750. if (*pathSeg) {
  8751. dotNr = pCountDotsA (pathSeg);
  8752. if (dotNr>1) {
  8753. newPathPtr = pGoBackA (newPathPtr, newPath, dotNr);
  8754. if (newPathPtr == NULL) {
  8755. DEBUGMSGA ((DBG_WARNING, "Broken path detected:%s", FileSpec));
  8756. FreePathStringA (newPath);
  8757. return NULL;
  8758. }
  8759. } else {
  8760. StringCopyA (newPathPtr, pathSeg);
  8761. newPathPtr = GetEndOfStringA (newPathPtr);
  8762. if (wackPtr) {
  8763. *newPathPtr = '\\';
  8764. //we increment this because we know that \ is a single byte character.
  8765. newPathPtr ++;
  8766. }
  8767. }
  8768. }
  8769. } while (wackPtr);
  8770. *newPathPtr = 0;
  8771. return newPath;
  8772. }
  8773. PCWSTR
  8774. SanitizePathW (
  8775. IN PCWSTR FileSpec
  8776. )
  8777. {
  8778. WCHAR pathSeg [MEMDB_MAX];
  8779. PCWSTR wackPtr;
  8780. UINT dotNr;
  8781. PWSTR newPath = DuplicatePathStringW (FileSpec, 0);
  8782. PWSTR newPathPtr = newPath;
  8783. BOOL firstPass = TRUE;
  8784. do {
  8785. wackPtr = wcschr (FileSpec, L'\\');
  8786. if (wackPtr) {
  8787. if (firstPass && (wackPtr == FileSpec)) {
  8788. // this one starts with a wack, let's see if we have double wacks
  8789. wackPtr ++;
  8790. if (*wackPtr == L'\\') {
  8791. // this one starts with a double wack
  8792. wackPtr ++;
  8793. wackPtr = wcschr (wackPtr, L'\\');
  8794. } else {
  8795. wackPtr = wcschr (wackPtr, L'\\');
  8796. }
  8797. }
  8798. firstPass = FALSE;
  8799. if (wackPtr) {
  8800. StringCopyByteCountABW (
  8801. pathSeg,
  8802. FileSpec,
  8803. wackPtr,
  8804. (UINT) sizeof (pathSeg)
  8805. );
  8806. FileSpec = wackPtr + 1;
  8807. } else {
  8808. StringCopyByteCountABW (pathSeg, FileSpec, GetEndOfStringW (FileSpec), (UINT) sizeof (pathSeg));
  8809. }
  8810. } else {
  8811. StringCopyByteCountABW (pathSeg, FileSpec, GetEndOfStringW (FileSpec), (UINT) sizeof (pathSeg));
  8812. }
  8813. if (*pathSeg) {
  8814. dotNr = pCountDotsW (pathSeg);
  8815. if (dotNr>1) {
  8816. newPathPtr = pGoBackW (newPathPtr, newPath, dotNr);
  8817. if (newPathPtr == NULL) {
  8818. DEBUGMSGW ((DBG_WARNING, "Broken path detected:%s", FileSpec));
  8819. FreePathStringW (newPath);
  8820. return NULL;
  8821. }
  8822. } else {
  8823. StringCopyW (newPathPtr, pathSeg);
  8824. newPathPtr = GetEndOfStringW (newPathPtr);
  8825. if (wackPtr) {
  8826. *newPathPtr = L'\\';
  8827. newPathPtr ++;
  8828. }
  8829. }
  8830. }
  8831. } while (wackPtr);
  8832. *newPathPtr = 0;
  8833. return newPath;
  8834. }
  8835. UINT
  8836. pBuildFromDHList (
  8837. IN UINT ch1,
  8838. IN UINT ch2
  8839. )
  8840. {
  8841. PDHLIST p;
  8842. UINT result = 0;
  8843. p = g_DHList;
  8844. while (p->char1) {
  8845. if ((p->char1 == ch1) && (p->char2 == ch2)) {
  8846. result = p->result;
  8847. break;
  8848. }
  8849. p++;
  8850. }
  8851. return result;
  8852. }
  8853. VOID
  8854. _mbssetchar (
  8855. OUT PSTR Dest,
  8856. IN UINT Char
  8857. )
  8858. {
  8859. if (Char >= 256) {
  8860. *(Dest+1) = *((PBYTE)(&Char));
  8861. *(Dest) = *((PBYTE)(&Char) + 1);
  8862. }
  8863. else {
  8864. *Dest = (CHAR) Char;
  8865. }
  8866. }
  8867. /*++
  8868. Routine Description:
  8869. FindLastWack finds the position of the last \ in the given string or NULL if none found
  8870. Arguments:
  8871. Str - Specifies the string
  8872. Return Value:
  8873. Pointer to the last occurence of a \ in the string or NULL
  8874. --*/
  8875. PCSTR
  8876. FindLastWackA (
  8877. IN PCSTR Str
  8878. )
  8879. {
  8880. PCSTR lastWack = NULL;
  8881. if (Str) {
  8882. while ((Str = _mbschr (Str, '\\')) != NULL) {
  8883. lastWack = Str;
  8884. Str++;
  8885. }
  8886. }
  8887. return lastWack;
  8888. }
  8889. PCWSTR
  8890. FindLastWackW (
  8891. IN PCWSTR Str
  8892. )
  8893. {
  8894. PCWSTR lastWack = NULL;
  8895. if (Str) {
  8896. while ((Str = wcschr (Str, L'\\')) != NULL) {
  8897. lastWack = Str;
  8898. Str++;
  8899. }
  8900. }
  8901. return lastWack;
  8902. }
  8903. /*++
  8904. Routine Description:
  8905. GetNodePatternMinMaxLevels treats the given string pattern as a path with \ as separator
  8906. and computes the min and max levels of the given node; the root has level 1; if a * is
  8907. followed by \ it is treated as a single level (e.g. *\ only enumerates roots)
  8908. Arguments:
  8909. NodePattern - Specifies the node as a string pattern
  8910. FormattedNodePattern - Receives the formatted string, eliminating duplicate * and the last \;
  8911. may be the same as NodePattern
  8912. MinLevel - Receives the minimum level of a node having this pattern
  8913. MaxLevel - Receives the maximum level of a node having this pattern; may be NODE_LEVEL_MAX
  8914. Return Value:
  8915. TRUE if NodePattern is a valid pattern and the function succeeded, FALSE otherwise
  8916. --*/
  8917. #define NODESTATE_BEGIN 0
  8918. #define NODESTATE_UNC 1
  8919. #define NODESTATE_BEGINSEG 2
  8920. #define NODESTATE_INSEG 3
  8921. #define NODESTATE_ESCAPED 4
  8922. #define NODESTATE_STAR 5
  8923. #define NODESTATE_STARONLY 6
  8924. #define NODESTATE_INEXPAT 7
  8925. #define NODESTATE_QMARK 8
  8926. BOOL
  8927. GetNodePatternMinMaxLevelsA (
  8928. IN PCSTR NodePattern,
  8929. OUT PSTR FormattedNode, OPTIONAL
  8930. OUT PDWORD MinLevel, OPTIONAL
  8931. OUT PDWORD MaxLevel OPTIONAL
  8932. )
  8933. {
  8934. PCSTR nodePattern = NodePattern;
  8935. MBCHAR currCh = 0;
  8936. DWORD minLevel = 0;
  8937. DWORD maxLevel = 0;
  8938. DWORD state = NODESTATE_BEGIN;
  8939. BOOL advance;
  8940. BOOL copyChar;
  8941. if (!NodePattern || *NodePattern == 0) {
  8942. return FALSE;
  8943. }
  8944. while (*nodePattern) {
  8945. advance = TRUE;
  8946. copyChar = TRUE;
  8947. currCh = _mbsnextc (nodePattern);
  8948. switch (state) {
  8949. case NODESTATE_BEGIN:
  8950. switch (currCh) {
  8951. case '\\':
  8952. state = NODESTATE_UNC;
  8953. break;
  8954. case '*':
  8955. minLevel ++;
  8956. maxLevel ++;
  8957. state = NODESTATE_INSEG;
  8958. advance = FALSE;
  8959. break;
  8960. case '?':
  8961. minLevel ++;
  8962. maxLevel ++;
  8963. state = NODESTATE_INSEG;
  8964. advance = FALSE;
  8965. break;
  8966. case '^':
  8967. minLevel ++;
  8968. maxLevel ++;
  8969. state = NODESTATE_ESCAPED;
  8970. break;
  8971. default:
  8972. minLevel ++;
  8973. maxLevel ++;
  8974. state = NODESTATE_INSEG;
  8975. break;
  8976. }
  8977. break;
  8978. case NODESTATE_UNC:
  8979. minLevel ++;
  8980. if (maxLevel != NODE_LEVEL_MAX) {
  8981. maxLevel ++;
  8982. }
  8983. switch (currCh) {
  8984. case '\\':
  8985. state = NODESTATE_BEGINSEG;
  8986. break;
  8987. case '*':
  8988. state = NODESTATE_BEGINSEG;
  8989. advance = FALSE;
  8990. break;
  8991. case '?':
  8992. state = NODESTATE_INSEG;
  8993. advance = FALSE;
  8994. break;
  8995. case '^':
  8996. state = NODESTATE_ESCAPED;
  8997. break;
  8998. default:
  8999. state = NODESTATE_INSEG;
  9000. break;
  9001. }
  9002. break;
  9003. case NODESTATE_BEGINSEG:
  9004. switch (currCh) {
  9005. case '\\':
  9006. DEBUGMSGA ((DBG_STRINGS, "GetNodeMinMaxLevelsA: two wacks in a row: %s", NodePattern));
  9007. return FALSE;
  9008. case '*':
  9009. minLevel --;
  9010. state = NODESTATE_STARONLY;
  9011. maxLevel = NODE_LEVEL_MAX;
  9012. break;
  9013. case '?':
  9014. state = NODESTATE_INSEG;
  9015. advance = FALSE;
  9016. break;
  9017. case '^':
  9018. state = NODESTATE_ESCAPED;
  9019. break;
  9020. default:
  9021. state = NODESTATE_INSEG;
  9022. break;
  9023. }
  9024. break;
  9025. case NODESTATE_STARONLY:
  9026. state = NODESTATE_INSEG;
  9027. switch (currCh) {
  9028. case '*':
  9029. copyChar = FALSE;
  9030. break;
  9031. case '[':
  9032. state = NODESTATE_INEXPAT;
  9033. minLevel ++;
  9034. if (maxLevel != NODE_LEVEL_MAX) {
  9035. maxLevel ++;
  9036. }
  9037. break;
  9038. default:
  9039. minLevel ++;
  9040. if (maxLevel != NODE_LEVEL_MAX) {
  9041. maxLevel ++;
  9042. }
  9043. advance = FALSE;
  9044. }
  9045. break;
  9046. case NODESTATE_INEXPAT:
  9047. // NTRAID#NTBUG9-153307-2000/08/01-jimschm Min/max parsing needs to be more extensive
  9048. // so we can allow ] in the excluded or included list
  9049. // The syntax checking needs to be quite extensive
  9050. switch (currCh) {
  9051. case ']':
  9052. state = NODESTATE_INSEG;
  9053. break;
  9054. default:
  9055. break;
  9056. }
  9057. break;
  9058. case NODESTATE_STAR:
  9059. switch (currCh) {
  9060. case '*':
  9061. state = NODESTATE_STAR;
  9062. copyChar = FALSE;
  9063. break;
  9064. case '[':
  9065. state = NODESTATE_INEXPAT;
  9066. break;
  9067. default:
  9068. state = NODESTATE_INSEG;
  9069. advance = FALSE;
  9070. }
  9071. break;
  9072. case NODESTATE_QMARK:
  9073. switch (currCh) {
  9074. case '[':
  9075. state = NODESTATE_INEXPAT;
  9076. break;
  9077. default:
  9078. state = NODESTATE_INSEG;
  9079. advance = FALSE;
  9080. }
  9081. break;
  9082. case NODESTATE_INSEG:
  9083. switch (currCh) {
  9084. case '\\':
  9085. minLevel ++;
  9086. if (maxLevel != NODE_LEVEL_MAX) {
  9087. maxLevel ++;
  9088. }
  9089. state = NODESTATE_BEGINSEG;
  9090. break;
  9091. case '*':
  9092. state = NODESTATE_STAR;
  9093. maxLevel = NODE_LEVEL_MAX;
  9094. break;
  9095. case '?':
  9096. state = NODESTATE_QMARK;
  9097. if (maxLevel != NODE_LEVEL_MAX) {
  9098. maxLevel ++;
  9099. }
  9100. break;
  9101. case '^':
  9102. state = NODESTATE_ESCAPED;
  9103. break;
  9104. default:
  9105. state = NODESTATE_INSEG;
  9106. break;
  9107. }
  9108. break;
  9109. case NODESTATE_ESCAPED:
  9110. if (!_mbschr (EscapedCharsA, currCh)) {
  9111. DEBUGMSGA ((DBG_STRINGS, "GetNodeMinMaxLevelsA: illegal escaped character: %s", NodePattern));
  9112. return FALSE;
  9113. }
  9114. state = NODESTATE_INSEG;
  9115. break;
  9116. default:
  9117. DEBUGMSGA ((DBG_STRINGS, "GetNodeMinMaxLevelsA: unknown state while processing: %s", NodePattern));
  9118. return FALSE;
  9119. }
  9120. if (advance) {
  9121. if (copyChar && FormattedNode) {
  9122. if (IsLeadByte (nodePattern)) {
  9123. *FormattedNode = *nodePattern;
  9124. FormattedNode ++;
  9125. nodePattern ++;
  9126. }
  9127. *FormattedNode = *nodePattern;
  9128. FormattedNode ++;
  9129. nodePattern ++;
  9130. } else {
  9131. nodePattern = _mbsinc (nodePattern);
  9132. }
  9133. }
  9134. }
  9135. if (MinLevel) {
  9136. *MinLevel = minLevel;
  9137. }
  9138. if (MaxLevel) {
  9139. *MaxLevel = maxLevel;
  9140. }
  9141. if (FormattedNode) {
  9142. *FormattedNode = 0;
  9143. }
  9144. return TRUE;
  9145. }
  9146. BOOL
  9147. GetNodePatternMinMaxLevelsW (
  9148. IN PCWSTR NodePattern,
  9149. OUT PWSTR FormattedNode, OPTIONAL
  9150. OUT PDWORD MinLevel, OPTIONAL
  9151. OUT PDWORD MaxLevel OPTIONAL
  9152. )
  9153. {
  9154. PCWSTR nodePattern = NodePattern;
  9155. DWORD minLevel = 0;
  9156. DWORD maxLevel = 0;
  9157. DWORD state = NODESTATE_BEGIN;
  9158. BOOL advance;
  9159. BOOL copyChar;
  9160. if (!NodePattern || *NodePattern == 0) {
  9161. return FALSE;
  9162. }
  9163. while (*nodePattern) {
  9164. advance = TRUE;
  9165. copyChar = TRUE;
  9166. switch (state) {
  9167. case NODESTATE_BEGIN:
  9168. switch (*nodePattern) {
  9169. case L'\\':
  9170. state = NODESTATE_UNC;
  9171. break;
  9172. case L'*':
  9173. minLevel ++;
  9174. maxLevel ++;
  9175. state = NODESTATE_INSEG;
  9176. advance = FALSE;
  9177. break;
  9178. case L'?':
  9179. minLevel ++;
  9180. maxLevel ++;
  9181. state = NODESTATE_INSEG;
  9182. advance = FALSE;
  9183. break;
  9184. case L'^':
  9185. minLevel ++;
  9186. maxLevel ++;
  9187. state = NODESTATE_ESCAPED;
  9188. break;
  9189. default:
  9190. minLevel ++;
  9191. maxLevel ++;
  9192. state = NODESTATE_INSEG;
  9193. break;
  9194. }
  9195. break;
  9196. case NODESTATE_UNC:
  9197. minLevel ++;
  9198. if (maxLevel != NODE_LEVEL_MAX) {
  9199. maxLevel ++;
  9200. }
  9201. switch (*nodePattern) {
  9202. case L'\\':
  9203. state = NODESTATE_BEGINSEG;
  9204. break;
  9205. case L'*':
  9206. state = NODESTATE_BEGINSEG;
  9207. advance = FALSE;
  9208. break;
  9209. case L'?':
  9210. state = NODESTATE_INSEG;
  9211. advance = FALSE;
  9212. break;
  9213. case L'^':
  9214. state = NODESTATE_ESCAPED;
  9215. break;
  9216. default:
  9217. state = NODESTATE_INSEG;
  9218. break;
  9219. }
  9220. break;
  9221. case NODESTATE_BEGINSEG:
  9222. switch (*nodePattern) {
  9223. case L'\\':
  9224. DEBUGMSGW ((DBG_STRINGS, "GetNodeMinMaxLevelsA: two wacks in a row: %s", NodePattern));
  9225. return FALSE;
  9226. case L'*':
  9227. minLevel --;
  9228. state = NODESTATE_STARONLY;
  9229. maxLevel = NODE_LEVEL_MAX;
  9230. break;
  9231. case L'?':
  9232. state = NODESTATE_INSEG;
  9233. advance = FALSE;
  9234. break;
  9235. case L'^':
  9236. state = NODESTATE_ESCAPED;
  9237. break;
  9238. default:
  9239. state = NODESTATE_INSEG;
  9240. break;
  9241. }
  9242. break;
  9243. case NODESTATE_STARONLY:
  9244. state = NODESTATE_INSEG;
  9245. switch (*nodePattern) {
  9246. case L'*':
  9247. copyChar = FALSE;
  9248. break;
  9249. case L'[':
  9250. state = NODESTATE_INEXPAT;
  9251. minLevel ++;
  9252. if (maxLevel != NODE_LEVEL_MAX) {
  9253. maxLevel ++;
  9254. }
  9255. break;
  9256. default:
  9257. minLevel ++;
  9258. if (maxLevel != NODE_LEVEL_MAX) {
  9259. maxLevel ++;
  9260. }
  9261. advance = FALSE;
  9262. }
  9263. break;
  9264. case NODESTATE_INEXPAT:
  9265. // NTRAID#NTBUG9-153307-2000/08/01-jimschm Min/max parsing needs to be more extensive
  9266. // so we can allow ] in the excluded or included list
  9267. // The syntax checking needs to be quite extensive
  9268. switch (*nodePattern) {
  9269. case L']':
  9270. state = NODESTATE_INSEG;
  9271. break;
  9272. default:
  9273. break;
  9274. }
  9275. break;
  9276. case NODESTATE_STAR:
  9277. switch (*nodePattern) {
  9278. case L'*':
  9279. state = NODESTATE_STAR;
  9280. copyChar = FALSE;
  9281. break;
  9282. case L'[':
  9283. state = NODESTATE_INEXPAT;
  9284. break;
  9285. default:
  9286. state = NODESTATE_INSEG;
  9287. advance = FALSE;
  9288. }
  9289. break;
  9290. case NODESTATE_QMARK:
  9291. switch (*nodePattern) {
  9292. case L'[':
  9293. state = NODESTATE_INEXPAT;
  9294. break;
  9295. default:
  9296. state = NODESTATE_INSEG;
  9297. advance = FALSE;
  9298. }
  9299. break;
  9300. case NODESTATE_INSEG:
  9301. switch (*nodePattern) {
  9302. case L'\\':
  9303. minLevel ++;
  9304. if (maxLevel != NODE_LEVEL_MAX) {
  9305. maxLevel ++;
  9306. }
  9307. state = NODESTATE_BEGINSEG;
  9308. break;
  9309. case L'*':
  9310. state = NODESTATE_STAR;
  9311. maxLevel = NODE_LEVEL_MAX;
  9312. break;
  9313. case L'?':
  9314. state = NODESTATE_QMARK;
  9315. if (maxLevel != NODE_LEVEL_MAX) {
  9316. maxLevel ++;
  9317. }
  9318. break;
  9319. case L'^':
  9320. state = NODESTATE_ESCAPED;
  9321. break;
  9322. default:
  9323. state = NODESTATE_INSEG;
  9324. break;
  9325. }
  9326. break;
  9327. case NODESTATE_ESCAPED:
  9328. if (!wcschr (EscapedCharsW, *nodePattern)) {
  9329. DEBUGMSGW ((DBG_STRINGS, "GetNodeMinMaxLevelsA: illegal escaped character: %s", NodePattern));
  9330. return FALSE;
  9331. }
  9332. state = NODESTATE_INSEG;
  9333. break;
  9334. default:
  9335. DEBUGMSGW ((DBG_STRINGS, "GetNodeMinMaxLevelsA: unknown state while processing: %s", NodePattern));
  9336. return FALSE;
  9337. }
  9338. if (advance) {
  9339. if (copyChar && FormattedNode) {
  9340. *FormattedNode = *nodePattern;
  9341. FormattedNode ++;
  9342. nodePattern ++;
  9343. } else {
  9344. nodePattern ++;
  9345. }
  9346. }
  9347. }
  9348. if (MinLevel) {
  9349. *MinLevel = minLevel;
  9350. }
  9351. if (MaxLevel) {
  9352. *MaxLevel = maxLevel;
  9353. }
  9354. if (FormattedNode) {
  9355. *FormattedNode = 0;
  9356. }
  9357. return TRUE;
  9358. }
  9359. #if 0
  9360. //
  9361. // PORTBUG Uses memdb max. #if 0'd out for now.
  9362. //
  9363. PCSTR
  9364. ConvertSBtoDB (
  9365. IN PCSTR RootPath,
  9366. IN PCSTR FullPath,
  9367. IN PCSTR Limit
  9368. )
  9369. {
  9370. CHAR result[MEMDB_MAX];
  9371. PCSTR p,p1,q;
  9372. PSTR s;
  9373. UINT ch;
  9374. UINT ch1;
  9375. BOOL dhCase = FALSE;
  9376. ZeroMemory (result, MAX_PATH);
  9377. p = FullPath;
  9378. q = RootPath;
  9379. s = result;
  9380. while (*p && (((DWORD)s - (DWORD)result) < MEMDB_MAX)) {
  9381. if (q && *q) {
  9382. _mbssetchar (s, _mbsnextc(p));
  9383. q = _mbsinc (q);
  9384. } else if (Limit && (p >= Limit)) {
  9385. _mbssetchar (s, _mbsnextc(p));
  9386. } else {
  9387. ch = _mbsnextc (p);
  9388. //
  9389. // It is very important not to make the conversion for characters below A1. Otherwise
  9390. // all english letters will be converted to large letters.
  9391. //
  9392. if (ch >= 0xA1 && ch <= 0xDF) {
  9393. // this is a candidate for conversion
  9394. // we need to see if there is a special Dakutenn/Handakuten conversion
  9395. dhCase = FALSE;
  9396. p1 = _mbsinc (p);
  9397. if (p1) {
  9398. ch1 = _mbsnextc (p1);
  9399. ch1 = pBuildFromDHList (ch, ch1);
  9400. if (ch1) {
  9401. p = _mbsinc (p);
  9402. _mbssetchar (s, ch1);
  9403. dhCase = TRUE;
  9404. }
  9405. }
  9406. if (!dhCase) {
  9407. _mbssetchar (s, _mbbtombc (ch));
  9408. }
  9409. } else {
  9410. _mbssetchar (s, ch);
  9411. }
  9412. }
  9413. p = _mbsinc (p);
  9414. s = _mbsinc (s);
  9415. }
  9416. result [MAX_PATH - 1] = 0;
  9417. return (DuplicatePathString (result, 0));
  9418. }
  9419. #endif
  9420. ULONGLONG
  9421. StringToUint64A (
  9422. IN PCSTR String,
  9423. OUT PCSTR *EndOfNumber OPTIONAL
  9424. )
  9425. {
  9426. ULONGLONG n;
  9427. n = 0;
  9428. while (*String >= '0' && *String <= '9') {
  9429. n = n * 10 + *String - '0';
  9430. String++;
  9431. }
  9432. if (EndOfNumber) {
  9433. *EndOfNumber = String;
  9434. }
  9435. return n;
  9436. }
  9437. ULONGLONG
  9438. StringToUint64W (
  9439. IN PCWSTR String,
  9440. OUT PCWSTR *EndOfNumber OPTIONAL
  9441. )
  9442. {
  9443. ULONGLONG n;
  9444. n = 0;
  9445. while (*String >= L'0' && *String <= L'9') {
  9446. n = n * 10 + *String - L'0';
  9447. String++;
  9448. }
  9449. if (EndOfNumber) {
  9450. *EndOfNumber = String;
  9451. }
  9452. return n;
  9453. }
  9454. LONGLONG
  9455. StringToInt64A (
  9456. IN PCSTR String,
  9457. OUT PCSTR *EndOfNumber OPTIONAL
  9458. )
  9459. {
  9460. LONGLONG n;
  9461. BOOL negate = FALSE;
  9462. if (*String == '-') {
  9463. negate = TRUE;
  9464. String++;
  9465. } else if (*String == '+') {
  9466. String++;
  9467. }
  9468. n = 0;
  9469. while (*String >= '0' && *String <= '9') {
  9470. n = n * 10 + *String - '0';
  9471. String++;
  9472. }
  9473. if (negate) {
  9474. n = -n;
  9475. }
  9476. if (EndOfNumber) {
  9477. *EndOfNumber = String;
  9478. }
  9479. return n;
  9480. }
  9481. LONGLONG
  9482. StringToInt64W (
  9483. IN PCWSTR String,
  9484. OUT PCWSTR *EndOfNumber OPTIONAL
  9485. )
  9486. {
  9487. LONGLONG n;
  9488. BOOL negate = FALSE;
  9489. if (*String == L'-') {
  9490. negate = TRUE;
  9491. String++;
  9492. } else if (*String == L'+') {
  9493. String++;
  9494. }
  9495. n = 0;
  9496. while (*String >= L'0' && *String <= L'9') {
  9497. n = n * 10 + *String - L'0';
  9498. String++;
  9499. }
  9500. if (negate) {
  9501. n = -n;
  9502. }
  9503. if (EndOfNumber) {
  9504. *EndOfNumber = String;
  9505. }
  9506. return n;
  9507. }
  9508. BOOL
  9509. TestBuffer (
  9510. IN PCBYTE SrcBuff,
  9511. IN PCBYTE DestBuff,
  9512. IN UINT Size
  9513. )
  9514. {
  9515. while (Size) {
  9516. if (*SrcBuff != *DestBuff) {
  9517. return FALSE;
  9518. }
  9519. SrcBuff ++;
  9520. DestBuff ++;
  9521. Size --;
  9522. }
  9523. return TRUE;
  9524. }