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.

1747 lines
55 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. sxsasmidencdec.c
  5. Abstract:
  6. Implementation of the encoding/decoding support for the assembly identity data type.
  7. Author:
  8. Michael Grier (MGrier) 7/28/2000
  9. Revision History:
  10. --*/
  11. #include "stdinc.h"
  12. #include <sxsapi.h>
  13. #include <stdlib.h>
  14. #include <search.h>
  15. #include "idp.h"
  16. static const WCHAR s_rgHexChars[] = L"0123456789abcdef";
  17. typedef struct _CHARPAIR
  18. {
  19. WCHAR wchStart;
  20. WCHAR wchEnd;
  21. } CHARPAIR, *PCHARPAIR;
  22. typedef const CHARPAIR *PCCHARPAIR;
  23. const CHARPAIR s_rgXMLBaseChar[] =
  24. {
  25. { 0x0041, 0x005a },
  26. { 0x0061, 0x007a },
  27. { 0x00c0, 0x00d6 },
  28. { 0x00d8, 0x00f6 },
  29. { 0x00f8, 0x00ff },
  30. { 0x0100, 0x0131 },
  31. { 0x0134, 0x013e },
  32. { 0x0141, 0x0148 },
  33. { 0x014a, 0x017e },
  34. { 0x0180, 0x01c3 },
  35. { 0x01cd, 0x01f0 },
  36. { 0x01f4, 0x01f5 },
  37. { 0x01fa, 0x0217 },
  38. { 0x0250, 0x02a8 },
  39. { 0x02bb, 0x02c1 },
  40. { 0x0386, 0x0386 },
  41. { 0x0388, 0x038a },
  42. { 0x038c, 0x038c },
  43. { 0x038e, 0x03a1 },
  44. { 0x03a3, 0x03ce },
  45. { 0x03d0, 0x03d6 },
  46. { 0x03da, 0x03da },
  47. { 0x03dc, 0x03dc },
  48. { 0x03de, 0x03de },
  49. { 0x03e0, 0x03e0 },
  50. { 0x03e2, 0x03f3 },
  51. { 0x0401, 0x040c },
  52. { 0x040e, 0x044f },
  53. { 0x0451, 0x045c },
  54. { 0x045e, 0x0481 },
  55. { 0x0490, 0x04c4 },
  56. { 0x04c7, 0x04c8 },
  57. { 0x04cb, 0x04cc },
  58. { 0x04d0, 0x04eb },
  59. { 0x04ee, 0x04f5 },
  60. { 0x04f8, 0x04f9 },
  61. { 0x0531, 0x0556 },
  62. { 0x0559, 0x0559 },
  63. { 0x0561, 0x0586 },
  64. { 0x05d0, 0x05ea },
  65. { 0x05f0, 0x05f2 },
  66. { 0x0621, 0x063a },
  67. { 0x0641, 0x064a },
  68. { 0x0671, 0x06b7 },
  69. { 0x06ba, 0x06be },
  70. { 0x06c0, 0x06ce },
  71. { 0x06d0, 0x06d3 },
  72. { 0x06d5, 0x06d5 },
  73. { 0x06e5, 0x06e6 },
  74. { 0x0905, 0x0939 },
  75. { 0x093d, 0x093d },
  76. { 0x0958, 0x0961 },
  77. { 0x0985, 0x098c },
  78. { 0x098f, 0x0990 },
  79. { 0x0993, 0x09a8 },
  80. { 0x09aa, 0x09b0 },
  81. { 0x09b2, 0x09b2 },
  82. { 0x09b6, 0x09b9 },
  83. { 0x09dc, 0x09dd },
  84. { 0x09df, 0x09e1 },
  85. { 0x09f0, 0x09f1 },
  86. { 0x0a05, 0x0a0a },
  87. { 0x0a0f, 0x0a10 },
  88. { 0x0a13, 0x0a28 },
  89. { 0x0a2a, 0x0a30 },
  90. { 0x0a32, 0x0a33 },
  91. { 0x0a35, 0x0a36 },
  92. { 0x0a38, 0x0a39 },
  93. { 0x0a59, 0x0a5c },
  94. { 0x0a5e, 0x0a5e },
  95. { 0x0a72, 0x0a74 },
  96. { 0x0a85, 0x0a8b },
  97. { 0x0a8d, 0x0a8d },
  98. { 0x0a8f, 0x0a91 },
  99. { 0x0a93, 0x0aa8 },
  100. { 0x0aaa, 0x0ab0 },
  101. { 0x0ab2, 0x0ab3 },
  102. { 0x0ab5, 0x0ab9 },
  103. { 0x0abd, 0x0abd },
  104. { 0x0ae0, 0x0ae0 },
  105. { 0x0b05, 0x0b0c },
  106. { 0x0b0f, 0x0b10 },
  107. { 0x0b13, 0x0b28 },
  108. { 0x0b2a, 0x0b30 },
  109. { 0x0b32, 0x0b33 },
  110. { 0x0b36, 0x0b39 },
  111. { 0x0b3d, 0x0b3d },
  112. { 0x0b5c, 0x0b5d },
  113. { 0x0b5f, 0x0b61 },
  114. { 0x0b85, 0x0b8a },
  115. { 0x0b8e, 0x0b90 },
  116. { 0x0b92, 0x0b95 },
  117. { 0x0b99, 0x0b9a },
  118. { 0x0b9c, 0x0b9c },
  119. { 0x0b9e, 0x0b9f },
  120. { 0x0ba3, 0x0ba4 },
  121. { 0x0ba8, 0x0baa },
  122. { 0x0bae, 0x0bb5 },
  123. { 0x0bb7, 0x0bb9 },
  124. { 0x0c05, 0x0c0c },
  125. { 0x0c0e, 0x0c10 },
  126. { 0x0c12, 0x0c28 },
  127. { 0x0c2a, 0x0c33 },
  128. { 0x0c35, 0x0c39 },
  129. { 0x0c60, 0x0c61 },
  130. { 0x0c85, 0x0c8c },
  131. { 0x0c8e, 0x0c90 },
  132. { 0x0c92, 0x0ca8 },
  133. { 0x0caa, 0x0cb3 },
  134. { 0x0cb5, 0x0cb9 },
  135. { 0x0cde, 0x0cde },
  136. { 0x0ce0, 0x0ce1 },
  137. { 0x0d05, 0x0d0c },
  138. { 0x0d0e, 0x0d10 },
  139. { 0x0d12, 0x0d28 },
  140. { 0x0d2a, 0x0d39 },
  141. { 0x0d60, 0x0d61 },
  142. { 0x0e01, 0x0e2e },
  143. { 0x0e30, 0x0e30 },
  144. { 0x0e32, 0x0e33 },
  145. { 0x0e40, 0x0e45 },
  146. { 0x0e81, 0x0e82 },
  147. { 0x0e84, 0x0e84 },
  148. { 0x0e87, 0x0e88 },
  149. { 0x0e8a, 0x0e8a },
  150. { 0x0e8d, 0x0e8d },
  151. { 0x0e94, 0x0e97 },
  152. { 0x0e99, 0x0e9f },
  153. { 0x0ea1, 0x0ea3 },
  154. { 0x0ea5, 0x0ea5 },
  155. { 0x0ea7, 0x0ea7 },
  156. { 0x0eaa, 0x0eab },
  157. { 0x0ead, 0x0eae },
  158. { 0x0eb0, 0x0eb0 },
  159. { 0x0eb2, 0x0eb3 },
  160. { 0x0ebd, 0x0ebd },
  161. { 0x0ec0, 0x0ec4 },
  162. { 0x0f40, 0x0f47 },
  163. { 0x0f49, 0x0f69 },
  164. { 0x10a0, 0x10c5 },
  165. { 0x10d0, 0x10f6 },
  166. { 0x1100, 0x1100 },
  167. { 0x1102, 0x1103 },
  168. { 0x1105, 0x1107 },
  169. { 0x1109, 0x1109 },
  170. { 0x110b, 0x110c },
  171. { 0x110e, 0x1112 },
  172. { 0x113c, 0x113c },
  173. { 0x113e, 0x113e },
  174. { 0x1140, 0x1140 },
  175. { 0x114c, 0x114c },
  176. { 0x114e, 0x114e },
  177. { 0x1150, 0x1150 },
  178. { 0x1154, 0x1155 },
  179. { 0x1159, 0x1159 },
  180. { 0x115f, 0x1161 },
  181. { 0x1163, 0x1163 },
  182. { 0x1165, 0x1165 },
  183. { 0x1167, 0x1167 },
  184. { 0x1169, 0x1169 },
  185. { 0x116d, 0x116e },
  186. { 0x1172, 0x1173 },
  187. { 0x1175, 0x1175 },
  188. { 0x119e, 0x119e },
  189. { 0x11a8, 0x11a8 },
  190. { 0x11ab, 0x11ab },
  191. { 0x11ae, 0x11af },
  192. { 0x11b7, 0x11b8 },
  193. { 0x11ba, 0x11ba },
  194. { 0x11bc, 0x11c2 },
  195. { 0x11eb, 0x11eb },
  196. { 0x11f0, 0x11f0 },
  197. { 0x11f9, 0x11f9 },
  198. { 0x1e00, 0x1e9b },
  199. { 0x1ea0, 0x1ef9 },
  200. { 0x1f00, 0x1f15 },
  201. { 0x1f18, 0x1f1d },
  202. { 0x1f20, 0x1f45 },
  203. { 0x1f48, 0x1f4d },
  204. { 0x1f50, 0x1f57 },
  205. { 0x1f59, 0x1f59 },
  206. { 0x1f5b, 0x1f5b },
  207. { 0x1f5d, 0x1f5d },
  208. { 0x1f5f, 0x1f7d },
  209. { 0x1f80, 0x1fb4 },
  210. { 0x1fb6, 0x1fbc },
  211. { 0x1fbe, 0x1fbe },
  212. { 0x1fc2, 0x1fc4 },
  213. { 0x1fc6, 0x1fcc },
  214. { 0x1fd0, 0x1fd3 },
  215. { 0x1fd6, 0x1fdb },
  216. { 0x1fe0, 0x1fec },
  217. { 0x1ff2, 0x1ff4 },
  218. { 0x1ff6, 0x1ffc },
  219. { 0x2126, 0x2126 },
  220. { 0x212a, 0x212b },
  221. { 0x212e, 0x212e },
  222. { 0x2180, 0x2182 },
  223. { 0x3041, 0x3094 },
  224. { 0x30a1, 0x30fa },
  225. { 0x3105, 0x312c },
  226. { 0xac00, 0xd7a3 },
  227. };
  228. NTSTATUS
  229. RtlSxsComputeAssemblyIdentityEncodedSize(
  230. IN ULONG Flags,
  231. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  232. IN const GUID *EncodingGroup OPTIONAL,
  233. IN ULONG EncodingFormat,
  234. OUT SIZE_T *SizeOut
  235. )
  236. {
  237. NTSTATUS status = STATUS_SUCCESS;
  238. SIZE_T Size = 0;
  239. ULONG i;
  240. ULONG AttributeCount, NamespaceCount;
  241. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *AttributePointerArray = NULL;
  242. PCASSEMBLY_IDENTITY_NAMESPACE *NamespacePointerArray = NULL;
  243. if (SizeOut != NULL)
  244. *SizeOut = 0;
  245. PARAMETER_CHECK(Flags == 0);
  246. PARAMETER_CHECK(AssemblyIdentity != NULL);
  247. PARAMETER_CHECK(SizeOut != NULL);
  248. if (EncodingGroup != NULL) {
  249. status = STATUS_SXS_UNKNOWN_ENCODING_GROUP;
  250. goto Exit;
  251. }
  252. if ((EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_BINARY) &&
  253. (EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_TEXTUAL)) {
  254. status = STATUS_SXS_UNKNOWN_ENCODING;
  255. goto Exit;
  256. }
  257. status = RtlSxspValidateAssemblyIdentity(0, AssemblyIdentity);
  258. if (!NT_SUCCESS(status)) {
  259. goto Exit;
  260. }
  261. AttributeCount = AssemblyIdentity->AttributeCount;
  262. NamespaceCount = AssemblyIdentity->NamespaceCount;
  263. AttributePointerArray = AssemblyIdentity->AttributePointerArray;
  264. NamespacePointerArray = AssemblyIdentity->NamespacePointerArray;
  265. switch (EncodingFormat)
  266. {
  267. case SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_BINARY:
  268. // First, we know we need a header.
  269. Size = sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER);
  270. // Then a ULONG hash per attribute:
  271. Size += (AssemblyIdentity->AttributeCount * sizeof(ULONG));
  272. // Then a USHORT per namespace...
  273. Size += (AssemblyIdentity->NamespaceCount * sizeof(ULONG));
  274. // Then we need an attribute header per attribute:
  275. Size += AssemblyIdentity->AttributeCount * sizeof(ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER);
  276. // Then come the namespace strings...
  277. for (i=0; i<NamespaceCount; i++)
  278. Size += NamespacePointerArray[i]->NamespaceCch * sizeof(WCHAR);
  279. // Then we need space for each of the attributes' names and value.
  280. AttributePointerArray = AssemblyIdentity->AttributePointerArray;
  281. for (i=0; i<AttributeCount; i++)
  282. {
  283. if(AttributePointerArray[i] == NULL) {
  284. status = STATUS_INTERNAL_ERROR;
  285. goto Exit;
  286. }
  287. Size += AttributePointerArray[i]->Attribute.NameCch * sizeof(WCHAR);
  288. Size += AttributePointerArray[i]->Attribute.ValueCch * sizeof(WCHAR);
  289. }
  290. // We should at least be byte aligned here...
  291. ASSERT((Size % 2) == 0);
  292. // And finally pad out to a multiple of four if we are not...
  293. Size = (Size + 3) & ~3;
  294. break;
  295. case SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_TEXTUAL:
  296. for (i=0; i<AttributeCount; i++)
  297. {
  298. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Attribute = AttributePointerArray[i];
  299. BOOLEAN IsAssemblyName = FALSE;
  300. SIZE_T BytesThisAttribute = 0;
  301. if (Attribute == NULL) {
  302. status = STATUS_INTERNAL_ERROR;
  303. goto Exit;
  304. }
  305. status = RtlSxspIsInternalAssemblyIdentityAttribute(
  306. 0,
  307. Attribute,
  308. NULL,
  309. 0,
  310. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME,
  311. NUMBER_OF(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME) - 1,
  312. &IsAssemblyName);
  313. if (!NT_SUCCESS(status)) {
  314. goto Exit;
  315. }
  316. // It's the attribute name. Just account for the size of the encoded value string
  317. status = RtlSxspComputeInternalAssemblyIdentityAttributeEncodedTextualSize(
  318. IsAssemblyName
  319. ? SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_VALUE_ONLY |
  320. SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_OMIT_QUOTES
  321. : 0,
  322. Attribute,
  323. &BytesThisAttribute);
  324. if (!NT_SUCCESS(status)) {
  325. goto Exit;
  326. }
  327. // Account for the separator character
  328. if (i != 0)
  329. Size += sizeof(WCHAR);
  330. Size += BytesThisAttribute;
  331. }
  332. break;
  333. }
  334. *SizeOut = Size;
  335. Exit:
  336. return status;
  337. }
  338. NTSTATUS
  339. RtlSxspComputeQuotedStringSize(
  340. IN ULONG Flags,
  341. IN const WCHAR *StringIn,
  342. IN SIZE_T Cch,
  343. OUT SIZE_T *BytesOut
  344. )
  345. {
  346. NTSTATUS status = STATUS_SUCCESS;
  347. SIZE_T Bytes = 0;
  348. if (BytesOut != NULL)
  349. *BytesOut = 0;
  350. PARAMETER_CHECK(Flags == 0);
  351. PARAMETER_CHECK(StringIn != NULL || Cch == 0);
  352. PARAMETER_CHECK(BytesOut != NULL);
  353. while (Cch != 0)
  354. {
  355. const WCHAR wch = *StringIn++;
  356. if (((wch >= L'A') && (wch <= L'Z')) ||
  357. ((wch >= L'a') && (wch <= L'z')) ||
  358. ((wch >= L'0') && (wch <= L'9')) ||
  359. (wch == L'.') ||
  360. (wch == L'-') ||
  361. (wch == L'_'))
  362. {
  363. Bytes += sizeof(WCHAR);
  364. }
  365. else
  366. {
  367. switch (wch)
  368. {
  369. case L'&':
  370. // &amp;
  371. Bytes += (5 * sizeof(WCHAR));
  372. break;
  373. case L'"':
  374. // &quot;
  375. Bytes += (6 * sizeof(WCHAR));
  376. break;
  377. case L'<':
  378. // &lt;
  379. Bytes += (4 * sizeof(WCHAR));
  380. break;
  381. case L'>':
  382. // &gt;
  383. Bytes += (4 * sizeof(WCHAR));
  384. break;
  385. case L'\'':
  386. // &apos;
  387. Bytes += (6 * sizeof(WCHAR));
  388. break;
  389. default:
  390. // Otherwise, it's going to be &#xn;
  391. if (wch < 0x10)
  392. Bytes += (5 * sizeof(WCHAR));
  393. else if (wch < 0x100)
  394. Bytes += (6 * sizeof(WCHAR));
  395. else if (wch < 0x1000)
  396. Bytes += (7 * sizeof(WCHAR));
  397. else
  398. Bytes += (8 * sizeof(WCHAR));
  399. break;
  400. }
  401. }
  402. Cch--;
  403. }
  404. *BytesOut = Bytes;
  405. return status;
  406. }
  407. NTSTATUS
  408. RtlSxspDequoteString(
  409. IN ULONG dwFlags,
  410. IN PCWSTR pcwszStringIn,
  411. IN SIZE_T cchStringIn,
  412. OUT PWSTR pwszStringOut,
  413. OUT SIZE_T *pcchStringOut
  414. )
  415. {
  416. NTSTATUS status = STATUS_SUCCESS;
  417. PCWSTR pcwszInputCursor = pcwszStringIn;
  418. PWSTR pwszOutputCursor = pwszStringOut;
  419. PCWSTR pcwszInputCursorEnd = pcwszStringIn + cchStringIn;
  420. SIZE_T cchOutputRemaining = 0;
  421. BOOLEAN fInsufficient = FALSE;
  422. PARAMETER_CHECK(dwFlags == 0);
  423. if (pcchStringOut != NULL)
  424. {
  425. cchOutputRemaining = *pcchStringOut;
  426. *pcchStringOut = 0;
  427. }
  428. if (pwszStringOut != NULL)
  429. pwszStringOut[0] = UNICODE_NULL;
  430. PARAMETER_CHECK(pcchStringOut != NULL);
  431. //
  432. // reserve one wchar for trailing NULL
  433. //
  434. #define APPEND_OUTPUT_CHARACTER( toadd ) { \
  435. if ( cchOutputRemaining > 1 ) { \
  436. *pwszOutputCursor++ = (toadd); \
  437. cchOutputRemaining--; \
  438. (*pcchStringOut)++; \
  439. } else fInsufficient = TRUE; \
  440. }
  441. #define CONTAINS_TAG(tag) (RtlSxspCompareStrings(pcwszInputCursor, cchToNextSemicolon, (tag), NUMBER_OF(tag)-1, FALSE) == 0)
  442. #define REPLACE_TAG( tag, newchar ) if ( CONTAINS_TAG(tag) ) { APPEND_OUTPUT_CHARACTER(newchar) }
  443. //
  444. // Zing through the input string until there's nothing left
  445. //
  446. while ((pcwszInputCursor < pcwszInputCursorEnd) && (!fInsufficient))
  447. {
  448. const WCHAR wchCurrent = *pcwszInputCursor;
  449. // Something we know and love?
  450. if (wchCurrent == L'&')
  451. {
  452. SIZE_T cchToNextSemicolon;
  453. PCWSTR pcwszSemicolon = NULL;
  454. pcwszInputCursor++;
  455. cchToNextSemicolon = RtlStringComplimentSpan(
  456. pcwszInputCursor,
  457. pcwszInputCursorEnd,
  458. L";");
  459. pcwszSemicolon = pcwszInputCursor + cchToNextSemicolon;
  460. REPLACE_TAG(L"amp", L'&')
  461. else REPLACE_TAG(L"quot", L'"')
  462. else REPLACE_TAG(L"lt", L'<')
  463. else REPLACE_TAG(L"gt", L'>')
  464. else REPLACE_TAG(L"apos", L'\'')
  465. // This might be an encoded character...
  466. else if ( cchToNextSemicolon >= 2 )
  467. {
  468. BOOLEAN fIsHexString = FALSE;
  469. WCHAR wchReplacement = 0;
  470. // The only non-chunk think accepted is the # character
  471. PARAMETER_CHECK(*pcwszInputCursor == L'#');
  472. // which means we've skipped one
  473. pcwszInputCursor++;
  474. fIsHexString = (*pcwszInputCursor == L'x') || (*pcwszInputCursor == 'X');
  475. if (fIsHexString) {
  476. pcwszInputCursor++;
  477. }
  478. while ( pcwszInputCursor != pcwszSemicolon )
  479. {
  480. if ( fIsHexString )
  481. {
  482. wchReplacement <<= 4;
  483. switch ( *pcwszInputCursor++ ) {
  484. case L'0' : break;
  485. case L'1' : wchReplacement += 0x1; break;
  486. case L'2' : wchReplacement += 0x2; break;
  487. case L'3' : wchReplacement += 0x3; break;
  488. case L'4' : wchReplacement += 0x4; break;
  489. case L'5' : wchReplacement += 0x5; break;
  490. case L'6' : wchReplacement += 0x6; break;
  491. case L'7' : wchReplacement += 0x7; break;
  492. case L'8' : wchReplacement += 0x8; break;
  493. case L'9' : wchReplacement += 0x9; break;
  494. case L'a': case L'A': wchReplacement += 0xA; break;
  495. case L'b': case L'B': wchReplacement += 0xB; break;
  496. case L'c': case L'C': wchReplacement += 0xC; break;
  497. case L'd': case L'D': wchReplacement += 0xD; break;
  498. case L'e': case L'E': wchReplacement += 0xE; break;
  499. case L'f': case L'F': wchReplacement += 0xF; break;
  500. default:
  501. PARAMETER_CHECK(FALSE && L"wchReplacement contains a non-hex digit");
  502. break;
  503. }
  504. }
  505. else
  506. {
  507. wchReplacement *= 10;
  508. switch ( *pcwszInputCursor++ ) {
  509. case L'0' : break;
  510. case L'1' : wchReplacement += 0x1; break;
  511. case L'2' : wchReplacement += 0x2; break;
  512. case L'3' : wchReplacement += 0x3; break;
  513. case L'4' : wchReplacement += 0x4; break;
  514. case L'5' : wchReplacement += 0x5; break;
  515. case L'6' : wchReplacement += 0x6; break;
  516. case L'7' : wchReplacement += 0x7; break;
  517. case L'8' : wchReplacement += 0x8; break;
  518. case L'9' : wchReplacement += 0x9; break;
  519. default:
  520. PARAMETER_CHECK(FALSE && "wchReplacement contains a non-decimal digit");
  521. break;
  522. }
  523. }
  524. }
  525. APPEND_OUTPUT_CHARACTER(wchReplacement);
  526. }
  527. if (!fInsufficient)
  528. pcwszInputCursor = pcwszSemicolon + 1;
  529. }
  530. // Otherwise, simply copy the character to the output string
  531. else
  532. {
  533. APPEND_OUTPUT_CHARACTER(wchCurrent);
  534. if (!fInsufficient)
  535. pcwszInputCursor++;
  536. }
  537. }
  538. if (fInsufficient) {
  539. status = STATUS_BUFFER_TOO_SMALL;
  540. goto Exit;
  541. }
  542. pwszStringOut[*pcchStringOut] = L'\0';
  543. Exit:
  544. return status;
  545. }
  546. NTSTATUS
  547. RtlSxspQuoteString(
  548. IN ULONG Flags,
  549. IN const WCHAR *StringIn,
  550. IN SIZE_T Cch,
  551. IN SIZE_T BufferSize,
  552. IN PVOID Buffer,
  553. OUT SIZE_T *BytesWrittenOut
  554. )
  555. {
  556. NTSTATUS status = STATUS_SUCCESS;
  557. WCHAR *Cursor;
  558. SIZE_T BytesWritten = 0;
  559. SIZE_T BytesLeft = BufferSize;
  560. if (BytesWrittenOut != NULL)
  561. *BytesWrittenOut = 0;
  562. PARAMETER_CHECK(Flags == 0);
  563. PARAMETER_CHECK(StringIn != NULL || Cch == 0);
  564. PARAMETER_CHECK(Buffer != NULL || BufferSize == 0);
  565. Cursor = (WCHAR *) Buffer;
  566. BytesWritten = 0;
  567. while (Cch != 0)
  568. {
  569. const WCHAR wch = *StringIn++;
  570. if (((wch >= L'A') && (wch <= L'Z')) ||
  571. ((wch >= L'a') && (wch <= L'z')) ||
  572. ((wch >= L'0') && (wch <= L'9')) ||
  573. (wch == L'.') ||
  574. (wch == L'-') ||
  575. (wch == L'_'))
  576. {
  577. if (BytesLeft < sizeof(WCHAR)) {
  578. status = STATUS_BUFFER_TOO_SMALL;
  579. goto Exit;
  580. }
  581. *Cursor++ = wch;
  582. BytesLeft -= sizeof(WCHAR);
  583. BytesWritten += sizeof(WCHAR);
  584. }
  585. else
  586. {
  587. #define HANDLE_CASE(_wch, _wstr) \
  588. case _wch: \
  589. { \
  590. ULONG i; \
  591. if (BytesLeft < (sizeof(_wstr) - sizeof(WCHAR))) {\
  592. status = STATUS_BUFFER_TOO_SMALL; goto Exit; }\
  593. for (i=0; i<(NUMBER_OF(_wstr) - 1); i++) \
  594. *Cursor++ = _wstr[i]; \
  595. BytesLeft -= (sizeof(_wstr) - sizeof(WCHAR)); \
  596. BytesWritten += (sizeof(_wstr) - sizeof(WCHAR)); \
  597. break; \
  598. }
  599. switch (wch)
  600. {
  601. HANDLE_CASE(L'"', L"&quot;")
  602. HANDLE_CASE(L'&', L"&amp;")
  603. HANDLE_CASE(L'<', L"&lt;")
  604. HANDLE_CASE(L'>', L"&gt;")
  605. HANDLE_CASE(L'\'', L"&apos;")
  606. default:
  607. if (wch < 0x10)
  608. {
  609. if (BytesLeft < (5 * sizeof(WCHAR))) {
  610. status = STATUS_BUFFER_TOO_SMALL;
  611. goto Exit;
  612. }
  613. *Cursor++ = L'&';
  614. *Cursor++ = L'#';
  615. *Cursor++ = L'x';
  616. *Cursor++ = s_rgHexChars[wch];
  617. *Cursor++ = L';';
  618. BytesWritten += (5 * sizeof(WCHAR));
  619. BytesLeft -= (5 * sizeof(WCHAR));
  620. }
  621. else if (wch < 0x100)
  622. {
  623. if (BytesLeft < (6 * sizeof(WCHAR))) {
  624. status = STATUS_BUFFER_TOO_SMALL;
  625. goto Exit;
  626. }
  627. *Cursor++ = L'&';
  628. *Cursor++ = L'#';
  629. *Cursor++ = L'x';
  630. *Cursor++ = s_rgHexChars[(wch >> 4) & 0xf];
  631. *Cursor++ = s_rgHexChars[wch & 0xf];
  632. *Cursor++ = L';';
  633. BytesWritten += (6 * sizeof(WCHAR));
  634. BytesLeft -= (6 * sizeof(WCHAR));
  635. }
  636. else if (wch < 0x1000)
  637. {
  638. if (BytesLeft < (7 * sizeof(WCHAR))) {
  639. status = STATUS_BUFFER_TOO_SMALL;
  640. goto Exit;
  641. }
  642. *Cursor++ = L'&';
  643. *Cursor++ = L'#';
  644. *Cursor++ = L'x';
  645. *Cursor++ = s_rgHexChars[(wch >> 8) & 0xf];
  646. *Cursor++ = s_rgHexChars[(wch >> 4) & 0xf];
  647. *Cursor++ = s_rgHexChars[wch & 0xf];
  648. *Cursor++ = L';';
  649. BytesWritten += (7 * sizeof(WCHAR));
  650. BytesLeft -= (7 * sizeof(WCHAR));
  651. }
  652. else
  653. {
  654. if (wch > 0xffff) {
  655. status = STATUS_INTERNAL_ERROR;
  656. goto Exit;
  657. }
  658. if (BytesLeft < (8 * sizeof(WCHAR))) {
  659. status = STATUS_BUFFER_TOO_SMALL;
  660. goto Exit;
  661. }
  662. *Cursor++ = L'&';
  663. *Cursor++ = L'#';
  664. *Cursor++ = L'x';
  665. *Cursor++ = s_rgHexChars[(wch >> 12) & 0xf];
  666. *Cursor++ = s_rgHexChars[(wch >> 8) & 0xf];
  667. *Cursor++ = s_rgHexChars[(wch >> 4) & 0xf];
  668. *Cursor++ = s_rgHexChars[wch & 0xf];
  669. *Cursor++ = L';';
  670. BytesWritten += (8 * sizeof(WCHAR));
  671. BytesLeft -= (8 * sizeof(WCHAR));
  672. }
  673. break;
  674. }
  675. }
  676. Cch--;
  677. }
  678. if (BytesWrittenOut != NULL)
  679. *BytesWrittenOut = BytesWritten;
  680. Exit:
  681. return status;
  682. }
  683. NTSTATUS
  684. RtlSxspComputeInternalAssemblyIdentityAttributeEncodedTextualSize(
  685. IN ULONG Flags,
  686. IN PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Attribute,
  687. OUT SIZE_T *BytesOut
  688. )
  689. {
  690. NTSTATUS status = STATUS_SUCCESS;
  691. SIZE_T Bytes = 0;
  692. SIZE_T BytesTemp = 0;
  693. if (BytesOut != NULL)
  694. *BytesOut = 0;
  695. PARAMETER_CHECK((Flags & ~(
  696. SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_VALUE_ONLY |
  697. SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_OMIT_QUOTES)) == 0);
  698. PARAMETER_CHECK(Attribute != NULL);
  699. PARAMETER_CHECK(BytesOut != NULL);
  700. Bytes = 0;
  701. if ((Flags & SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_VALUE_ONLY) == 0)
  702. {
  703. if (Attribute->Attribute.NamespaceCch != 0)
  704. {
  705. // Figure out the ns:n= part
  706. status = RtlSxspComputeQuotedStringSize(0, Attribute->Attribute.Namespace, Attribute->Attribute.NamespaceCch, &BytesTemp);
  707. if (!NT_SUCCESS(status)) {
  708. goto Exit;
  709. }
  710. Bytes += BytesTemp;
  711. Bytes += sizeof(WCHAR); // the ":"
  712. }
  713. status = RtlSxspComputeQuotedStringSize(0, Attribute->Attribute.Name, Attribute->Attribute.NameCch, &BytesTemp);
  714. if (!NT_SUCCESS(status)) {
  715. goto Exit;
  716. }
  717. Bytes += BytesTemp;
  718. Bytes += sizeof(WCHAR); // the "="
  719. }
  720. status = RtlSxspComputeQuotedStringSize(0, Attribute->Attribute.Value, Attribute->Attribute.ValueCch, &BytesTemp);
  721. if (!NT_SUCCESS(status)) {
  722. goto Exit;
  723. }
  724. Bytes += BytesTemp;
  725. if ((Flags & SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_OMIT_QUOTES) == 0)
  726. Bytes += 2 * sizeof(WCHAR); // the beginning and ending quotes
  727. *BytesOut = Bytes;
  728. Exit:
  729. return status;
  730. }
  731. NTSTATUS
  732. RtlSxspEncodeInternalAssemblyIdentityAttributeAsText(
  733. IN ULONG Flags,
  734. IN PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Attribute,
  735. SIZE_T BufferSize,
  736. PVOID Buffer,
  737. SIZE_T *BytesWrittenOut
  738. )
  739. {
  740. NTSTATUS status = STATUS_SUCCESS;
  741. SIZE_T BytesWritten = 0;
  742. SIZE_T BytesLeft = 0;
  743. SIZE_T BytesThisSegment;
  744. WCHAR *Cursor;
  745. if (BytesWrittenOut != NULL)
  746. *BytesWrittenOut = 0;
  747. PARAMETER_CHECK(Flags == 0);
  748. PARAMETER_CHECK(Attribute != NULL);
  749. PARAMETER_CHECK((Buffer != NULL) || (BufferSize == 0));
  750. BytesWritten = 0;
  751. BytesLeft = BufferSize;
  752. Cursor = (PWSTR)Buffer;
  753. if (Attribute->Attribute.NamespaceCch != 0)
  754. {
  755. status = RtlSxspQuoteString(0, Attribute->Namespace->Namespace, Attribute->Namespace->NamespaceCch, BytesLeft, Cursor, &BytesThisSegment);
  756. if (!NT_SUCCESS(status)) {
  757. goto Exit;
  758. }
  759. if (BytesThisSegment > BytesLeft) {
  760. status = STATUS_INTERNAL_ERROR;
  761. goto Exit;
  762. }
  763. Cursor = (WCHAR *) (((ULONG_PTR) Cursor) + BytesThisSegment);
  764. BytesLeft -= BytesThisSegment;
  765. BytesWritten += BytesThisSegment;
  766. if (BytesLeft < sizeof(WCHAR)) {
  767. status = STATUS_BUFFER_TOO_SMALL;
  768. goto Exit;
  769. }
  770. *Cursor++ = L':';
  771. BytesLeft -= sizeof(WCHAR);
  772. BytesWritten += sizeof(WCHAR);
  773. }
  774. status = RtlSxspQuoteString(0, Attribute->Attribute.Name, Attribute->Attribute.NameCch, BytesLeft, Cursor, &BytesThisSegment);
  775. if (!NT_SUCCESS(status)) {
  776. goto Exit;
  777. }
  778. if (BytesThisSegment > BytesLeft) {
  779. status = STATUS_INTERNAL_ERROR;
  780. goto Exit;
  781. }
  782. Cursor = (WCHAR *) (((ULONG_PTR) Cursor) + BytesThisSegment);
  783. BytesLeft -= BytesThisSegment;
  784. BytesWritten += BytesThisSegment;
  785. if (BytesLeft < (2 * sizeof(WCHAR))) {
  786. status = STATUS_BUFFER_TOO_SMALL;
  787. goto Exit;
  788. }
  789. *Cursor++ = L'=';
  790. *Cursor++ = L'"';
  791. BytesLeft -= (2 * sizeof(WCHAR));
  792. BytesWritten += (2 * sizeof(WCHAR));
  793. status = RtlSxspQuoteString(0, Attribute->Attribute.Value, Attribute->Attribute.ValueCch, BytesLeft, Cursor, &BytesThisSegment);
  794. if (!NT_SUCCESS(status)) {
  795. goto Exit;
  796. }
  797. if (BytesThisSegment > BytesLeft) {
  798. status = STATUS_INTERNAL_ERROR;
  799. goto Exit;
  800. }
  801. Cursor = (WCHAR *) (((ULONG_PTR) Cursor) + BytesThisSegment);
  802. BytesLeft -= BytesThisSegment;
  803. BytesWritten += BytesThisSegment;
  804. if (BytesLeft < sizeof(WCHAR)) {
  805. status = STATUS_BUFFER_TOO_SMALL;
  806. goto Exit;
  807. }
  808. *Cursor++ = L'"';
  809. BytesLeft -= sizeof(WCHAR);
  810. BytesWritten += sizeof(WCHAR);
  811. *BytesWrittenOut = BytesWritten;
  812. Exit:
  813. return status;
  814. }
  815. NTSTATUS
  816. RtlSxspEncodeAssemblyIdentityTextually(
  817. IN ULONG Flags,
  818. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  819. IN SIZE_T BufferSize,
  820. IN PVOID Buffer,
  821. OUT SIZE_T *BytesWrittenOut)
  822. {
  823. NTSTATUS status = STATUS_SUCCESS;
  824. ULONG AttributeCount, NamespaceCount;
  825. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *Attributes;
  826. PCASSEMBLY_IDENTITY_NAMESPACE *Namespaces;
  827. ULONG i;
  828. ASSEMBLY_IDENTITY_ATTRIBUTE Attribute;
  829. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE NameInternalAttribute = NULL;
  830. SIZE_T BytesLeft;
  831. SIZE_T BytesWritten;
  832. PVOID Cursor;
  833. SIZE_T TempBytesWritten;
  834. if (BytesWrittenOut != NULL)
  835. *BytesWrittenOut = 0;
  836. PARAMETER_CHECK(Flags == 0);
  837. PARAMETER_CHECK(AssemblyIdentity != NULL);
  838. PARAMETER_CHECK(BufferSize != 0);
  839. PARAMETER_CHECK(Buffer != NULL);
  840. PARAMETER_CHECK(BytesWrittenOut != NULL);
  841. Cursor = Buffer;
  842. BytesLeft = BufferSize;
  843. BytesWritten = 0;
  844. // The root assembly identity is actually totally empty, so we'll short-circuit that case.
  845. AttributeCount = AssemblyIdentity->AttributeCount;
  846. if (AttributeCount != 0)
  847. {
  848. NamespaceCount = AssemblyIdentity->NamespaceCount;
  849. Attributes = AssemblyIdentity->AttributePointerArray;
  850. Namespaces = AssemblyIdentity->NamespacePointerArray;
  851. // First, let's look for the "name" attribute.
  852. Attribute.Flags = 0;
  853. Attribute.Namespace = NULL;
  854. Attribute.NamespaceCch = 0;
  855. Attribute.Name = SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME;
  856. Attribute.NameCch = NUMBER_OF(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME) - 1;
  857. status = RtlSxspLocateInternalAssemblyIdentityAttribute(
  858. SXSP_LOCATE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_FLAG_MATCH_NAMESPACE |
  859. SXSP_LOCATE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_FLAG_MATCH_NAME,
  860. AssemblyIdentity,
  861. &Attribute,
  862. &NameInternalAttribute,
  863. NULL);
  864. if (!NT_SUCCESS(status)) {
  865. goto Exit;
  866. } else if (NameInternalAttribute == NULL) {
  867. status = STATUS_INTERNAL_ERROR;
  868. goto Exit;
  869. }
  870. status = RtlSxspQuoteString(0, NameInternalAttribute->Attribute.Value, NameInternalAttribute->Attribute.ValueCch, BytesLeft, Cursor, &TempBytesWritten);
  871. if (!NT_SUCCESS(status)) {
  872. goto Exit;
  873. }
  874. else if (TempBytesWritten > BytesLeft) {
  875. status = STATUS_INTERNAL_ERROR;
  876. goto Exit;
  877. }
  878. Cursor = (PVOID) (((ULONG_PTR) Cursor) + TempBytesWritten);
  879. BytesLeft -= TempBytesWritten;
  880. BytesWritten += TempBytesWritten;
  881. for (i=0; i<AttributeCount; i++)
  882. {
  883. // Skip the standard "name" attribute
  884. if (Attributes[i] == NameInternalAttribute)
  885. continue;
  886. if (BytesLeft < sizeof(WCHAR)) {
  887. status = STATUS_BUFFER_TOO_SMALL;
  888. goto Exit;
  889. }
  890. *((WCHAR *) Cursor) = L',';
  891. Cursor = (PVOID) (((ULONG_PTR) Cursor) + sizeof(WCHAR));
  892. BytesLeft -= sizeof(WCHAR);
  893. BytesWritten += sizeof(WCHAR);
  894. status = RtlSxspEncodeInternalAssemblyIdentityAttributeAsText(0, Attributes[i], BytesLeft, Cursor, &TempBytesWritten);
  895. if (!NT_SUCCESS(status)) {
  896. goto Exit;
  897. }
  898. else if (TempBytesWritten > BytesLeft) {
  899. status = STATUS_INTERNAL_ERROR;
  900. goto Exit;
  901. }
  902. Cursor = (PVOID) (((ULONG_PTR) Cursor) + TempBytesWritten);
  903. BytesLeft -= TempBytesWritten;
  904. BytesWritten += TempBytesWritten;
  905. }
  906. }
  907. *BytesWrittenOut = BytesWritten;
  908. Exit:
  909. return status;
  910. }
  911. #define IFNTFAILED_EXIT(q) do { status = (q); if (!NT_SUCCESS(status)) { goto Exit; } } while (0)
  912. NTSTATUS
  913. RtlSxsEncodeAssemblyIdentity(
  914. IN ULONG Flags,
  915. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  916. IN const GUID *EncodingGroup OPTIONAL, // use NULL to use any of the SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_* encodings
  917. IN ULONG EncodingFormat,
  918. IN SIZE_T BufferSize,
  919. OUT PVOID Buffer,
  920. OUT SIZE_T *BytesWrittenOrRequired
  921. )
  922. {
  923. NTSTATUS status = STATUS_SUCCESS;
  924. SIZE_T TotalSize = 0;
  925. PVOID Cursor = NULL;
  926. SIZE_T i;
  927. PENCODED_ASSEMBLY_IDENTITY_HEADER EncodedAssemblyIdentityHeader = NULL;
  928. PENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER EncodedAssemblyIdentityAttributeHeader = NULL;
  929. ULONG *TempULONGArrayPointer;
  930. SIZE_T BytesWritten = 0;
  931. ULONG AttributeCount, NamespaceCount;
  932. if (BytesWrittenOrRequired != NULL)
  933. *BytesWrittenOrRequired = 0;
  934. PARAMETER_CHECK(Flags == 0);
  935. PARAMETER_CHECK(AssemblyIdentity != NULL);
  936. PARAMETER_CHECK((BufferSize == 0) || (Buffer != NULL));
  937. PARAMETER_CHECK((BufferSize != 0) || (BytesWrittenOrRequired != NULL));
  938. if (EncodingGroup != NULL) {
  939. status = STATUS_SXS_UNKNOWN_ENCODING_GROUP;
  940. goto Exit;
  941. }
  942. if ((EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_BINARY) &&
  943. (EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_TEXTUAL))
  944. {
  945. status = STATUS_SXS_UNKNOWN_ENCODING_GROUP;
  946. goto Exit;
  947. }
  948. IFNTFAILED_EXIT(RtlSxspValidateAssemblyIdentity(0, AssemblyIdentity));
  949. IFNTFAILED_EXIT(RtlSxsComputeAssemblyIdentityEncodedSize(0, AssemblyIdentity, EncodingGroup, EncodingFormat, &TotalSize));
  950. if (TotalSize > BufferSize)
  951. {
  952. if (BytesWrittenOrRequired != NULL)
  953. *BytesWrittenOrRequired = TotalSize;
  954. status = STATUS_BUFFER_TOO_SMALL;
  955. goto Exit;
  956. }
  957. AttributeCount = AssemblyIdentity->AttributeCount;
  958. NamespaceCount = AssemblyIdentity->NamespaceCount;
  959. //
  960. // Let's start filling it in.
  961. //
  962. switch (EncodingFormat)
  963. {
  964. case SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_BINARY:
  965. BytesWritten = 0;
  966. Cursor = Buffer;
  967. EncodedAssemblyIdentityHeader = (PENCODED_ASSEMBLY_IDENTITY_HEADER) Cursor;
  968. Cursor = (PVOID) (((ULONG_PTR) Cursor) + sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER));
  969. BytesWritten += sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER);
  970. EncodedAssemblyIdentityHeader->HeaderSize = sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER);
  971. EncodedAssemblyIdentityHeader->Magic = ENCODED_ASSEMBLY_IDENTITY_HEADER_MAGIC;
  972. EncodedAssemblyIdentityHeader->TotalSize = (ULONG)TotalSize;
  973. // turn off any flags not relevant to persisted state
  974. EncodedAssemblyIdentityHeader->Type = AssemblyIdentity->Type;
  975. EncodedAssemblyIdentityHeader->Flags = AssemblyIdentity->Flags & ~(ASSEMBLY_IDENTITY_FLAG_FROZEN);
  976. EncodedAssemblyIdentityHeader->EncodingFlags = 0;
  977. EncodedAssemblyIdentityHeader->AttributeCount = AttributeCount;
  978. EncodedAssemblyIdentityHeader->NamespaceCount = NamespaceCount;
  979. EncodedAssemblyIdentityHeader->ReservedMustBeZero1 = 0;
  980. EncodedAssemblyIdentityHeader->ReservedMustBeZero2 = 0;
  981. EncodedAssemblyIdentityHeader->ReservedMustBeZero3 = 0;
  982. EncodedAssemblyIdentityHeader->ReservedMustBeZero4 = 0;
  983. TempULONGArrayPointer = (ULONG *) Cursor;
  984. Cursor = (PVOID) (TempULONGArrayPointer + AttributeCount);
  985. BytesWritten += (AttributeCount * sizeof(ULONG));
  986. for (i=0; i<AttributeCount; i++)
  987. TempULONGArrayPointer[i] = AssemblyIdentity->AttributePointerArray[i]->WholeAttributeHash;
  988. // sort 'em...
  989. qsort(TempULONGArrayPointer, AttributeCount, sizeof(ULONG), &RtlSxspCompareULONGsForQsort);
  990. TempULONGArrayPointer = (ULONG *) Cursor;
  991. Cursor = (PVOID) (TempULONGArrayPointer + NamespaceCount);
  992. BytesWritten += (sizeof(ULONG) * NamespaceCount);
  993. for (i=0; i<NamespaceCount; i++)
  994. TempULONGArrayPointer[i] = (ULONG)(AssemblyIdentity->NamespacePointerArray[i]->NamespaceCch);
  995. EncodedAssemblyIdentityAttributeHeader = (PENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER) Cursor;
  996. Cursor = (PVOID) (EncodedAssemblyIdentityAttributeHeader + AttributeCount);
  997. BytesWritten += (AttributeCount * sizeof(ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER));
  998. for (i=0; i<AttributeCount; i++)
  999. {
  1000. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE InternalAttribute = AssemblyIdentity->AttributePointerArray[i];
  1001. ULONG NamespaceIndex;
  1002. // Totally gross linear search to determine the namespace index. Fortunately the common case
  1003. // will be a single namespace for all attributes.
  1004. for (NamespaceIndex = 0; NamespaceIndex < NamespaceCount; NamespaceIndex++)
  1005. {
  1006. if (AssemblyIdentity->NamespacePointerArray[NamespaceIndex] == InternalAttribute->Namespace)
  1007. break;
  1008. }
  1009. // If this assert fires, the attribute refers to a namespace that's not in the identity; bad!
  1010. if((InternalAttribute->Namespace != NULL) && (NamespaceIndex >= NamespaceCount)) {
  1011. status = STATUS_INTERNAL_ERROR;
  1012. goto Exit;
  1013. }
  1014. EncodedAssemblyIdentityAttributeHeader[i].NamespaceIndex = NamespaceIndex + 1;
  1015. EncodedAssemblyIdentityAttributeHeader[i].NameCch = (ULONG)(InternalAttribute->Attribute.NameCch);
  1016. EncodedAssemblyIdentityAttributeHeader[i].ValueCch = (ULONG)(InternalAttribute->Attribute.ValueCch);
  1017. }
  1018. // so much for the fixed length stuff; write the namespaces.
  1019. for (i=0; i<NamespaceCount; i++)
  1020. {
  1021. PWSTR psz = (PWSTR) Cursor;
  1022. Cursor = (PVOID) (((ULONG_PTR) psz) + (AssemblyIdentity->NamespacePointerArray[i]->NamespaceCch * sizeof(WCHAR)));
  1023. BytesWritten += (AssemblyIdentity->NamespacePointerArray[i]->NamespaceCch * sizeof(WCHAR));
  1024. memcpy(
  1025. psz,
  1026. AssemblyIdentity->NamespacePointerArray[i]->Namespace,
  1027. AssemblyIdentity->NamespacePointerArray[i]->NamespaceCch * sizeof(WCHAR));
  1028. }
  1029. // And the attributes...
  1030. for (i=0; i<AttributeCount; i++)
  1031. {
  1032. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE InternalAttribute = AssemblyIdentity->AttributePointerArray[i];
  1033. PWSTR psz;
  1034. psz = (PWSTR) Cursor;
  1035. Cursor = (PVOID) (((ULONG_PTR) psz) + (InternalAttribute->Attribute.NameCch * sizeof(WCHAR)));
  1036. BytesWritten += (InternalAttribute->Attribute.NameCch * sizeof(WCHAR));
  1037. memcpy(
  1038. psz,
  1039. InternalAttribute->Attribute.Name,
  1040. InternalAttribute->Attribute.NameCch * sizeof(WCHAR));
  1041. psz = (PWSTR) Cursor;
  1042. Cursor = (PVOID) (((ULONG_PTR) psz) + InternalAttribute->Attribute.ValueCch * sizeof(WCHAR));
  1043. BytesWritten += InternalAttribute->Attribute.ValueCch * sizeof(WCHAR);
  1044. memcpy(
  1045. psz,
  1046. InternalAttribute->Attribute.Value,
  1047. InternalAttribute->Attribute.ValueCch * sizeof(WCHAR));
  1048. }
  1049. if ((BytesWritten % 4) != 0) {
  1050. ASSERT((BytesWritten % 4) == sizeof(USHORT));
  1051. *((USHORT *) Cursor) = 0;
  1052. BytesWritten += sizeof(USHORT);
  1053. }
  1054. break;
  1055. case SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_TEXTUAL:
  1056. IFNTFAILED_EXIT(RtlSxspEncodeAssemblyIdentityTextually(0, AssemblyIdentity, BufferSize, Buffer, &BytesWritten));
  1057. break;
  1058. }
  1059. if (BytesWritten != TotalSize) {
  1060. status = STATUS_INTERNAL_ERROR;
  1061. goto Exit;
  1062. }
  1063. if (BytesWrittenOrRequired != NULL)
  1064. *BytesWrittenOrRequired = BytesWritten;
  1065. Exit:
  1066. return status;
  1067. }
  1068. NTSTATUS
  1069. RtlSxsDecodeAssemblyIdentity(
  1070. ULONG Flags,
  1071. IN const GUID *EncodingGroup,
  1072. IN ULONG EncodingFormat,
  1073. IN SIZE_T BufferSize,
  1074. IN const VOID *Buffer,
  1075. OUT PASSEMBLY_IDENTITY *AssemblyIdentityOut
  1076. )
  1077. {
  1078. NTSTATUS status = STATUS_SUCCESS;
  1079. PCENCODED_ASSEMBLY_IDENTITY_HEADER EncodedAssemblyIdentityHeader = NULL;
  1080. PCENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER EncodedAssemblyIdentityAttributeHeader = NULL;
  1081. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *AttributePointerArray = NULL;
  1082. PCASSEMBLY_IDENTITY_NAMESPACE *NamespacePointerArray = NULL;
  1083. PASSEMBLY_IDENTITY AssemblyIdentity = NULL;
  1084. ULONG AttributeCount = 0;
  1085. ULONG NamespaceCount = 0;
  1086. ULONG AttributeArraySize = 0;
  1087. ULONG NamespaceArraySize = 0;
  1088. ULONG i;
  1089. const ULONG *NamespaceLengthArray = NULL;
  1090. const ULONG *AttributeHashArray = NULL;
  1091. const WCHAR *UnicodeStringArray = NULL;
  1092. if (AssemblyIdentityOut != NULL)
  1093. *AssemblyIdentityOut = NULL;
  1094. PARAMETER_CHECK((Flags & ~(SXS_DECODE_ASSEMBLY_IDENTITY_FLAG_FREEZE)) == 0);
  1095. PARAMETER_CHECK(BufferSize >= sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER));
  1096. PARAMETER_CHECK(Buffer != NULL);
  1097. PARAMETER_CHECK(AssemblyIdentityOut != NULL);
  1098. if (EncodingGroup != NULL) {
  1099. status = STATUS_SXS_UNKNOWN_ENCODING_GROUP;
  1100. goto Exit;
  1101. }
  1102. if ((EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_BINARY) &&
  1103. (EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_TEXTUAL)) {
  1104. status = STATUS_SXS_UNKNOWN_ENCODING;
  1105. goto Exit;
  1106. }
  1107. EncodedAssemblyIdentityHeader = (PCENCODED_ASSEMBLY_IDENTITY_HEADER) Buffer;
  1108. if ((EncodedAssemblyIdentityHeader->HeaderSize != sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER)) ||
  1109. (EncodedAssemblyIdentityHeader->Magic != ENCODED_ASSEMBLY_IDENTITY_HEADER_MAGIC) ||
  1110. (EncodedAssemblyIdentityHeader->TotalSize > BufferSize) ||
  1111. (EncodedAssemblyIdentityHeader->Flags != 0) ||
  1112. ((EncodedAssemblyIdentityHeader->Type != ASSEMBLY_IDENTITY_TYPE_DEFINITION) &&
  1113. (EncodedAssemblyIdentityHeader->Type != ASSEMBLY_IDENTITY_TYPE_REFERENCE) &&
  1114. (EncodedAssemblyIdentityHeader->Type != ASSEMBLY_IDENTITY_TYPE_WILDCARD)) ||
  1115. (EncodedAssemblyIdentityHeader->EncodingFlags != 0) ||
  1116. (EncodedAssemblyIdentityHeader->ReservedMustBeZero1 != 0) ||
  1117. (EncodedAssemblyIdentityHeader->ReservedMustBeZero2 != 0) ||
  1118. (EncodedAssemblyIdentityHeader->ReservedMustBeZero3 != 0) ||
  1119. (EncodedAssemblyIdentityHeader->ReservedMustBeZero4 != 0)) {
  1120. status = STATUS_INVALID_PARAMETER;
  1121. goto Exit;
  1122. }
  1123. AssemblyIdentity = (PASSEMBLY_IDENTITY)RtlAllocateHeap(
  1124. RtlProcessHeap(),
  1125. HEAP_ZERO_MEMORY,
  1126. sizeof(ASSEMBLY_IDENTITY));
  1127. if (AssemblyIdentity == NULL) {
  1128. status = STATUS_NO_MEMORY;
  1129. goto Exit;
  1130. }
  1131. NamespaceCount = EncodedAssemblyIdentityHeader->NamespaceCount;
  1132. if (Flags & SXS_DECODE_ASSEMBLY_IDENTITY_FLAG_FREEZE)
  1133. {
  1134. NamespaceArraySize = NamespaceCount;
  1135. }
  1136. else if (NamespaceCount == 0)
  1137. {
  1138. NamespaceArraySize = 8;
  1139. }
  1140. else
  1141. {
  1142. NamespaceArraySize = (NamespaceCount + 7) & ~7;
  1143. }
  1144. if (NamespaceArraySize != 0)
  1145. {
  1146. NamespacePointerArray = (PCASSEMBLY_IDENTITY_NAMESPACE*)RtlAllocateHeap(
  1147. RtlProcessHeap(),
  1148. HEAP_ZERO_MEMORY,
  1149. sizeof(PCASSEMBLY_IDENTITY_NAMESPACE) * NamespaceArraySize);
  1150. for (i=0; i<NamespaceArraySize; i++)
  1151. NamespacePointerArray[i] = NULL;
  1152. }
  1153. AttributeCount = EncodedAssemblyIdentityHeader->AttributeCount;
  1154. if (Flags & SXS_DECODE_ASSEMBLY_IDENTITY_FLAG_FREEZE)
  1155. {
  1156. // If we're going to freeze, just perform an exact allocation.
  1157. AttributeArraySize = AttributeCount;
  1158. }
  1159. else if (AttributeCount == 0)
  1160. {
  1161. AttributeArraySize = 8;
  1162. }
  1163. else
  1164. {
  1165. AttributeArraySize = (AttributeCount + 7) & ~7;
  1166. }
  1167. if (AttributeArraySize != 0)
  1168. {
  1169. AttributePointerArray = (PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE*)RtlAllocateHeap(
  1170. RtlProcessHeap(),
  1171. HEAP_ZERO_MEMORY,
  1172. sizeof (PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE) * AttributeArraySize);
  1173. for (i=0; i<AttributeArraySize; i++)
  1174. AttributePointerArray[i] = NULL;
  1175. }
  1176. AttributeHashArray = (const ULONG *) (EncodedAssemblyIdentityHeader + 1);
  1177. NamespaceLengthArray = (const ULONG *) (AttributeHashArray + AttributeCount);
  1178. EncodedAssemblyIdentityAttributeHeader = (PCENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER) (NamespaceLengthArray + NamespaceCount);
  1179. UnicodeStringArray = (const WCHAR *) (EncodedAssemblyIdentityAttributeHeader + AttributeCount);
  1180. // Start by building up those namespaces...
  1181. for (i=0; i<NamespaceCount; i++)
  1182. {
  1183. ULONG NamespaceHash = 0;
  1184. IFNTFAILED_EXIT(RtlSxspHashUnicodeString(UnicodeStringArray, NamespaceLengthArray[i], &NamespaceHash, FALSE));
  1185. IFNTFAILED_EXIT(RtlSxspAllocateAssemblyIdentityNamespace(0, UnicodeStringArray, NamespaceLengthArray[i], NamespaceHash, &NamespacePointerArray[i]));
  1186. UnicodeStringArray += NamespaceLengthArray[i];
  1187. }
  1188. if (AttributeCount != 0)
  1189. {
  1190. // and now those attributes...
  1191. for (i=0; i<AttributeCount; i++)
  1192. {
  1193. const ULONG NamespaceIndex = EncodedAssemblyIdentityAttributeHeader[i].NamespaceIndex;
  1194. const ULONG NameCch = EncodedAssemblyIdentityAttributeHeader[i].NameCch;
  1195. const ULONG ValueCch = EncodedAssemblyIdentityAttributeHeader[i].ValueCch;
  1196. const WCHAR * const Name = UnicodeStringArray;
  1197. const WCHAR * const Value = &UnicodeStringArray[NameCch];
  1198. UnicodeStringArray = &Value[ValueCch];
  1199. IFNTFAILED_EXIT(RtlSxspAllocateInternalAssemblyIdentityAttribute(
  1200. 0,
  1201. NamespacePointerArray[NamespaceIndex],
  1202. Name,
  1203. NameCch,
  1204. Value,
  1205. ValueCch,
  1206. &AttributePointerArray[i]));
  1207. }
  1208. // sort 'em...
  1209. qsort((PVOID) AttributePointerArray, AttributeCount, sizeof(PINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE), &RtlSxspCompareInternalAttributesForQsort);
  1210. }
  1211. IFNTFAILED_EXIT(RtlSxspHashInternalAssemblyIdentityAttributes(0, AttributeCount, AttributePointerArray, &AssemblyIdentity->Hash));
  1212. AssemblyIdentity->Flags = 0;
  1213. AssemblyIdentity->Type = EncodedAssemblyIdentityHeader->Type;
  1214. AssemblyIdentity->InternalFlags = ASSEMBLY_IDENTITY_INTERNAL_FLAG_ATTRIBUTE_POINTERS_IN_SEPARATE_ALLOCATION | ASSEMBLY_IDENTITY_INTERNAL_FLAG_NAMESPACE_POINTERS_IN_SEPARATE_ALLOCATION;
  1215. AssemblyIdentity->AttributePointerArray = AttributePointerArray;
  1216. AssemblyIdentity->AttributeCount = AttributeCount;
  1217. AssemblyIdentity->AttributeArraySize = AttributeArraySize;
  1218. AssemblyIdentity->NamespacePointerArray = NamespacePointerArray;
  1219. AssemblyIdentity->NamespaceCount = NamespaceCount;
  1220. AssemblyIdentity->NamespaceArraySize = NamespaceArraySize;
  1221. AttributePointerArray = NULL;
  1222. NamespacePointerArray = NULL;
  1223. if (Flags & SXS_DECODE_ASSEMBLY_IDENTITY_FLAG_FREEZE)
  1224. AssemblyIdentity->Flags |= ASSEMBLY_IDENTITY_FLAG_FROZEN;
  1225. *AssemblyIdentityOut = AssemblyIdentity;
  1226. AssemblyIdentity = NULL;
  1227. Exit:
  1228. //
  1229. // REVIEW: Should this be an SxsDestroyAssemblyIdentity
  1230. //
  1231. if (AssemblyIdentity != NULL)
  1232. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)AssemblyIdentity);
  1233. if ((AttributeCount != 0) && (AttributePointerArray != NULL))
  1234. {
  1235. for (i=0; i<AttributeCount; i++)
  1236. {
  1237. if (AttributePointerArray[i] != NULL)
  1238. {
  1239. RtlSxspDeallocateInternalAssemblyIdentityAttribute(AttributePointerArray[i]);
  1240. AttributePointerArray[i] = NULL;
  1241. }
  1242. }
  1243. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)AttributePointerArray );
  1244. }
  1245. if ((NamespaceCount != 0) && (NamespacePointerArray != NULL))
  1246. {
  1247. for (i=0; i<NamespaceCount; i++)
  1248. {
  1249. if (NamespacePointerArray[i] != NULL)
  1250. {
  1251. RtlSxspDeallocateAssemblyIdentityNamespace(NamespacePointerArray[i]);
  1252. NamespacePointerArray[i] = NULL;
  1253. }
  1254. }
  1255. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)NamespacePointerArray);
  1256. }
  1257. return status;
  1258. }
  1259. int __cdecl
  1260. RtlSxspCharPairArrayComparisonCallback(
  1261. const void *pelem1,
  1262. const void *pelem2
  1263. )
  1264. {
  1265. PCCHARPAIR pcp1 = (PCCHARPAIR) pelem1;
  1266. PCCHARPAIR pcp2 = (PCCHARPAIR) pelem2;
  1267. if (pcp1->wchEnd < pcp2->wchStart)
  1268. return -1;
  1269. if (pcp2->wchEnd < pcp1->wchStart)
  1270. return 1;
  1271. return 0;
  1272. }
  1273. BOOLEAN
  1274. RtlSxspIsCharInCharPairArray(
  1275. WCHAR wch,
  1276. PCCHARPAIR prg,
  1277. SIZE_T n
  1278. )
  1279. {
  1280. CHARPAIR cp = { wch, wch };
  1281. return (bsearch(&cp, prg, n, sizeof(CHARPAIR), &RtlSxspCharPairArrayComparisonCallback) != NULL);
  1282. }
  1283. BOOLEAN
  1284. RtlSxspIsCharXMLBaseChar(
  1285. WCHAR wch
  1286. )
  1287. {
  1288. return RtlSxspIsCharInCharPairArray(wch, s_rgXMLBaseChar, NUMBER_OF(s_rgXMLBaseChar));
  1289. }
  1290. BOOLEAN
  1291. RtlSxspIsCharXMLIdeographic(
  1292. WCHAR wch
  1293. )
  1294. {
  1295. return (
  1296. (wch >= 0x4e00 && wch <= 0x9fa5) ||
  1297. (wch == 0x3007) ||
  1298. (wch >= 0x3021 && wch <= 0x3029)
  1299. );
  1300. }
  1301. BOOLEAN
  1302. RtlSxspIsCharXMLLetter(
  1303. WCHAR wch
  1304. )
  1305. {
  1306. return
  1307. RtlSxspIsCharXMLBaseChar(wch) ||
  1308. RtlSxspIsCharXMLIdeographic(wch);
  1309. }
  1310. BOOLEAN
  1311. RtlSxspIsCharXMLCombiningChar(
  1312. WCHAR wch
  1313. )
  1314. {
  1315. return (
  1316. (wch >= 0x0300 && wch <= 0x0345) ||
  1317. (wch >= 0x0360 && wch <= 0x0361) ||
  1318. (wch >= 0x0483 && wch <= 0x0486) ||
  1319. (wch >= 0x0591 && wch <= 0x05a1) ||
  1320. (wch >= 0x05a3 && wch <= 0x05b9) ||
  1321. (wch >= 0x05bb && wch <= 0x05bd) ||
  1322. wch == 0x05bf ||
  1323. (wch >= 0x05c1 && wch <= 0x05c2) ||
  1324. wch == 0x05c4 ||
  1325. (wch >= 0x064b && wch <= 0x0652) ||
  1326. wch == 0x0670 ||
  1327. (wch >= 0x06d6 && wch <= 0x06dc) ||
  1328. (wch >= 0x06dd && wch <= 0x06df) ||
  1329. (wch >= 0x06e0 && wch <= 0x06e4) ||
  1330. (wch >= 0x06e7 && wch <= 0x06e8) ||
  1331. (wch >= 0x06ea && wch <= 0x06ed) ||
  1332. (wch >= 0x0901 && wch <= 0x0903) ||
  1333. wch == 0x093c ||
  1334. (wch >= 0x093e && wch <= 0x094c) ||
  1335. wch == 0x094d ||
  1336. (wch >= 0x0951 && wch <= 0x0954) ||
  1337. (wch >= 0x0962 && wch <= 0x0963) ||
  1338. (wch >= 0x0981 && wch <= 0x0983) ||
  1339. wch == 0x09bc ||
  1340. wch == 0x09be ||
  1341. wch == 0x09bf ||
  1342. (wch >= 0x09c0 && wch <= 0x09c4) ||
  1343. (wch >= 0x09c7 && wch <= 0x09c8) ||
  1344. (wch >= 0x09cb && wch <= 0x09cd) ||
  1345. wch == 0x09d7 ||
  1346. (wch >= 0x09e2 && wch <= 0x09e3) ||
  1347. wch == 0x0a02 ||
  1348. wch == 0x0a3c ||
  1349. wch == 0x0a3e ||
  1350. wch == 0x0a3f ||
  1351. (wch >= 0x0a40 && wch <= 0x0a42) ||
  1352. (wch >= 0x0a47 && wch <= 0x0a48) ||
  1353. (wch >= 0x0a4b && wch <= 0x0a4d) ||
  1354. (wch >= 0x0a70 && wch <= 0x0a71) ||
  1355. (wch >= 0x0a81 && wch <= 0x0a83) ||
  1356. wch == 0x0abc ||
  1357. (wch >= 0x0abe && wch <= 0x0ac5) ||
  1358. (wch >= 0x0ac7 && wch <= 0x0ac9) ||
  1359. (wch >= 0x0acb && wch <= 0x0acd) ||
  1360. (wch >= 0x0b01 && wch <= 0x0b03) ||
  1361. wch == 0x0b3c ||
  1362. (wch >= 0x0b3e && wch <= 0x0b43) ||
  1363. (wch >= 0x0b47 && wch <= 0x0b48) ||
  1364. (wch >= 0x0b4b && wch <= 0x0b4d) ||
  1365. (wch >= 0x0b56 && wch <= 0x0b57) ||
  1366. (wch >= 0x0b82 && wch <= 0x0b83) ||
  1367. (wch >= 0x0bbe && wch <= 0x0bc2) ||
  1368. (wch >= 0x0bc6 && wch <= 0x0bc8) ||
  1369. (wch >= 0x0bca && wch <= 0x0bcd) ||
  1370. wch == 0x0bd7 ||
  1371. (wch >= 0x0c01 && wch <= 0x0c03) ||
  1372. (wch >= 0x0c3e && wch <= 0x0c44) ||
  1373. (wch >= 0x0c46 && wch <= 0x0c48) ||
  1374. (wch >= 0x0c4a && wch <= 0x0c4d) ||
  1375. (wch >= 0x0c55 && wch <= 0x0c56) ||
  1376. (wch >= 0x0c82 && wch <= 0x0c83) ||
  1377. (wch >= 0x0cbe && wch <= 0x0cc4) ||
  1378. (wch >= 0x0cc6 && wch <= 0x0cc8) ||
  1379. (wch >= 0x0cca && wch <= 0x0ccd) ||
  1380. (wch >= 0x0cd5 && wch <= 0x0cd6) ||
  1381. (wch >= 0x0d02 && wch <= 0x0d03) ||
  1382. (wch >= 0x0d3e && wch <= 0x0d43) ||
  1383. (wch >= 0x0d46 && wch <= 0x0d48) ||
  1384. (wch >= 0x0d4a && wch <= 0x0d4d) ||
  1385. wch == 0x0d57 ||
  1386. wch == 0x0e31 ||
  1387. (wch >= 0x0e34 && wch <= 0x0e3a) ||
  1388. (wch >= 0x0e47 && wch <= 0x0e4e) ||
  1389. wch == 0x0eb1 ||
  1390. (wch >= 0x0eb4 && wch <= 0x0eb9) ||
  1391. (wch >= 0x0ebb && wch <= 0x0ebc) ||
  1392. (wch >= 0x0ec8 && wch <= 0x0ecd) ||
  1393. (wch >= 0x0f18 && wch <= 0x0f19) ||
  1394. wch == 0x0f35 ||
  1395. wch == 0x0f37 ||
  1396. wch == 0x0f39 ||
  1397. wch == 0x0f3e ||
  1398. wch == 0x0f3f ||
  1399. (wch >= 0x0f71 && wch <= 0x0f84) ||
  1400. (wch >= 0x0f86 && wch <= 0x0f8b) ||
  1401. (wch >= 0x0f90 && wch <= 0x0f95) ||
  1402. wch == 0x0f97 ||
  1403. (wch >= 0x0f99 && wch <= 0x0fad) ||
  1404. (wch >= 0x0fb1 && wch <= 0x0fb7) ||
  1405. wch == 0x0fb9 ||
  1406. (wch >= 0x20d0 && wch <= 0x20dc) ||
  1407. wch == 0x20e1 ||
  1408. (wch >= 0x302a && wch <= 0x302f) ||
  1409. wch == 0x3099 ||
  1410. wch == 0x309a
  1411. );
  1412. }
  1413. BOOLEAN
  1414. RtlSxspIsCharXMLDigit(
  1415. WCHAR wch
  1416. )
  1417. {
  1418. return (
  1419. (wch >= 0x0030 && wch <= 0x0039) ||
  1420. (wch >= 0x0660 && wch <= 0x0669) ||
  1421. (wch >= 0x06f0 && wch <= 0x06f9) ||
  1422. (wch >= 0x0966 && wch <= 0x096f) ||
  1423. (wch >= 0x09e6 && wch <= 0x09ef) ||
  1424. (wch >= 0x0a66 && wch <= 0x0a6f) ||
  1425. (wch >= 0x0ae6 && wch <= 0x0aef) ||
  1426. (wch >= 0x0b66 && wch <= 0x0b6f) ||
  1427. (wch >= 0x0be7 && wch <= 0x0bef) ||
  1428. (wch >= 0x0c66 && wch <= 0x0c6f) ||
  1429. (wch >= 0x0ce6 && wch <= 0x0cef) ||
  1430. (wch >= 0x0d66 && wch <= 0x0d6f) ||
  1431. (wch >= 0x0e50 && wch <= 0x0e59) ||
  1432. (wch >= 0x0ed0 && wch <= 0x0ed9) ||
  1433. (wch >= 0x0f20 && wch <= 0x0f29)
  1434. );
  1435. }
  1436. BOOLEAN
  1437. RtlSxspIsCharXMLExtender(
  1438. WCHAR wch
  1439. )
  1440. {
  1441. return (
  1442. wch == 0x00b7 ||
  1443. wch == 0x02d0 ||
  1444. wch == 0x02d1 ||
  1445. wch == 0x0387 ||
  1446. wch == 0x0640 ||
  1447. wch == 0x0e46 ||
  1448. wch == 0x0ec6 ||
  1449. wch == 0x3005 ||
  1450. (wch >= 0x3031 && wch <= 0x3035) ||
  1451. (wch >= 0x309d && wch <= 0x309e) ||
  1452. (wch >= 0x30fc && wch <= 0x30fe)
  1453. );
  1454. }
  1455. NTSTATUS
  1456. RtlSxspValidateXMLName(
  1457. PCWSTR psz,
  1458. SIZE_T cch,
  1459. BOOLEAN *prfValid
  1460. )
  1461. {
  1462. NTSTATUS status = STATUS_SUCCESS;
  1463. SIZE_T i;
  1464. PARAMETER_CHECK(psz != NULL);
  1465. PARAMETER_CHECK((cch == 0) || (psz != NULL));
  1466. PARAMETER_CHECK(prfValid != NULL);
  1467. *prfValid = FALSE;
  1468. // [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender
  1469. // [5] Name ::= (Letter | '_' | ':') (NameChar)*
  1470. if (cch >= 1)
  1471. {
  1472. WCHAR wch = psz[0];
  1473. if (RtlSxspIsCharXMLLetter(wch) ||
  1474. (wch == L'_') ||
  1475. (wch == L':'))
  1476. {
  1477. for (i=1; i<cch; i++)
  1478. {
  1479. wch = psz[i];
  1480. if (!RtlSxspIsCharXMLLetter(wch) &&
  1481. !RtlSxspIsCharXMLDigit(wch) &&
  1482. (wch != L'.') &&
  1483. (wch != L'-') &&
  1484. (wch != L'_') &&
  1485. (wch != L':') &&
  1486. !RtlSxspIsCharXMLCombiningChar(wch) &&
  1487. !RtlSxspIsCharXMLExtender(wch))
  1488. break;
  1489. }
  1490. if (i == cch)
  1491. *prfValid = TRUE;
  1492. }
  1493. }
  1494. return status;
  1495. }