Leaked source code of windows server 2003
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.

1421 lines
36 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. strmap.c
  5. Abstract:
  6. Strmap (formally pathmap) is a fast hueristic-based program that
  7. searches strings and attempts to replace substrings when there
  8. are matching substrings in the mapping database.
  9. Author:
  10. Marc R. Whitten (marcw) 20-Mar-1997
  11. Revision History:
  12. Jim Schmidt (jimschm) 05-Jun-2000 Added multi table capability
  13. Jim Schmidt (jimschm) 08-May-2000 Improved replacement routines and
  14. added consistent filtering and
  15. extra data option
  16. Jim Schmidt (jimschm) 18-Aug-1998 Redesigned to fix two bugs, made
  17. A & W versions
  18. --*/
  19. //
  20. // Includes
  21. //
  22. #include "pch.h"
  23. #include "migutilp.h"
  24. //
  25. // Strings
  26. //
  27. // None
  28. //
  29. // Constants
  30. //
  31. #define CHARNODE_SINGLE_BYTE 0x0000
  32. #define CHARNODE_DOUBLE_BYTE 0x0001
  33. #define CHARNODE_REQUIRE_WACK_OR_NUL 0x0002
  34. //
  35. // Macros
  36. //
  37. // None
  38. //
  39. // Types
  40. //
  41. // None
  42. //
  43. // Globals
  44. //
  45. // None
  46. //
  47. // Macro expansion list
  48. //
  49. // None
  50. //
  51. // Private function prototypes
  52. //
  53. // None
  54. //
  55. // Macro expansion definition
  56. //
  57. // None
  58. //
  59. // Code
  60. //
  61. PMAPSTRUCT
  62. CreateStringMappingEx (
  63. IN BOOL UsesFilters,
  64. IN BOOL UsesExtraData
  65. )
  66. /*++
  67. Routine Description:
  68. CreateStringMapping allocates a string mapping data structure and
  69. initializes it. Callers can enable filter callbacks, extra data support, or
  70. both. The mapping structure contains either CHARNODE elements, or
  71. CHARNODEEX elements, depending on the UsesFilters or UsesExtraData flag.
  72. Arguments:
  73. UsesFilters - Specifies TRUE to enable filter callbacks. If enabled,
  74. those who add string pairs must specify the filter callback
  75. (each search/replace pair has its own callback)
  76. UsesExtraData - Specifies TRUE to associate extra data with the string
  77. mapping pair.
  78. Return Value:
  79. A handle to the string mapping structure, or NULL if a structure could not
  80. be created.
  81. --*/
  82. {
  83. POOLHANDLE Pool;
  84. PMAPSTRUCT Map;
  85. Pool = PoolMemInitNamedPool ("String Mapping");
  86. MYASSERT (Pool);
  87. Map = (PMAPSTRUCT) PoolMemGetAlignedMemory (Pool, sizeof (MAPSTRUCT));
  88. MYASSERT (Map);
  89. ZeroMemory (Map, sizeof (MAPSTRUCT));
  90. Map->Pool = Pool;
  91. Map->UsesExNode = UsesFilters|UsesExtraData;
  92. Map->UsesFilter = UsesFilters;
  93. Map->UsesExtraData = UsesExtraData;
  94. return Map;
  95. }
  96. VOID
  97. DestroyStringMapping (
  98. IN PMAPSTRUCT Map
  99. )
  100. {
  101. if (Map) {
  102. PoolMemEmptyPool (Map->Pool);
  103. PoolMemDestroyPool (Map->Pool);
  104. // Map is no longer valid
  105. }
  106. }
  107. PCHARNODE
  108. pFindCharNode (
  109. IN PMAPSTRUCT Map,
  110. IN PCHARNODE PrevNode, OPTIONAL
  111. IN WORD Char
  112. )
  113. {
  114. PCHARNODE Node;
  115. if (!PrevNode) {
  116. Node = Map->FirstLevelRoot;
  117. } else {
  118. Node = PrevNode->NextLevel;
  119. }
  120. while (Node) {
  121. if (Node->Char == Char) {
  122. return Node;
  123. }
  124. Node = Node->NextPeer;
  125. }
  126. return NULL;
  127. }
  128. PCHARNODE
  129. pAddCharNode (
  130. IN PMAPSTRUCT Map,
  131. IN PCHARNODE PrevNode, OPTIONAL
  132. IN WORD Char,
  133. IN WORD Flags
  134. )
  135. {
  136. PCHARNODE Node;
  137. PCHARNODEEX exNode;
  138. if (Map->UsesExNode) {
  139. exNode = PoolMemGetAlignedMemory (Map->Pool, sizeof (CHARNODEEX));
  140. Node = (PCHARNODE) exNode;
  141. MYASSERT (Node);
  142. ZeroMemory (exNode, sizeof (CHARNODEEX));
  143. } else {
  144. Node = PoolMemGetAlignedMemory (Map->Pool, sizeof (CHARNODE));
  145. MYASSERT (Node);
  146. ZeroMemory (Node, sizeof (CHARNODE));
  147. }
  148. Node->Char = Char;
  149. Node->Flags = Flags;
  150. if (PrevNode) {
  151. Node->NextPeer = PrevNode->NextLevel;
  152. PrevNode->NextLevel = Node;
  153. } else {
  154. Node->NextPeer = Map->FirstLevelRoot;
  155. Map->FirstLevelRoot = Node;
  156. }
  157. return Node;
  158. }
  159. VOID
  160. AddStringMappingPairExA (
  161. IN OUT PMAPSTRUCT Map,
  162. IN PCSTR Old,
  163. IN PCSTR New,
  164. IN REG_REPLACE_FILTER Filter, OPTIONAL
  165. IN ULONG_PTR ExtraData, OPTIONAL
  166. IN DWORD Flags
  167. )
  168. /*++
  169. Routine Description:
  170. AddStringMappingPairEx adds a search and replace string pair to the linked
  171. list data structures. If the same search string is already in the
  172. structures, then the replace string and optional extra data is updated.
  173. Arguments:
  174. Map - Specifies the string mapping
  175. Old - Specifies the search string
  176. New - Specifies the replace string
  177. Filter - Specifies the callback filter. This is only supported if the
  178. map was created with filter support enabled.
  179. ExtraData - Specifies arbitrary data to assign to the search/replace pair.
  180. This is only valid if the map was created with extra data
  181. enabled.
  182. Flags - Specifies optional flag STRMAP_REQUIRE_WACK_OR_NUL
  183. Return Value:
  184. None.
  185. --*/
  186. {
  187. PSTR OldCopy;
  188. PSTR NewCopy;
  189. PCSTR p;
  190. WORD w;
  191. PCHARNODE Prev;
  192. PCHARNODE Node;
  193. PCHARNODEEX exNode;
  194. WORD nodeFlags = 0;
  195. if (Flags & STRMAP_REQUIRE_WACK_OR_NUL) {
  196. nodeFlags = CHARNODE_REQUIRE_WACK_OR_NUL;
  197. }
  198. MYASSERT (Map);
  199. MYASSERT (Old);
  200. MYASSERT (New);
  201. MYASSERT (*Old);
  202. //
  203. // Duplicate strings
  204. //
  205. OldCopy = PoolMemDuplicateStringA (Map->Pool, Old);
  206. NewCopy = PoolMemDuplicateStringA (Map->Pool, New);
  207. //
  208. // Make OldCopy all lowercase
  209. //
  210. CharLowerA (OldCopy);
  211. //
  212. // Add the letters that are not in the mapping
  213. //
  214. for (Prev = NULL, p = OldCopy ; *p ; p = _mbsinc (p)) {
  215. w = (WORD) _mbsnextc (p);
  216. Node = pFindCharNode (Map, Prev, w);
  217. if (!Node) {
  218. break;
  219. }
  220. Prev = Node;
  221. }
  222. for ( ; *p ; p = _mbsinc (p)) {
  223. w = (WORD) _mbsnextc (p);
  224. nodeFlags |= (WORD) (IsLeadByte (p) ? CHARNODE_DOUBLE_BYTE : CHARNODE_SINGLE_BYTE);
  225. Prev = pAddCharNode (Map, Prev, w, nodeFlags);
  226. }
  227. if (Prev) {
  228. StringCopyA (OldCopy, Old);
  229. Prev->OriginalStr = (PVOID) OldCopy;
  230. Prev->ReplacementStr = (PVOID) NewCopy;
  231. Prev->ReplacementBytes = ByteCountA (NewCopy);
  232. exNode = (PCHARNODEEX) Prev;
  233. if (Map->UsesExtraData) {
  234. exNode->ExtraData = ExtraData;
  235. }
  236. if (Map->UsesFilter) {
  237. exNode->Filter = Filter;
  238. }
  239. }
  240. }
  241. VOID
  242. AddStringMappingPairExW (
  243. IN OUT PMAPSTRUCT Map,
  244. IN PCWSTR Old,
  245. IN PCWSTR New,
  246. IN REG_REPLACE_FILTER Filter, OPTIONAL
  247. IN ULONG_PTR ExtraData, OPTIONAL
  248. IN DWORD Flags
  249. )
  250. /*++
  251. Routine Description:
  252. AddStringMappingPairEx adds a search and replace string pair to the linked
  253. list data structures. If the same search string is already in the
  254. structures, then the replace string and optional extra data is updated.
  255. Arguments:
  256. Map - Specifies the string mapping
  257. Old - Specifies the search string
  258. New - Specifies the replace string
  259. Filter - Specifies the callback filter. This is only supported if the
  260. map was created with filter support enabled.
  261. ExtraData - Specifies arbitrary data to assign to the search/replace pair.
  262. This is only valid if the map was created with extra data
  263. enabled.
  264. Flags - Specifies optional flag STRMAP_REQUIRE_WACK_OR_NUL
  265. Return Value:
  266. None.
  267. --*/
  268. {
  269. PWSTR OldCopy;
  270. PWSTR NewCopy;
  271. PCWSTR p;
  272. WORD w;
  273. PCHARNODE Prev;
  274. PCHARNODE Node;
  275. PCHARNODEEX exNode;
  276. WORD nodeFlags = 0;
  277. if (Flags & STRMAP_REQUIRE_WACK_OR_NUL) {
  278. nodeFlags = CHARNODE_REQUIRE_WACK_OR_NUL;
  279. }
  280. MYASSERT (Map);
  281. MYASSERT (Old);
  282. MYASSERT (New);
  283. MYASSERT (*Old);
  284. //
  285. // Duplicate strings
  286. //
  287. OldCopy = PoolMemDuplicateStringW (Map->Pool, Old);
  288. NewCopy = PoolMemDuplicateStringW (Map->Pool, New);
  289. //
  290. // Make OldCopy all lowercase
  291. //
  292. CharLowerW (OldCopy);
  293. //
  294. // Add the letters that are not in the mapping
  295. //
  296. Prev = NULL;
  297. p = OldCopy;
  298. while (w = *p) { // intentional assignment optimization
  299. Node = pFindCharNode (Map, Prev, w);
  300. if (!Node) {
  301. break;
  302. }
  303. Prev = Node;
  304. p++;
  305. }
  306. while (w = *p) { // intentional assignment optimization
  307. Prev = pAddCharNode (Map, Prev, w, nodeFlags);
  308. p++;
  309. }
  310. if (Prev) {
  311. StringCopyW (OldCopy, Old);
  312. Prev->OriginalStr = OldCopy;
  313. Prev->ReplacementStr = (PVOID) NewCopy;
  314. Prev->ReplacementBytes = ByteCountW (NewCopy);
  315. exNode = (PCHARNODEEX) Prev;
  316. if (Map->UsesExtraData) {
  317. exNode->ExtraData = ExtraData;
  318. }
  319. if (Map->UsesFilter) {
  320. exNode->Filter = Filter;
  321. }
  322. }
  323. }
  324. PCSTR
  325. pFindReplacementStringInOneMapA (
  326. IN PMAPSTRUCT Map,
  327. IN PCSTR Source,
  328. IN INT MaxSourceBytes,
  329. OUT PINT SourceBytesPtr,
  330. OUT PINT ReplacementBytesPtr,
  331. IN PREG_REPLACE_DATA Data,
  332. OUT ULONG_PTR *ExtraDataValue, OPTIONAL
  333. IN BOOL RequireWackOrNul
  334. )
  335. {
  336. PCHARNODE BestMatch;
  337. PCHARNODE Node;
  338. WORD Char;
  339. PCSTR OrgSource;
  340. PCSTR newString;
  341. INT newStringSizeInBytes;
  342. PCHARNODEEX exNode;
  343. BOOL replacementFound;
  344. *SourceBytesPtr = 0;
  345. Node = NULL;
  346. BestMatch = NULL;
  347. OrgSource = Source;
  348. while (*Source) {
  349. Char = (WORD) _mbsnextc (Source);
  350. Node = pFindCharNode (Map, Node, Char);
  351. if (Node) {
  352. //
  353. // Advance string pointer
  354. //
  355. if (Node->Flags & CHARNODE_DOUBLE_BYTE) {
  356. Source += 2;
  357. } else {
  358. Source++;
  359. }
  360. if (((PBYTE) Source - (PBYTE) OrgSource) > MaxSourceBytes) {
  361. break;
  362. }
  363. //
  364. // If replacement string is available, keep it
  365. // until a longer match comes along
  366. //
  367. replacementFound = (Node->ReplacementStr != NULL);
  368. if ((RequireWackOrNul || (Node->Flags & CHARNODE_REQUIRE_WACK_OR_NUL)) && replacementFound) {
  369. if (*Source && _mbsnextc (Source) != '\\') {
  370. replacementFound = FALSE;
  371. }
  372. }
  373. if (replacementFound) {
  374. newString = (PCSTR) Node->ReplacementStr;
  375. newStringSizeInBytes = Node->ReplacementBytes;
  376. if (Map->UsesFilter) {
  377. //
  378. // Call rename filter to allow denial of match
  379. //
  380. exNode = (PCHARNODEEX) Node;
  381. if (exNode->Filter) {
  382. Data->Ansi.BeginningOfMatch = OrgSource;
  383. Data->Ansi.OldSubString = (PCSTR) Node->OriginalStr;
  384. Data->Ansi.NewSubString = newString;
  385. Data->Ansi.NewSubStringSizeInBytes = newStringSizeInBytes;
  386. if (!exNode->Filter (Data)) {
  387. replacementFound = FALSE;
  388. } else {
  389. newString = Data->Ansi.NewSubString;
  390. newStringSizeInBytes = Data->Ansi.NewSubStringSizeInBytes;
  391. }
  392. }
  393. }
  394. if (replacementFound) {
  395. BestMatch = Node;
  396. *SourceBytesPtr = (UINT) (UINT_PTR) ((PBYTE) Source - (PBYTE) OrgSource);
  397. }
  398. }
  399. } else {
  400. //
  401. // No Node ends the search
  402. //
  403. break;
  404. }
  405. }
  406. if (BestMatch) {
  407. //
  408. // Return replacement data to caller
  409. //
  410. if (ExtraDataValue) {
  411. if (Map->UsesExtraData) {
  412. exNode = (PCHARNODEEX) BestMatch;
  413. *ExtraDataValue = exNode->ExtraData;
  414. } else {
  415. *ExtraDataValue = 0;
  416. }
  417. }
  418. *ReplacementBytesPtr = newStringSizeInBytes;
  419. return newString;
  420. }
  421. return NULL;
  422. }
  423. PCSTR
  424. pFindReplacementStringA (
  425. IN PMAPSTRUCT *MapArray,
  426. IN UINT MapArrayCount,
  427. IN PCSTR Source,
  428. IN INT MaxSourceBytes,
  429. OUT PINT SourceBytesPtr,
  430. OUT PINT ReplacementBytesPtr,
  431. IN PREG_REPLACE_DATA Data,
  432. OUT ULONG_PTR *ExtraDataValue, OPTIONAL
  433. IN BOOL RequireWackOrNul
  434. )
  435. {
  436. UINT u;
  437. PCSTR result;
  438. for (u = 0 ; u < MapArrayCount ; u++) {
  439. if (!MapArray[u]) {
  440. continue;
  441. }
  442. result = pFindReplacementStringInOneMapA (
  443. MapArray[u],
  444. Source,
  445. MaxSourceBytes,
  446. SourceBytesPtr,
  447. ReplacementBytesPtr,
  448. Data,
  449. ExtraDataValue,
  450. RequireWackOrNul
  451. );
  452. if (result) {
  453. return result;
  454. }
  455. }
  456. return NULL;
  457. }
  458. PCWSTR
  459. pFindReplacementStringInOneMapW (
  460. IN PMAPSTRUCT Map,
  461. IN PCWSTR Source,
  462. IN INT MaxSourceBytes,
  463. OUT PINT SourceBytesPtr,
  464. OUT PINT ReplacementBytesPtr,
  465. IN PREG_REPLACE_DATA Data,
  466. OUT ULONG_PTR *ExtraDataValue, OPTIONAL
  467. IN BOOL RequireWackOrNul
  468. )
  469. {
  470. PCHARNODE BestMatch;
  471. PCHARNODE Node;
  472. PCWSTR OrgSource;
  473. PCWSTR newString;
  474. INT newStringSizeInBytes;
  475. BOOL replacementFound;
  476. PCHARNODEEX exNode;
  477. *SourceBytesPtr = 0;
  478. Node = NULL;
  479. BestMatch = NULL;
  480. OrgSource = Source;
  481. while (*Source) {
  482. Node = pFindCharNode (Map, Node, *Source);
  483. if (Node) {
  484. //
  485. // Advance string pointer
  486. //
  487. Source++;
  488. if (((PBYTE) Source - (PBYTE) OrgSource) > MaxSourceBytes) {
  489. break;
  490. }
  491. //
  492. // If replacement string is available, keep it
  493. // until a longer match comes along
  494. //
  495. replacementFound = (Node->ReplacementStr != NULL);
  496. if ((RequireWackOrNul || (Node->Flags & CHARNODE_REQUIRE_WACK_OR_NUL)) && replacementFound) {
  497. if (*Source && *Source != L'\\') {
  498. replacementFound = FALSE;
  499. }
  500. }
  501. if (replacementFound) {
  502. newString = (PCWSTR) Node->ReplacementStr;
  503. newStringSizeInBytes = Node->ReplacementBytes;
  504. if (Map->UsesFilter) {
  505. //
  506. // Call rename filter to allow denial of match
  507. //
  508. exNode = (PCHARNODEEX) Node;
  509. if (exNode->Filter) {
  510. Data->Unicode.BeginningOfMatch = OrgSource;
  511. Data->Unicode.OldSubString = (PCWSTR) Node->OriginalStr;
  512. Data->Unicode.NewSubString = newString;
  513. Data->Unicode.NewSubStringSizeInBytes = newStringSizeInBytes;
  514. if (!exNode->Filter (Data)) {
  515. replacementFound = FALSE;
  516. } else {
  517. newString = Data->Unicode.NewSubString;
  518. newStringSizeInBytes = Data->Unicode.NewSubStringSizeInBytes;
  519. }
  520. }
  521. }
  522. if (replacementFound) {
  523. BestMatch = Node;
  524. *SourceBytesPtr = (UINT) (UINT_PTR) ((PBYTE) Source - (PBYTE) OrgSource);
  525. }
  526. }
  527. } else {
  528. //
  529. // No Node ends the search
  530. //
  531. break;
  532. }
  533. }
  534. if (BestMatch) {
  535. //
  536. // Return replacement data to caller
  537. //
  538. if (ExtraDataValue) {
  539. if (Map->UsesExtraData) {
  540. exNode = (PCHARNODEEX) BestMatch;
  541. *ExtraDataValue = exNode->ExtraData;
  542. } else {
  543. *ExtraDataValue = 0;
  544. }
  545. }
  546. *ReplacementBytesPtr = newStringSizeInBytes;
  547. return newString;
  548. }
  549. return NULL;
  550. }
  551. PCWSTR
  552. pFindReplacementStringW (
  553. IN PMAPSTRUCT *MapArray,
  554. IN UINT MapArrayCount,
  555. IN PCWSTR Source,
  556. IN INT MaxSourceBytes,
  557. OUT PINT SourceBytesPtr,
  558. OUT PINT ReplacementBytesPtr,
  559. IN PREG_REPLACE_DATA Data,
  560. OUT ULONG_PTR *ExtraDataValue, OPTIONAL
  561. IN BOOL RequireWackOrNul
  562. )
  563. {
  564. UINT u;
  565. PCWSTR result;
  566. for (u = 0 ; u < MapArrayCount ; u++) {
  567. if (!MapArray[u]) {
  568. continue;
  569. }
  570. result = pFindReplacementStringInOneMapW (
  571. MapArray[u],
  572. Source,
  573. MaxSourceBytes,
  574. SourceBytesPtr,
  575. ReplacementBytesPtr,
  576. Data,
  577. ExtraDataValue,
  578. RequireWackOrNul
  579. );
  580. if (result) {
  581. return result;
  582. }
  583. }
  584. return NULL;
  585. }
  586. BOOL
  587. MappingMultiTableSearchAndReplaceExA (
  588. IN PMAPSTRUCT *MapArray,
  589. IN UINT MapArrayCount,
  590. IN PCSTR SrcBuffer,
  591. OUT PSTR Buffer, // can be the same as SrcBuffer
  592. IN INT InboundBytes, OPTIONAL
  593. OUT PINT OutboundBytesPtr, OPTIONAL
  594. IN INT MaxSizeInBytes,
  595. IN DWORD Flags,
  596. OUT ULONG_PTR *ExtraDataValue, OPTIONAL
  597. OUT PCSTR *EndOfString OPTIONAL
  598. )
  599. /*++
  600. Routine Description:
  601. MappingSearchAndReplaceEx performs a search/replace operation based on the
  602. specified string mapping. The replace can be in-place or to another buffer.
  603. Arguments:
  604. MapArray - Specifies an array of string mapping tables that holds
  605. zero or more search/replace pairs
  606. MapArrayCount - Specifies the number of mapping tables in MapArray
  607. SrcBuffer - Specifies the source string that might contain one or
  608. more search strings
  609. Buffer - Specifies the outbound buffer. This arg can be the same
  610. as SrcBuffer.
  611. InboundBytes - Specifies the number of bytes in SrcBuffer to process,
  612. or 0 to process a nul-terminated string in SrcBuffer.
  613. If InboundBytes is specified, it must point to the nul
  614. terminator of SrcBuffer.
  615. OutbountBytesPtr - Receives the number of bytes that Buffer contains,
  616. excluding the nul terminator.
  617. MaxSizeInBytes - Specifies the size of Buffer, in bytes.
  618. Flags - Specifies flags that control the search/replace:
  619. STRMAP_COMPLETE_MATCH_ONLY
  620. STRMAP_FIRST_CHAR_MUST_MATCH
  621. STRMAP_RETURN_AFTER_FIRST_REPLACE
  622. STRMAP_REQUIRE_WACK_OR_NUL
  623. ExtraDataValue - Receives the extra data associated with the first search/
  624. replace pair.
  625. EndOfString - Receives a pointer to the end of the replace string, or
  626. the nul pointer when the entire string is processed. The
  627. pointer is within the string contained in Buffer.
  628. --*/
  629. {
  630. UINT sizeOfTempBuf;
  631. INT inboundSize;
  632. PCSTR lowerCaseSrc;
  633. PCSTR orgSrc;
  634. PCSTR lowerSrcPos;
  635. PCSTR orgSrcPos;
  636. INT orgSrcBytesLeft;
  637. PSTR destPos;
  638. PCSTR lowerSrcEnd;
  639. INT searchStringBytes;
  640. INT replaceStringBytes;
  641. INT destBytesLeft;
  642. REG_REPLACE_DATA filterData;
  643. PCSTR replaceString;
  644. BOOL result = FALSE;
  645. INT i;
  646. PCSTR endPtr;
  647. //
  648. // Empty string case
  649. //
  650. if (*SrcBuffer == 0 || MaxSizeInBytes <= sizeof (CHAR)) {
  651. if (MaxSizeInBytes >= sizeof (CHAR)) {
  652. *Buffer = 0;
  653. }
  654. if (OutboundBytesPtr) {
  655. *OutboundBytesPtr = 0;
  656. }
  657. return FALSE;
  658. }
  659. //
  660. // If caller did not specify inbound size, compute it now
  661. //
  662. if (!InboundBytes) {
  663. InboundBytes = ByteCountA (SrcBuffer);
  664. } else {
  665. i = 0;
  666. while (i < InboundBytes) {
  667. if (IsLeadByte (&SrcBuffer[i])) {
  668. MYASSERT (SrcBuffer[i + 1]);
  669. i += 2;
  670. } else {
  671. i++;
  672. }
  673. }
  674. if (i > InboundBytes) {
  675. InboundBytes--;
  676. }
  677. }
  678. inboundSize = InboundBytes + sizeof (CHAR);
  679. //
  680. // Allocate a buffer big enough for the lower-cased input string,
  681. // plus (optionally) a copy of the entire destination buffer. Then
  682. // copy the data to the buffer.
  683. //
  684. sizeOfTempBuf = inboundSize;
  685. if (SrcBuffer == Buffer) {
  686. sizeOfTempBuf += MaxSizeInBytes;
  687. }
  688. lowerCaseSrc = AllocTextA (sizeOfTempBuf);
  689. if (!lowerCaseSrc) {
  690. return FALSE;
  691. }
  692. CopyMemory ((PSTR) lowerCaseSrc, SrcBuffer, InboundBytes);
  693. *((PSTR) ((PBYTE) lowerCaseSrc + InboundBytes)) = 0;
  694. CharLowerBuffA ((PSTR) lowerCaseSrc, InboundBytes / sizeof (CHAR));
  695. if (SrcBuffer == Buffer && !(Flags & STRMAP_COMPLETE_MATCH_ONLY)) {
  696. orgSrc = (PCSTR) ((PBYTE) lowerCaseSrc + inboundSize);
  697. //
  698. // If we are processing entire inbound string, then just copy the
  699. // whole string. Otherwise, copy the entire destination buffer, so we
  700. // don't lose data beyond the partial inbound string.
  701. //
  702. if (*((PCSTR) ((PBYTE) SrcBuffer + InboundBytes))) {
  703. CopyMemory ((PSTR) orgSrc, SrcBuffer, MaxSizeInBytes);
  704. } else {
  705. CopyMemory ((PSTR) orgSrc, SrcBuffer, inboundSize);
  706. }
  707. } else {
  708. orgSrc = SrcBuffer;
  709. }
  710. //
  711. // Walk the lower cased string, looking for strings to replace
  712. //
  713. orgSrcPos = orgSrc;
  714. lowerSrcPos = lowerCaseSrc;
  715. lowerSrcEnd = (PCSTR) ((PBYTE) lowerSrcPos + InboundBytes);
  716. destPos = Buffer;
  717. destBytesLeft = MaxSizeInBytes - sizeof (CHAR);
  718. filterData.UnicodeData = FALSE;
  719. filterData.Ansi.OriginalString = orgSrc;
  720. filterData.Ansi.CurrentString = Buffer;
  721. endPtr = NULL;
  722. while (lowerSrcPos < lowerSrcEnd) {
  723. replaceString = pFindReplacementStringA (
  724. MapArray,
  725. MapArrayCount,
  726. lowerSrcPos,
  727. (UINT) (UINT_PTR) ((PBYTE) lowerSrcEnd - (PBYTE) lowerSrcPos),
  728. &searchStringBytes,
  729. &replaceStringBytes,
  730. &filterData,
  731. ExtraDataValue,
  732. (Flags & STRMAP_REQUIRE_WACK_OR_NUL) != 0
  733. );
  734. if (replaceString) {
  735. //
  736. // Implement complete match flag
  737. //
  738. if (Flags & STRMAP_COMPLETE_MATCH_ONLY) {
  739. if (InboundBytes != searchStringBytes) {
  740. break;
  741. }
  742. }
  743. result = TRUE;
  744. //
  745. // Verify replacement string isn't growing string too much. If it
  746. // is, truncate the replacement string.
  747. //
  748. if (destBytesLeft < replaceStringBytes) {
  749. //
  750. // Respect logical dbcs characters
  751. //
  752. replaceStringBytes = 0;
  753. i = 0;
  754. while (i < destBytesLeft) {
  755. MYASSERT (replaceString[i]);
  756. if (IsLeadByte (&replaceString[i])) {
  757. MYASSERT (replaceString[i + 1]);
  758. i += 2;
  759. } else {
  760. i++;
  761. }
  762. }
  763. if (i > destBytesLeft) {
  764. destBytesLeft--;
  765. }
  766. replaceStringBytes = destBytesLeft;
  767. } else {
  768. destBytesLeft -= replaceStringBytes;
  769. }
  770. //
  771. // Transfer the memory
  772. //
  773. CopyMemory (destPos, replaceString, replaceStringBytes);
  774. destPos = (PSTR) ((PBYTE) destPos + replaceStringBytes);
  775. lowerSrcPos = (PCSTR) ((PBYTE) lowerSrcPos + searchStringBytes);
  776. orgSrcPos = (PCSTR) ((PBYTE) orgSrcPos + searchStringBytes);
  777. //
  778. // Implement single match flag
  779. //
  780. if (Flags & STRMAP_RETURN_AFTER_FIRST_REPLACE) {
  781. endPtr = destPos;
  782. break;
  783. }
  784. } else if (Flags & (STRMAP_FIRST_CHAR_MUST_MATCH|STRMAP_COMPLETE_MATCH_ONLY)) {
  785. //
  786. // This string does not match any search strings
  787. //
  788. break;
  789. } else {
  790. //
  791. // This character does not match, so copy it to the destination and
  792. // try the next string.
  793. //
  794. if (IsLeadByte (orgSrcPos)) {
  795. //
  796. // Copy double-byte character
  797. //
  798. if (destBytesLeft < sizeof (CHAR) * 2) {
  799. break;
  800. }
  801. MYASSERT (sizeof (CHAR) * 2 == sizeof (WORD));
  802. *((PWORD) destPos)++ = *((PWORD) orgSrcPos)++;
  803. destBytesLeft -= sizeof (WORD);
  804. lowerSrcPos = (PCSTR) ((PBYTE) lowerSrcPos + sizeof (WORD));
  805. } else {
  806. //
  807. // Copy single-byte character
  808. //
  809. if (destBytesLeft < sizeof (CHAR)) {
  810. break;
  811. }
  812. *destPos++ = *orgSrcPos++;
  813. destBytesLeft -= sizeof (CHAR);
  814. lowerSrcPos++;
  815. }
  816. }
  817. }
  818. //
  819. // Copy any remaining part of the original source to the
  820. // destination, unless destPos == Buffer == SrcBuffer
  821. //
  822. if (destPos != SrcBuffer) {
  823. if (*orgSrcPos) {
  824. orgSrcBytesLeft = ByteCountA (orgSrcPos);
  825. orgSrcBytesLeft = min (orgSrcBytesLeft, destBytesLeft);
  826. CopyMemory (destPos, orgSrcPos, orgSrcBytesLeft);
  827. destPos = (PSTR) ((PBYTE) destPos + orgSrcBytesLeft);
  828. }
  829. MYASSERT ((PBYTE) (destPos + 1) <= ((PBYTE) Buffer + MaxSizeInBytes));
  830. *destPos = 0;
  831. if (!endPtr) {
  832. endPtr = destPos;
  833. }
  834. } else {
  835. MYASSERT (SrcBuffer == Buffer);
  836. if (EndOfString || OutboundBytesPtr) {
  837. endPtr = GetEndOfStringA (destPos);
  838. }
  839. }
  840. if (EndOfString) {
  841. MYASSERT (endPtr);
  842. *EndOfString = endPtr;
  843. }
  844. if (OutboundBytesPtr) {
  845. MYASSERT (endPtr);
  846. if (*endPtr) {
  847. endPtr = GetEndOfStringA (endPtr);
  848. }
  849. *OutboundBytesPtr = (UINT) (UINT_PTR) ((PBYTE) endPtr - (PBYTE) Buffer);
  850. }
  851. FreeTextA (lowerCaseSrc);
  852. return result;
  853. }
  854. BOOL
  855. MappingMultiTableSearchAndReplaceExW (
  856. IN PMAPSTRUCT *MapArray,
  857. IN UINT MapArrayCount,
  858. IN PCWSTR SrcBuffer,
  859. OUT PWSTR Buffer, // can be the same as SrcBuffer
  860. IN INT InboundBytes, OPTIONAL
  861. OUT PINT OutboundBytesPtr, OPTIONAL
  862. IN INT MaxSizeInBytes,
  863. IN DWORD Flags,
  864. OUT ULONG_PTR *ExtraDataValue, OPTIONAL
  865. OUT PCWSTR *EndOfString OPTIONAL
  866. )
  867. {
  868. UINT sizeOfTempBuf;
  869. INT inboundSize;
  870. PCWSTR lowerCaseSrc;
  871. PCWSTR orgSrc;
  872. PCWSTR lowerSrcPos;
  873. PCWSTR orgSrcPos;
  874. INT orgSrcBytesLeft;
  875. PWSTR destPos;
  876. PCWSTR lowerSrcEnd;
  877. INT searchStringBytes;
  878. INT replaceStringBytes;
  879. INT destBytesLeft;
  880. REG_REPLACE_DATA filterData;
  881. PCWSTR replaceString;
  882. BOOL result = FALSE;
  883. PCWSTR endPtr;
  884. //
  885. // Empty string case
  886. //
  887. if (*SrcBuffer == 0 || MaxSizeInBytes <= sizeof (CHAR)) {
  888. if (MaxSizeInBytes >= sizeof (CHAR)) {
  889. *Buffer = 0;
  890. }
  891. if (OutboundBytesPtr) {
  892. *OutboundBytesPtr = 0;
  893. }
  894. return FALSE;
  895. }
  896. //
  897. // If caller did not specify inbound size, compute it now
  898. //
  899. if (!InboundBytes) {
  900. InboundBytes = ByteCountW (SrcBuffer);
  901. } else {
  902. InboundBytes = (InboundBytes / sizeof (WCHAR)) * sizeof (WCHAR);
  903. }
  904. inboundSize = InboundBytes + sizeof (WCHAR);
  905. //
  906. // Allocate a buffer big enough for the lower-cased input string,
  907. // plus (optionally) a copy of the entire destination buffer. Then
  908. // copy the data to the buffer.
  909. //
  910. sizeOfTempBuf = inboundSize;
  911. if (SrcBuffer == Buffer) {
  912. sizeOfTempBuf += MaxSizeInBytes;
  913. }
  914. lowerCaseSrc = AllocTextW (sizeOfTempBuf);
  915. if (!lowerCaseSrc) {
  916. return FALSE;
  917. }
  918. CopyMemory ((PWSTR) lowerCaseSrc, SrcBuffer, InboundBytes);
  919. *((PWSTR) ((PBYTE) lowerCaseSrc + InboundBytes)) = 0;
  920. CharLowerBuffW ((PWSTR) lowerCaseSrc, InboundBytes / sizeof (WCHAR));
  921. if (SrcBuffer == Buffer && !(Flags & STRMAP_COMPLETE_MATCH_ONLY)) {
  922. orgSrc = (PCWSTR) ((PBYTE) lowerCaseSrc + inboundSize);
  923. //
  924. // If we are processing entire inbound string, then just copy the
  925. // whole string. Otherwise, copy the entire destination buffer, so we
  926. // don't lose data beyond the partial inbound string.
  927. //
  928. if (*((PCWSTR) ((PBYTE) SrcBuffer + InboundBytes))) {
  929. CopyMemory ((PWSTR) orgSrc, SrcBuffer, MaxSizeInBytes);
  930. } else {
  931. CopyMemory ((PWSTR) orgSrc, SrcBuffer, inboundSize);
  932. }
  933. } else {
  934. orgSrc = SrcBuffer;
  935. }
  936. //
  937. // Walk the lower cased string, looking for strings to replace
  938. //
  939. orgSrcPos = orgSrc;
  940. lowerSrcPos = lowerCaseSrc;
  941. lowerSrcEnd = (PCWSTR) ((PBYTE) lowerSrcPos + InboundBytes);
  942. destPos = Buffer;
  943. destBytesLeft = MaxSizeInBytes - sizeof (WCHAR);
  944. filterData.UnicodeData = TRUE;
  945. filterData.Unicode.OriginalString = orgSrc;
  946. filterData.Unicode.CurrentString = Buffer;
  947. endPtr = NULL;
  948. while (lowerSrcPos < lowerSrcEnd) {
  949. replaceString = pFindReplacementStringW (
  950. MapArray,
  951. MapArrayCount,
  952. lowerSrcPos,
  953. (UINT) (UINT_PTR) ((PBYTE) lowerSrcEnd - (PBYTE) lowerSrcPos),
  954. &searchStringBytes,
  955. &replaceStringBytes,
  956. &filterData,
  957. ExtraDataValue,
  958. (Flags & STRMAP_REQUIRE_WACK_OR_NUL) != 0
  959. );
  960. if (replaceString) {
  961. //
  962. // Implement complete match flag
  963. //
  964. if (Flags & STRMAP_COMPLETE_MATCH_ONLY) {
  965. if (InboundBytes != searchStringBytes) {
  966. break;
  967. }
  968. }
  969. result = TRUE;
  970. //
  971. // Verify replacement string isn't growing string too much. If it
  972. // is, truncate the replacement string.
  973. //
  974. if (destBytesLeft < replaceStringBytes) {
  975. replaceStringBytes = destBytesLeft;
  976. } else {
  977. destBytesLeft -= replaceStringBytes;
  978. }
  979. //
  980. // Transfer the memory
  981. //
  982. CopyMemory (destPos, replaceString, replaceStringBytes);
  983. destPos = (PWSTR) ((PBYTE) destPos + replaceStringBytes);
  984. lowerSrcPos = (PCWSTR) ((PBYTE) lowerSrcPos + searchStringBytes);
  985. orgSrcPos = (PCWSTR) ((PBYTE) orgSrcPos + searchStringBytes);
  986. //
  987. // Implement single match flag
  988. //
  989. if (Flags & STRMAP_RETURN_AFTER_FIRST_REPLACE) {
  990. endPtr = destPos;
  991. break;
  992. }
  993. } else if (Flags & (STRMAP_FIRST_CHAR_MUST_MATCH|STRMAP_COMPLETE_MATCH_ONLY)) {
  994. //
  995. // This string does not match any search strings
  996. //
  997. break;
  998. } else {
  999. //
  1000. // This character does not match, so copy it to the destination and
  1001. // try the next string.
  1002. //
  1003. if (destBytesLeft < sizeof (WCHAR)) {
  1004. break;
  1005. }
  1006. *destPos++ = *orgSrcPos++;
  1007. destBytesLeft -= sizeof (WCHAR);
  1008. lowerSrcPos++;
  1009. }
  1010. }
  1011. //
  1012. // Copy any remaining part of the original source to the
  1013. // destination, unless destPos == Buffer == SrcBuffer
  1014. //
  1015. if (destPos != SrcBuffer) {
  1016. if (*orgSrcPos) {
  1017. orgSrcBytesLeft = ByteCountW (orgSrcPos);
  1018. orgSrcBytesLeft = min (orgSrcBytesLeft, destBytesLeft);
  1019. CopyMemory (destPos, orgSrcPos, orgSrcBytesLeft);
  1020. destPos = (PWSTR) ((PBYTE) destPos + orgSrcBytesLeft);
  1021. }
  1022. MYASSERT ((PBYTE) (destPos + 1) <= ((PBYTE) Buffer + MaxSizeInBytes));
  1023. *destPos = 0;
  1024. if (!endPtr) {
  1025. endPtr = destPos;
  1026. }
  1027. } else {
  1028. MYASSERT (SrcBuffer == Buffer);
  1029. if (EndOfString || OutboundBytesPtr) {
  1030. endPtr = GetEndOfStringW (destPos);
  1031. }
  1032. }
  1033. if (EndOfString) {
  1034. MYASSERT (endPtr);
  1035. *EndOfString = endPtr;
  1036. }
  1037. if (OutboundBytesPtr) {
  1038. MYASSERT (endPtr);
  1039. if (*endPtr) {
  1040. endPtr = GetEndOfStringW (endPtr);
  1041. }
  1042. *OutboundBytesPtr = (UINT) (UINT_PTR) ((PBYTE) endPtr - (PBYTE) Buffer);
  1043. }
  1044. FreeTextW (lowerCaseSrc);
  1045. return result;
  1046. }
  1047. BOOL
  1048. MappingSearchAndReplaceExA (
  1049. IN PMAPSTRUCT Map,
  1050. IN PCSTR SrcBuffer,
  1051. OUT PSTR Buffer, // can be the same as SrcBuffer
  1052. IN INT InboundBytes, OPTIONAL
  1053. OUT PINT OutboundBytesPtr, OPTIONAL
  1054. IN INT MaxSizeInBytes,
  1055. IN DWORD Flags,
  1056. OUT ULONG_PTR *ExtraDataValue, OPTIONAL
  1057. OUT PCSTR *EndOfString OPTIONAL
  1058. )
  1059. {
  1060. return MappingMultiTableSearchAndReplaceExA (
  1061. &Map,
  1062. 1,
  1063. SrcBuffer,
  1064. Buffer,
  1065. InboundBytes,
  1066. OutboundBytesPtr,
  1067. MaxSizeInBytes,
  1068. Flags,
  1069. ExtraDataValue,
  1070. EndOfString
  1071. );
  1072. }
  1073. BOOL
  1074. MappingSearchAndReplaceExW (
  1075. IN PMAPSTRUCT Map,
  1076. IN PCWSTR SrcBuffer,
  1077. OUT PWSTR Buffer, // can be the same as SrcBuffer
  1078. IN INT InboundBytes, OPTIONAL
  1079. OUT PINT OutboundBytesPtr, OPTIONAL
  1080. IN INT MaxSizeInBytes,
  1081. IN DWORD Flags,
  1082. OUT ULONG_PTR *ExtraDataValue, OPTIONAL
  1083. OUT PCWSTR *EndOfString OPTIONAL
  1084. )
  1085. {
  1086. return MappingMultiTableSearchAndReplaceExW (
  1087. &Map,
  1088. 1,
  1089. SrcBuffer,
  1090. Buffer,
  1091. InboundBytes,
  1092. OutboundBytesPtr,
  1093. MaxSizeInBytes,
  1094. Flags,
  1095. ExtraDataValue,
  1096. EndOfString
  1097. );
  1098. }