1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // ============================================================
6 // TextualIdentityParser.cpp
11 // Implements the TextualIdentityParser class
13 // ============================================================
15 #define DISABLE_BINDER_DEBUG_LOGGING
17 #include "textualidentityparser.hpp"
18 #include "assemblyidentity.hpp"
23 #define GO_IF_SEEN(kAssemblyIdentityFlag) \
24 if ((m_dwAttributesSeen & kAssemblyIdentityFlag) != 0) \
31 m_dwAttributesSeen |= kAssemblyIdentityFlag; \
34 #define GO_IF_WILDCARD(valueString) \
36 SmallStackSString wildCard(W("*")); \
37 if (valueString.Equals(wildCard)) \
43 #define GO_IF_VALIDATE_FAILED(validateProc, kIdentityFlag) \
44 if (!validateProc(valueString)) \
51 m_pAssemblyIdentity->SetHave(kIdentityFlag); \
54 #define FROMHEX(a) ((a)>=W('a') ? a - W('a') + 10 : a - W('0'))
55 #define TOHEX(a) ((a)>=10 ? W('a')+(a)-10 : W('0')+(a))
56 #define TOLOWER(a) (((a) >= W('A') && (a) <= W('Z')) ? (W('a') + (a - W('A'))) : (a))
58 namespace BINDER_SPACE
62 const int iPublicKeyTokenLength = 8;
64 const int iPublicKeyMinLength = 0;
65 const int iPublicKeyMaxLength = 2048;
67 const int iVersionMax = 65535;
68 const int iVersionParts = 4;
70 inline void UnicodeHexToBin(LPCWSTR pSrc, UINT cSrc, LPBYTE pDest)
79 for (UINT i = 0; i < cSrc-1; i+=2)
81 v = (BYTE)FROMHEX(TOLOWER(ps[i])) << 4;
82 v |= FROMHEX(TOLOWER(ps[i+1]));
87 inline void BinToUnicodeHex(const BYTE *pSrc, UINT cSrc, __out_ecount(2*cSrc) LPWSTR pDst)
92 for (x = 0, y = 0 ; x < cSrc; ++x)
97 pDst[y++] = (WCHAR)TOHEX(v);
99 pDst[y++] = (WCHAR)TOHEX(v);
103 inline BOOL EqualsCaseInsensitive(SString &a, LPCWSTR wzB)
105 SString b(SString::Literal, wzB);
107 return ::BINDER_SPACE::EqualsCaseInsensitive(a, b);
110 BOOL ValidateHex(SString &publicKeyOrToken)
112 if ((publicKeyOrToken.GetCount() == 0) || ((publicKeyOrToken.GetCount() % 2) != 0))
117 SString::Iterator cursor = publicKeyOrToken.Begin();
118 SString::Iterator end = publicKeyOrToken.End() - 1;
120 while (cursor <= end)
122 WCHAR wcCurrentChar = cursor[0];
124 if (((wcCurrentChar >= W('0')) && (wcCurrentChar <= W('9'))) ||
125 ((wcCurrentChar >= W('a')) && (wcCurrentChar <= W('f'))) ||
126 ((wcCurrentChar >= W('A')) && (wcCurrentChar <= W('F'))))
138 inline BOOL ValidatePublicKeyToken(SString &publicKeyToken)
140 return ((publicKeyToken.GetCount() == (iPublicKeyTokenLength * 2)) &&
141 ValidateHex(publicKeyToken));
144 inline BOOL ValidatePublicKey(SString &publicKey)
147 return ((publicKey.GetCount() >= (iPublicKeyMinLength * 2)) &&
148 (publicKey.GetCount() <= (iPublicKeyMaxLength * 2)) &&
149 ValidateHex(publicKey));
155 } wszKnownArchitectures[] = { { W("x86"), peI386 },
156 { W("IA64"), peIA64 },
157 { W("AMD64"), peAMD64 },
159 { W("MSIL"), peMSIL } };
161 BOOL ValidateAndConvertProcessorArchitecture(SString &processorArchitecture,
162 PEKIND *pkProcessorAchitecture)
164 for (int i = LENGTH_OF(wszKnownArchitectures); i--;)
166 if (EqualsCaseInsensitive(processorArchitecture, wszKnownArchitectures[i].strValue))
168 *pkProcessorAchitecture = wszKnownArchitectures[i].enumValue;
176 LPCWSTR PeKindToString(PEKIND kProcessorArchitecture)
178 _ASSERTE(kProcessorArchitecture != peNone);
180 for (int i = LENGTH_OF(wszKnownArchitectures); i--;)
182 if (wszKnownArchitectures[i].enumValue == kProcessorArchitecture)
184 return wszKnownArchitectures[i].strValue;
191 LPCWSTR ContentTypeToString(AssemblyContentType kContentType)
193 _ASSERTE(kContentType != AssemblyContentType_Default);
195 if (kContentType == AssemblyContentType_WindowsRuntime)
197 return W("WindowsRuntime");
202 }; // namespace (anonymous)
204 TextualIdentityParser::TextualIdentityParser(AssemblyIdentity *pAssemblyIdentity)
206 m_pAssemblyIdentity = pAssemblyIdentity;
207 m_dwAttributesSeen = AssemblyIdentity::IDENTITY_FLAG_EMPTY;
210 TextualIdentityParser::~TextualIdentityParser()
212 // Nothing to do here
215 BOOL TextualIdentityParser::IsSeparatorChar(WCHAR wcChar)
217 return ((wcChar == W(',')) || (wcChar == W('=')));
220 StringLexer::LEXEME_TYPE TextualIdentityParser::GetLexemeType(WCHAR wcChar)
225 return LEXEME_TYPE_EQUALS;
227 return LEXEME_TYPE_COMMA;
229 return LEXEME_TYPE_END_OF_STREAM;
231 return LEXEME_TYPE_STRING;
236 HRESULT TextualIdentityParser::Parse(SString &textualIdentity,
237 AssemblyIdentity *pAssemblyIdentity,
238 BOOL fPermitUnescapedQuotes)
241 BINDER_LOG_ENTER(W("TextualIdentityParser::Parse"));
243 IF_FALSE_GO(pAssemblyIdentity != NULL);
245 BINDER_LOG_STRING(W("textualIdentity"), textualIdentity);
249 TextualIdentityParser identityParser(pAssemblyIdentity);
251 if (!identityParser.Parse(textualIdentity, fPermitUnescapedQuotes))
253 IF_FAIL_GO(FUSION_E_INVALID_NAME);
256 EX_CATCH_HRESULT(hr);
259 BINDER_LOG_LEAVE_HR(W("TextualIdentityParser::Parse"), hr);
264 HRESULT TextualIdentityParser::ToString(AssemblyIdentity *pAssemblyIdentity,
265 DWORD dwIdentityFlags,
266 SString &textualIdentity)
269 BINDER_LOG_ENTER(W("TextualIdentityParser::ToString"));
271 IF_FALSE_GO(pAssemblyIdentity != NULL);
275 SmallStackSString tmpString;
277 textualIdentity.Clear();
279 if (pAssemblyIdentity->m_simpleName.IsEmpty())
284 EscapeString(pAssemblyIdentity->m_simpleName, tmpString);
285 textualIdentity.Append(tmpString);
287 if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_VERSION))
290 tmpString.Printf(W("%d.%d.%d.%d"),
291 (DWORD)(USHORT)pAssemblyIdentity->m_version.GetMajor(),
292 (DWORD)(USHORT)pAssemblyIdentity->m_version.GetMinor(),
293 (DWORD)(USHORT)pAssemblyIdentity->m_version.GetBuild(),
294 (DWORD)(USHORT)pAssemblyIdentity->m_version.GetRevision());
296 textualIdentity.Append(W(", Version="));
297 textualIdentity.Append(tmpString);
300 if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_CULTURE))
302 textualIdentity.Append(W(", Culture="));
303 if (pAssemblyIdentity->m_cultureOrLanguage.IsEmpty())
305 textualIdentity.Append(W("neutral"));
309 EscapeString(pAssemblyIdentity->m_cultureOrLanguage, tmpString);
310 textualIdentity.Append(tmpString);
314 if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY))
316 textualIdentity.Append(W(", PublicKey="));
318 BlobToHex(pAssemblyIdentity->m_publicKeyOrTokenBLOB, tmpString);
319 textualIdentity.Append(tmpString);
321 else if (AssemblyIdentity::Have(dwIdentityFlags,
322 AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN))
324 textualIdentity.Append(W(", PublicKeyToken="));
326 BlobToHex(pAssemblyIdentity->m_publicKeyOrTokenBLOB, tmpString);
327 textualIdentity.Append(tmpString);
329 else if (AssemblyIdentity::Have(dwIdentityFlags,
330 AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL))
332 textualIdentity.Append(W(", PublicKeyToken=null"));
335 if (AssemblyIdentity::Have(dwIdentityFlags,
336 AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE))
338 textualIdentity.Append(W(", processorArchitecture="));
339 textualIdentity.Append(PeKindToString(pAssemblyIdentity->m_kProcessorArchitecture));
342 if (AssemblyIdentity::Have(dwIdentityFlags,
343 AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE))
345 textualIdentity.Append(W(", Retargetable=Yes"));
348 if (AssemblyIdentity::Have(dwIdentityFlags,
349 AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE))
351 textualIdentity.Append(W(", ContentType="));
352 textualIdentity.Append(ContentTypeToString(pAssemblyIdentity->m_kContentType));
355 if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_CUSTOM))
357 textualIdentity.Append(W(", Custom="));
359 BlobToHex(pAssemblyIdentity->m_customBLOB, tmpString);
360 textualIdentity.Append(tmpString);
362 else if (AssemblyIdentity::Have(dwIdentityFlags,
363 AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL))
365 textualIdentity.Append(W(", Custom=null"));
368 EX_CATCH_HRESULT(hr);
371 BINDER_LOG_LEAVE_HR(W("TextualIdentityParser::ToString"), hr);
376 BOOL TextualIdentityParser::ParseVersion(SString &versionString,
377 AssemblyVersion *pAssemblyVersion)
379 BOOL fIsValid = FALSE;
380 DWORD dwFoundNumbers = 0;
381 bool foundUnspecifiedComponent = false;
382 const DWORD UnspecifiedNumber = (DWORD)-1;
383 DWORD dwCurrentNumber = UnspecifiedNumber;
384 DWORD dwNumbers[iVersionParts] = {UnspecifiedNumber, UnspecifiedNumber, UnspecifiedNumber, UnspecifiedNumber};
386 BINDER_LOG_ENTER(W("TextualIdentityParser::ParseVersion"));
388 if (versionString.GetCount() > 0) {
389 SString::Iterator cursor = versionString.Begin();
390 SString::Iterator end = versionString.End();
392 while (cursor <= end)
394 WCHAR wcCurrentChar = cursor[0];
396 if (dwFoundNumbers >= static_cast<DWORD>(iVersionParts))
400 else if (wcCurrentChar == W('.') || wcCurrentChar == W('\0'))
402 if (dwCurrentNumber == UnspecifiedNumber)
404 // Difference from .NET Framework, compat with Version(string) constructor: A missing version component
405 // is considered invalid.
408 // "MyAssembly, Version=."
409 // "MyAssembly, Version=1."
410 // "MyAssembly, Version=.1"
411 // "MyAssembly, Version=1..1"
415 // Compat with .NET Framework: A value of iVersionMax is considered unspecified. Once an unspecified
416 // component is found, validate the remaining components but consider them as unspecified as well.
417 if (dwCurrentNumber == iVersionMax)
419 foundUnspecifiedComponent = true;
420 dwCurrentNumber = UnspecifiedNumber;
422 else if (!foundUnspecifiedComponent)
424 dwNumbers[dwFoundNumbers] = dwCurrentNumber;
425 dwCurrentNumber = UnspecifiedNumber;
430 else if ((wcCurrentChar >= W('0')) && (wcCurrentChar <= W('9')))
432 if (dwCurrentNumber == UnspecifiedNumber)
436 dwCurrentNumber = (dwCurrentNumber * 10) + (wcCurrentChar - W('0'));
438 if (dwCurrentNumber > static_cast<DWORD>(iVersionMax))
451 // Difference from .NET Framework: If the major or minor version are unspecified, the version is considered invalid.
454 // "MyAssembly, Version="
455 // "MyAssembly, Version=1"
456 // "MyAssembly, Version=65535.1"
457 // "MyAssembly, Version=1.65535"
458 if (dwFoundNumbers < 2 || dwNumbers[0] == UnspecifiedNumber || dwNumbers[1] == UnspecifiedNumber)
463 pAssemblyVersion->SetFeatureVersion(dwNumbers[0], dwNumbers[1]);
464 pAssemblyVersion->SetServiceVersion(dwNumbers[2], dwNumbers[3]);
469 BINDER_LOG_LEAVE(W("TextualIdentityParser::ParseVersion"));
474 BOOL TextualIdentityParser::HexToBlob(SString &publicKeyOrToken,
477 SBuffer &publicKeyOrTokenBLOB)
479 // Optional input verification
482 if ((fIsToken && !ValidatePublicKeyToken(publicKeyOrToken)) ||
483 (!fIsToken && !ValidatePublicKey(publicKeyOrToken)))
489 UINT ccPublicKeyOrToken = publicKeyOrToken.GetCount();
490 BYTE *pByteBLOB = publicKeyOrTokenBLOB.OpenRawBuffer(ccPublicKeyOrToken / 2);
492 UnicodeHexToBin(publicKeyOrToken.GetUnicode(), ccPublicKeyOrToken, pByteBLOB);
493 publicKeyOrTokenBLOB.CloseRawBuffer();
499 void TextualIdentityParser::BlobToHex(SBuffer &publicKeyOrTokenBLOB,
500 SString &publicKeyOrToken)
502 UINT cbPublicKeyOrTokenBLOB = publicKeyOrTokenBLOB.GetSize();
503 WCHAR *pwzpublicKeyOrToken =
504 publicKeyOrToken.OpenUnicodeBuffer(cbPublicKeyOrTokenBLOB * 2);
506 BinToUnicodeHex(publicKeyOrTokenBLOB, cbPublicKeyOrTokenBLOB, pwzpublicKeyOrToken);
507 publicKeyOrToken.CloseBuffer(cbPublicKeyOrTokenBLOB * 2);
510 BOOL TextualIdentityParser::Parse(SString &textualIdentity, BOOL fPermitUnescapedQuotes)
512 BOOL fIsValid = TRUE;
513 BINDER_LOG_ENTER(W("TextualIdentityParser::Parse(textualIdentity)"));
514 SString unicodeTextualIdentity;
516 // Lexer modifies input string
517 textualIdentity.ConvertToUnicode(unicodeTextualIdentity);
518 Init(unicodeTextualIdentity, TRUE /* fSupportEscaping */);
520 SmallStackSString currentString;
522 // Identity format is simple name (, attr = value)*
523 GO_IF_NOT_EXPECTED(GetNextLexeme(currentString, fPermitUnescapedQuotes), LEXEME_TYPE_STRING);
524 m_pAssemblyIdentity->m_simpleName.Set(currentString);
525 m_pAssemblyIdentity->m_simpleName.Normalize();
526 m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME);
530 SmallStackSString attributeString;
531 SmallStackSString valueString;
533 GO_IF_END_OR_NOT_EXPECTED(GetNextLexeme(currentString), LEXEME_TYPE_COMMA);
534 GO_IF_NOT_EXPECTED(GetNextLexeme(attributeString), LEXEME_TYPE_STRING);
535 GO_IF_NOT_EXPECTED(GetNextLexeme(currentString), LEXEME_TYPE_EQUALS);
536 GO_IF_NOT_EXPECTED(GetNextLexeme(valueString), LEXEME_TYPE_STRING);
538 if (!PopulateAssemblyIdentity(attributeString, valueString))
546 BINDER_LOG_LEAVE_BOOL(W("TextualIdentityParser::Parse(textualIdentity)"), fIsValid);
550 BOOL TextualIdentityParser::ParseString(SString &textualString,
551 SString &contentString)
553 BOOL fIsValid = TRUE;
554 BINDER_LOG_ENTER(W("TextualIdentityParser::ParseString"));
555 SString unicodeTextualString;
557 // Lexer modifies input string
558 textualString.ConvertToUnicode(unicodeTextualString);
559 Init(unicodeTextualString, TRUE /* fSupportEscaping */);
561 SmallStackSString currentString;
562 GO_IF_NOT_EXPECTED(GetNextLexeme(currentString), LEXEME_TYPE_STRING);
564 contentString.Set(currentString);
565 currentString.Normalize();
568 BINDER_LOG_LEAVE_BOOL(W("TextualIdentityParser::ParseString"), fIsValid);
572 BOOL TextualIdentityParser::PopulateAssemblyIdentity(SString &attributeString,
573 SString &valueString)
575 BINDER_LOG_ENTER(W("TextualIdentityParser::PopulateAssemblyIdentity"));
576 BOOL fIsValid = TRUE;
578 if (EqualsCaseInsensitive(attributeString, W("culture")) ||
579 EqualsCaseInsensitive(attributeString, W("language")))
581 GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_CULTURE);
582 GO_IF_WILDCARD(valueString);
584 if (!EqualsCaseInsensitive(valueString, W("neutral")))
586 // culture/language is preserved as is
587 m_pAssemblyIdentity->m_cultureOrLanguage.Set(valueString);
588 m_pAssemblyIdentity->m_cultureOrLanguage.Normalize();
591 m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_CULTURE);
593 else if (EqualsCaseInsensitive(attributeString, W("version")))
595 AssemblyVersion *pAssemblyVersion = &(m_pAssemblyIdentity->m_version);
597 GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_VERSION);
598 GO_IF_WILDCARD(valueString);
600 if (ParseVersion(valueString, pAssemblyVersion))
602 m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_VERSION);
609 else if (EqualsCaseInsensitive(attributeString, W("publickeytoken")))
611 GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY);
612 GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
613 GO_IF_WILDCARD(valueString);
615 if (!EqualsCaseInsensitive(valueString, W("null")) &&
616 !EqualsCaseInsensitive(valueString, W("neutral")))
618 GO_IF_VALIDATE_FAILED(ValidatePublicKeyToken,
619 AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
620 HexToBlob(valueString,
621 FALSE /* fValidateHex */,
623 m_pAssemblyIdentity->m_publicKeyOrTokenBLOB);
627 m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
630 else if (EqualsCaseInsensitive(attributeString, W("publickey")))
632 GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
633 GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY);
635 if (!EqualsCaseInsensitive(valueString, W("null")) &&
636 !EqualsCaseInsensitive(valueString, W("neutral")))
638 GO_IF_VALIDATE_FAILED(ValidatePublicKey, AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY);
639 HexToBlob(valueString,
640 FALSE /* fValidateHex */,
641 FALSE /* fIsToken */,
642 m_pAssemblyIdentity->m_publicKeyOrTokenBLOB);
645 else if (EqualsCaseInsensitive(attributeString, W("processorarchitecture")))
647 PEKIND kProcessorArchitecture = peNone;
649 GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
650 GO_IF_WILDCARD(valueString);
652 if (ValidateAndConvertProcessorArchitecture(valueString, &kProcessorArchitecture))
654 m_pAssemblyIdentity->m_kProcessorArchitecture = kProcessorArchitecture;
655 m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
662 else if (EqualsCaseInsensitive(attributeString, W("retargetable")))
664 GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
666 if (EqualsCaseInsensitive(valueString, W("yes")))
668 m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
670 else if (!EqualsCaseInsensitive(valueString, W("no")))
675 else if (EqualsCaseInsensitive(attributeString, W("contenttype")))
677 GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
678 GO_IF_WILDCARD(valueString);
680 if (EqualsCaseInsensitive(valueString, W("windowsruntime")))
682 m_pAssemblyIdentity->m_kContentType = AssemblyContentType_WindowsRuntime;
683 m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
690 else if (EqualsCaseInsensitive(attributeString, W("custom")))
692 GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_CUSTOM);
694 if (EqualsCaseInsensitive(valueString, W("null")))
696 m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL);
700 GO_IF_VALIDATE_FAILED(ValidateHex, AssemblyIdentity::IDENTITY_FLAG_CUSTOM);
701 HexToBlob(valueString,
702 FALSE /* fValidateHex */,
703 FALSE /* fIsToken */,
704 m_pAssemblyIdentity->m_customBLOB);
709 // Fusion compat: Silently drop unknown attribute/value pair
710 BINDER_LOG_STRING(W("unknown attribute"), attributeString);
711 BINDER_LOG_STRING(W("unknown value"), valueString);
715 BINDER_LOG_LEAVE_HR(W("TextualIdentityParser::PopulateAssemblyIdentity"),
716 (fIsValid ? S_OK : S_FALSE));
721 void TextualIdentityParser::EscapeString(SString &input,
724 BINDER_LOG_ENTER(W("TextualIdentityParser::EscapeString"));
726 BINDER_LOG_STRING(W("input"), input);
728 BOOL fNeedQuotes = FALSE;
729 WCHAR wcQuoteCharacter = W('"');
731 SmallStackSString tmpString;
732 SString::Iterator cursor = input.Begin();
733 SString::Iterator end = input.End() - 1;
735 // Leading/Trailing white space require quotes
736 if (IsWhitespace(cursor[0]) || IsWhitespace(end[0]))
741 // Fusion textual identity compat: escape all non-quote characters even if quoted
742 while (cursor <= end)
744 WCHAR wcCurrentChar = cursor[0];
746 switch (wcCurrentChar)
750 if (fNeedQuotes && (wcQuoteCharacter != wcCurrentChar))
752 tmpString.Append(wcCurrentChar);
754 else if (!fNeedQuotes)
757 wcQuoteCharacter = (wcCurrentChar == W('"') ? W('\'') : W('"'));
758 tmpString.Append(wcCurrentChar);
762 tmpString.Append(W('\\'));
763 tmpString.Append(wcCurrentChar);
769 tmpString.Append(W('\\'));
770 tmpString.Append(wcCurrentChar);
773 tmpString.Append(W("\\t"));
776 tmpString.Append(W("\\n"));
779 tmpString.Append(W("\\r"));
782 tmpString.Append(wcCurrentChar);
792 result.Append(wcQuoteCharacter);
793 result.Append(tmpString);
794 result.Append(wcQuoteCharacter);
798 result.Set(tmpString);
801 BINDER_LOG_LEAVE(W("TextualIdentityParser::EscapeString"));