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

1093 lines
35 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. //adriaanc
  12. //#include "stdinc.h"
  13. //#include <setupapi.h>
  14. #include <sxsapi.h>
  15. // adriaanc
  16. //#include <stdlib.h>
  17. //#include <search.h>
  18. // adriaanc
  19. #include "idaux.h"
  20. #include "idp.h"
  21. static const WCHAR s_rgHexChars[] = L"0123456789abcdef";
  22. // adriaanc
  23. #undef FN_TRACE_WIN32
  24. #define FN_TRACE_WIN32(args)
  25. #undef PARAMETER_CHECK
  26. #define PARAMETER_CHECK(args)
  27. BOOL
  28. SxsComputeAssemblyIdentityEncodedSize(
  29. IN ULONG Flags,
  30. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  31. IN const GUID *EncodingGroup OPTIONAL,
  32. IN ULONG EncodingFormat,
  33. OUT SIZE_T *SizeOut
  34. )
  35. {
  36. BOOL fSuccess = FALSE;
  37. FN_TRACE_WIN32(fSuccess);
  38. SIZE_T Size = 0;
  39. ULONG i;
  40. ULONG AttributeCount, NamespaceCount;
  41. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *AttributePointerArray = NULL;
  42. PCASSEMBLY_IDENTITY_NAMESPACE *NamespacePointerArray = NULL;
  43. if (SizeOut != NULL)
  44. *SizeOut = 0;
  45. if ((Flags != 0) ||
  46. (AssemblyIdentity == NULL) ||
  47. (SizeOut == NULL)) {
  48. ::SetLastError(ERROR_INVALID_PARAMETER);
  49. goto Exit;
  50. }
  51. if (EncodingGroup != NULL)
  52. {
  53. ::SetLastError(ERROR_SXS_UNKNOWN_ENCODING_GROUP);
  54. goto Exit;
  55. }
  56. if ((EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_BINARY) &&
  57. (EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_TEXTUAL))
  58. {
  59. ::SetLastError(ERROR_SXS_UNKNOWN_ENCODING);
  60. goto Exit;
  61. }
  62. IFFALSE_EXIT(::SxspValidateAssemblyIdentity(0, AssemblyIdentity));
  63. AttributeCount = AssemblyIdentity->AttributeCount;
  64. NamespaceCount = AssemblyIdentity->NamespaceCount;
  65. AttributePointerArray = AssemblyIdentity->AttributePointerArray;
  66. NamespacePointerArray = AssemblyIdentity->NamespacePointerArray;
  67. switch (EncodingFormat)
  68. {
  69. case SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_BINARY:
  70. // First, we know we need a header.
  71. Size = sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER);
  72. // Then a ULONG hash per attribute:
  73. Size += (AssemblyIdentity->AttributeCount * sizeof(ULONG));
  74. // Then a USHORT per namespace...
  75. Size += (AssemblyIdentity->NamespaceCount * sizeof(ULONG));
  76. // Then we need an attribute header per attribute:
  77. Size += AssemblyIdentity->AttributeCount * sizeof(ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER);
  78. // Then come the namespace strings...
  79. for (i=0; i<NamespaceCount; i++)
  80. Size += NamespacePointerArray[i]->NamespaceCch * sizeof(WCHAR);
  81. // Then we need space for each of the attributes' names and value.
  82. AttributePointerArray = AssemblyIdentity->AttributePointerArray;
  83. for (i=0; i<AttributeCount; i++)
  84. {
  85. ASSERT(AttributePointerArray[i] != NULL);
  86. if (AttributePointerArray[i] == NULL)
  87. {
  88. ::SetLastError(ERROR_INTERNAL_ERROR);
  89. goto Exit;
  90. }
  91. Size += AttributePointerArray[i]->Attribute.NameCch * sizeof(WCHAR);
  92. Size += AttributePointerArray[i]->Attribute.ValueCch * sizeof(WCHAR);
  93. }
  94. // We should at least be byte aligned here...
  95. ASSERT((Size % 2) == 0);
  96. // And finally pad out to a multiple of four if we are not...
  97. Size = (Size + 3) & ~3;
  98. break;
  99. case SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_TEXTUAL:
  100. for (i=0; i<AttributeCount; i++)
  101. {
  102. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Attribute = AttributePointerArray[i];
  103. BOOL IsAssemblyName = FALSE;
  104. SIZE_T BytesThisAttribute = 0;
  105. INTERNAL_ERROR_CHECK(Attribute != NULL);
  106. IFFALSE_EXIT(SxspIsInternalAssemblyIdentityAttribute(
  107. 0,
  108. Attribute,
  109. NULL,
  110. 0,
  111. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME,
  112. NUMBER_OF(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME) - 1,
  113. &IsAssemblyName));
  114. // It's the attribute name. Just account for the size of the encoded value string
  115. IFFALSE_EXIT(::SxspComputeInternalAssemblyIdentityAttributeEncodedTextualSize(
  116. IsAssemblyName ?
  117. SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_VALUE_ONLY |
  118. SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_OMIT_QUOTES
  119. : 0,
  120. Attribute,
  121. &BytesThisAttribute));
  122. // Account for the separator character
  123. if (i != 0)
  124. Size += sizeof(WCHAR);
  125. Size += BytesThisAttribute;
  126. }
  127. break;
  128. }
  129. *SizeOut = Size;
  130. fSuccess = TRUE;
  131. Exit:
  132. return fSuccess;
  133. }
  134. BOOL
  135. SxspComputeQuotedStringSize(
  136. IN DWORD Flags,
  137. IN const WCHAR *StringIn,
  138. IN SIZE_T Cch,
  139. OUT SIZE_T *BytesOut
  140. )
  141. {
  142. BOOL fSuccess = FALSE;
  143. FN_TRACE_WIN32(fSuccess);
  144. SIZE_T Bytes = 0;
  145. if (BytesOut != NULL)
  146. *BytesOut = 0;
  147. PARAMETER_CHECK(Flags == 0);
  148. PARAMETER_CHECK(StringIn != NULL || Cch == 0);
  149. PARAMETER_CHECK(BytesOut != NULL);
  150. while (Cch != 0)
  151. {
  152. const WCHAR wch = *StringIn++;
  153. if (((wch >= L'A') && (wch <= L'Z')) ||
  154. ((wch >= L'a') && (wch <= L'z')) ||
  155. ((wch >= L'0') && (wch <= L'9')) ||
  156. (wch == L'.') ||
  157. (wch == L'-') ||
  158. (wch == L'_'))
  159. {
  160. Bytes += sizeof(WCHAR);
  161. }
  162. else
  163. {
  164. switch (wch)
  165. {
  166. case L'&':
  167. // &amp;
  168. Bytes += (5 * sizeof(WCHAR));
  169. break;
  170. case L'"':
  171. // &quot;
  172. Bytes += (6 * sizeof(WCHAR));
  173. break;
  174. case L'<':
  175. // &lt;
  176. Bytes += (4 * sizeof(WCHAR));
  177. break;
  178. case L'>':
  179. // &gt;
  180. Bytes += (4 * sizeof(WCHAR));
  181. break;
  182. case L'\'':
  183. // &apos;
  184. Bytes += (6 * sizeof(WCHAR));
  185. break;
  186. default:
  187. // Otherwise, it's going to be &#xn;
  188. if (wch < 0x10)
  189. Bytes += (5 * sizeof(WCHAR));
  190. else if (wch < 0x100)
  191. Bytes += (6 * sizeof(WCHAR));
  192. else if (wch < 0x1000)
  193. Bytes += (7 * sizeof(WCHAR));
  194. else
  195. Bytes += (8 * sizeof(WCHAR));
  196. break;
  197. }
  198. }
  199. Cch--;
  200. }
  201. *BytesOut = Bytes;
  202. fSuccess = TRUE;
  203. // adriaanc
  204. // Exit:
  205. return fSuccess;
  206. }
  207. BOOL
  208. SxspQuoteString(
  209. IN DWORD Flags,
  210. IN const WCHAR *StringIn,
  211. IN SIZE_T Cch,
  212. IN SIZE_T BufferSize,
  213. IN PVOID Buffer,
  214. OUT SIZE_T *BytesWrittenOut
  215. )
  216. {
  217. BOOL fSuccess = FALSE;
  218. FN_TRACE_WIN32(fSuccess);
  219. WCHAR *Cursor;
  220. SIZE_T BytesWritten = 0;
  221. SIZE_T BytesLeft = BufferSize;
  222. if (BytesWrittenOut != NULL)
  223. *BytesWrittenOut = 0;
  224. PARAMETER_CHECK(Flags == 0);
  225. PARAMETER_CHECK(StringIn != NULL || Cch == 0);
  226. PARAMETER_CHECK(Buffer != NULL || BufferSize == 0);
  227. Cursor = (WCHAR *) Buffer;
  228. BytesWritten = 0;
  229. while (Cch != 0)
  230. {
  231. const WCHAR wch = *StringIn++;
  232. if (((wch >= L'A') && (wch <= L'Z')) ||
  233. ((wch >= L'a') && (wch <= L'z')) ||
  234. ((wch >= L'0') && (wch <= L'9')) ||
  235. (wch == L'.') ||
  236. (wch == L'-') ||
  237. (wch == L'_'))
  238. {
  239. if (BytesLeft < sizeof(WCHAR))
  240. {
  241. ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
  242. goto Exit;
  243. }
  244. *Cursor++ = wch;
  245. BytesLeft -= sizeof(WCHAR);
  246. BytesWritten += sizeof(WCHAR);
  247. }
  248. else
  249. {
  250. #define HANDLE_CASE(_wch, _wstr) \
  251. case _wch: \
  252. { \
  253. ULONG i; \
  254. if (BytesLeft < (sizeof(_wstr) - sizeof(WCHAR))) \
  255. { \
  256. ::SetLastError(ERROR_INSUFFICIENT_BUFFER); \
  257. goto Exit; \
  258. } \
  259. for (i=0; i<(NUMBER_OF(_wstr) - 1); i++) \
  260. *Cursor++ = _wstr[i]; \
  261. BytesLeft -= (sizeof(_wstr) - sizeof(WCHAR)); \
  262. BytesWritten += (sizeof(_wstr) - sizeof(WCHAR)); \
  263. break; \
  264. }
  265. switch (wch)
  266. {
  267. HANDLE_CASE(L'"', L"&quot;")
  268. HANDLE_CASE(L'&', L"&amp;")
  269. HANDLE_CASE(L'<', L"&lt;")
  270. HANDLE_CASE(L'>', L"&gt;")
  271. HANDLE_CASE(L'\'', L"&apos;")
  272. default:
  273. if (wch < 0x10)
  274. {
  275. if (BytesLeft < (5 * sizeof(WCHAR)))
  276. {
  277. ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
  278. goto Exit;
  279. }
  280. *Cursor++ = L'&';
  281. *Cursor++ = L'#';
  282. *Cursor++ = L'x';
  283. *Cursor++ = s_rgHexChars[wch];
  284. *Cursor++ = L';';
  285. BytesWritten += (5 * sizeof(WCHAR));
  286. BytesLeft -= (5 * sizeof(WCHAR));
  287. }
  288. else if (wch < 0x100)
  289. {
  290. if (BytesLeft < (6 * sizeof(WCHAR)))
  291. {
  292. ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
  293. goto Exit;
  294. }
  295. *Cursor++ = L'&';
  296. *Cursor++ = L'#';
  297. *Cursor++ = L'x';
  298. *Cursor++ = s_rgHexChars[(wch >> 4) & 0xf];
  299. *Cursor++ = s_rgHexChars[wch & 0xf];
  300. *Cursor++ = L';';
  301. BytesWritten += (6 * sizeof(WCHAR));
  302. BytesLeft -= (6 * sizeof(WCHAR));
  303. }
  304. else if (wch < 0x1000)
  305. {
  306. if (BytesLeft < (7 * sizeof(WCHAR)))
  307. {
  308. ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
  309. goto Exit;
  310. }
  311. *Cursor++ = L'&';
  312. *Cursor++ = L'#';
  313. *Cursor++ = L'x';
  314. *Cursor++ = s_rgHexChars[(wch >> 8) & 0xf];
  315. *Cursor++ = s_rgHexChars[(wch >> 4) & 0xf];
  316. *Cursor++ = s_rgHexChars[wch & 0xf];
  317. *Cursor++ = L';';
  318. BytesWritten += (7 * sizeof(WCHAR));
  319. BytesLeft -= (7 * sizeof(WCHAR));
  320. }
  321. else
  322. {
  323. INTERNAL_ERROR_CHECK(wch <= 0xffff);
  324. if (BytesLeft < (8 * sizeof(WCHAR)))
  325. {
  326. ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
  327. goto Exit;
  328. }
  329. *Cursor++ = L'&';
  330. *Cursor++ = L'#';
  331. *Cursor++ = L'x';
  332. *Cursor++ = s_rgHexChars[(wch >> 12) & 0xf];
  333. *Cursor++ = s_rgHexChars[(wch >> 8) & 0xf];
  334. *Cursor++ = s_rgHexChars[(wch >> 4) & 0xf];
  335. *Cursor++ = s_rgHexChars[wch & 0xf];
  336. *Cursor++ = L';';
  337. BytesWritten += (8 * sizeof(WCHAR));
  338. BytesLeft -= (8 * sizeof(WCHAR));
  339. }
  340. break;
  341. }
  342. }
  343. Cch--;
  344. }
  345. if (BytesWrittenOut != NULL)
  346. *BytesWrittenOut = BytesWritten;
  347. fSuccess = TRUE;
  348. Exit:
  349. return fSuccess;
  350. }
  351. BOOL
  352. SxspComputeInternalAssemblyIdentityAttributeEncodedTextualSize(
  353. IN DWORD Flags,
  354. IN PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Attribute,
  355. OUT SIZE_T *BytesOut
  356. )
  357. {
  358. BOOL fSuccess = FALSE;
  359. FN_TRACE_WIN32(fSuccess);
  360. SIZE_T Bytes = 0;
  361. SIZE_T BytesTemp = 0;
  362. if (BytesOut != NULL)
  363. *BytesOut = 0;
  364. PARAMETER_CHECK((Flags & ~(
  365. SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_VALUE_ONLY |
  366. SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_OMIT_QUOTES)) == 0);
  367. PARAMETER_CHECK(Attribute != NULL);
  368. PARAMETER_CHECK(BytesOut != NULL);
  369. Bytes = 0;
  370. if ((Flags & SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_VALUE_ONLY) == 0)
  371. {
  372. if (Attribute->Attribute.NamespaceCch != 0)
  373. {
  374. // Figure out the ns:n= part
  375. IFFALSE_EXIT(::SxspComputeQuotedStringSize(0, Attribute->Attribute.Namespace, Attribute->Attribute.NamespaceCch, &BytesTemp));
  376. Bytes += BytesTemp;
  377. Bytes += sizeof(WCHAR); // the ":"
  378. }
  379. IFFALSE_EXIT(::SxspComputeQuotedStringSize(0, Attribute->Attribute.Name, Attribute->Attribute.NameCch, &BytesTemp));
  380. Bytes += BytesTemp;
  381. Bytes += sizeof(WCHAR); // the "="
  382. }
  383. IFFALSE_EXIT(::SxspComputeQuotedStringSize(0, Attribute->Attribute.Value, Attribute->Attribute.ValueCch, &BytesTemp));
  384. Bytes += BytesTemp;
  385. if ((Flags & SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_OMIT_QUOTES) == 0)
  386. Bytes += 2 * sizeof(WCHAR); // the beginning and ending quotes
  387. *BytesOut = Bytes;
  388. fSuccess = TRUE;
  389. Exit:
  390. return fSuccess;
  391. }
  392. BOOL
  393. SxspEncodeInternalAssemblyIdentityAttributeAsText(
  394. IN DWORD Flags,
  395. IN PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Attribute,
  396. SIZE_T BufferSize,
  397. PVOID Buffer,
  398. SIZE_T *BytesWrittenOut
  399. )
  400. {
  401. BOOL fSuccess = FALSE;
  402. FN_TRACE_WIN32(fSuccess);
  403. SIZE_T BytesWritten = 0;
  404. SIZE_T BytesLeft = 0;
  405. SIZE_T BytesThisSegment;
  406. WCHAR *Cursor;
  407. if (BytesWrittenOut != NULL)
  408. *BytesWrittenOut = 0;
  409. PARAMETER_CHECK(Flags == 0);
  410. PARAMETER_CHECK(Attribute != NULL);
  411. PARAMETER_CHECK((Buffer != NULL) || (BufferSize == 0));
  412. BytesWritten = 0;
  413. BytesLeft = BufferSize;
  414. Cursor = reinterpret_cast<WCHAR *>(Buffer);
  415. if (Attribute->Attribute.NamespaceCch != 0)
  416. {
  417. IFFALSE_EXIT(::SxspQuoteString(0, Attribute->Namespace->Namespace, Attribute->Namespace->NamespaceCch, BytesLeft, Cursor, &BytesThisSegment));
  418. INTERNAL_ERROR_CHECK(BytesThisSegment <= BytesLeft);
  419. Cursor = (WCHAR *) (((ULONG_PTR) Cursor) + BytesThisSegment);
  420. BytesLeft -= BytesThisSegment;
  421. BytesWritten += BytesThisSegment;
  422. if (BytesLeft < sizeof(WCHAR))
  423. {
  424. ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
  425. goto Exit;
  426. }
  427. *Cursor++ = L':';
  428. BytesLeft -= sizeof(WCHAR);
  429. BytesWritten += sizeof(WCHAR);
  430. }
  431. IFFALSE_EXIT(::SxspQuoteString(0, Attribute->Attribute.Name, Attribute->Attribute.NameCch, BytesLeft, Cursor, &BytesThisSegment));
  432. INTERNAL_ERROR_CHECK(BytesThisSegment <= BytesLeft);
  433. Cursor = (WCHAR *) (((ULONG_PTR) Cursor) + BytesThisSegment);
  434. BytesLeft -= BytesThisSegment;
  435. BytesWritten += BytesThisSegment;
  436. if (BytesLeft < (2 * sizeof(WCHAR)))
  437. {
  438. ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
  439. goto Exit;
  440. }
  441. *Cursor++ = L'=';
  442. *Cursor++ = L'"';
  443. BytesLeft -= (2 * sizeof(WCHAR));
  444. BytesWritten += (2 * sizeof(WCHAR));
  445. IFFALSE_EXIT(::SxspQuoteString(0, Attribute->Attribute.Value, Attribute->Attribute.ValueCch, BytesLeft, Cursor, &BytesThisSegment));
  446. INTERNAL_ERROR_CHECK(BytesThisSegment <= BytesLeft);
  447. Cursor = (WCHAR *) (((ULONG_PTR) Cursor) + BytesThisSegment);
  448. BytesLeft -= BytesThisSegment;
  449. BytesWritten += BytesThisSegment;
  450. if (BytesLeft < sizeof(WCHAR))
  451. {
  452. ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
  453. goto Exit;
  454. }
  455. *Cursor++ = L'"';
  456. BytesLeft -= sizeof(WCHAR);
  457. BytesWritten += sizeof(WCHAR);
  458. *BytesWrittenOut = BytesWritten;
  459. fSuccess = TRUE;
  460. Exit:
  461. return fSuccess;
  462. }
  463. BOOL
  464. SxspEncodeAssemblyIdentityTextually(
  465. IN DWORD Flags,
  466. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  467. IN SIZE_T BufferSize,
  468. IN PVOID Buffer,
  469. OUT SIZE_T *BytesWrittenOut)
  470. {
  471. BOOL fSuccess = FALSE;
  472. FN_TRACE_WIN32(fSuccess);
  473. ULONG AttributeCount, NamespaceCount;
  474. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *Attributes;
  475. PCASSEMBLY_IDENTITY_NAMESPACE *Namespaces;
  476. ULONG i;
  477. ASSEMBLY_IDENTITY_ATTRIBUTE Attribute;
  478. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE NameInternalAttribute = NULL;
  479. SIZE_T BytesLeft;
  480. SIZE_T BytesWritten;
  481. PVOID Cursor;
  482. SIZE_T TempBytesWritten;
  483. if (BytesWrittenOut != NULL)
  484. *BytesWrittenOut = 0;
  485. PARAMETER_CHECK(Flags == 0);
  486. PARAMETER_CHECK(AssemblyIdentity != NULL);
  487. PARAMETER_CHECK(BufferSize != 0);
  488. PARAMETER_CHECK(Buffer != NULL);
  489. PARAMETER_CHECK(BytesWrittenOut != NULL);
  490. Cursor = Buffer;
  491. BytesLeft = BufferSize;
  492. BytesWritten = 0;
  493. // The root assembly identity is actually totally empty, so we'll short-circuit that case.
  494. AttributeCount = AssemblyIdentity->AttributeCount;
  495. if (AttributeCount != 0)
  496. {
  497. NamespaceCount = AssemblyIdentity->NamespaceCount;
  498. Attributes = AssemblyIdentity->AttributePointerArray;
  499. Namespaces = AssemblyIdentity->NamespacePointerArray;
  500. // First, let's look for the "name" attribute.
  501. Attribute.Flags = 0;
  502. Attribute.Namespace = NULL;
  503. Attribute.NamespaceCch = 0;
  504. Attribute.Name = SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME;
  505. Attribute.NameCch = NUMBER_OF(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME) - 1;
  506. IFFALSE_EXIT(
  507. ::SxspLocateInternalAssemblyIdentityAttribute(
  508. SXSP_LOCATE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_FLAG_MATCH_NAMESPACE |
  509. SXSP_LOCATE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_FLAG_MATCH_NAME,
  510. AssemblyIdentity,
  511. &Attribute,
  512. &NameInternalAttribute,
  513. NULL));
  514. INTERNAL_ERROR_CHECK(NameInternalAttribute != NULL);
  515. IFFALSE_EXIT(::SxspQuoteString(0, NameInternalAttribute->Attribute.Value, NameInternalAttribute->Attribute.ValueCch, BytesLeft, Cursor, &TempBytesWritten));
  516. INTERNAL_ERROR_CHECK(TempBytesWritten <= BytesLeft);
  517. Cursor = (PVOID) (((ULONG_PTR) Cursor) + TempBytesWritten);
  518. BytesLeft -= TempBytesWritten;
  519. BytesWritten += TempBytesWritten;
  520. for (i=0; i<AttributeCount; i++)
  521. {
  522. // Skip the standard "name" attribute
  523. if (Attributes[i] == NameInternalAttribute)
  524. continue;
  525. if (BytesLeft < sizeof(WCHAR))
  526. {
  527. ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
  528. goto Exit;
  529. }
  530. *((WCHAR *) Cursor) = L',';
  531. Cursor = (PVOID) (((ULONG_PTR) Cursor) + sizeof(WCHAR));
  532. BytesLeft -= sizeof(WCHAR);
  533. BytesWritten += sizeof(WCHAR);
  534. IFFALSE_EXIT(::SxspEncodeInternalAssemblyIdentityAttributeAsText(0, Attributes[i], BytesLeft, Cursor, &TempBytesWritten));
  535. INTERNAL_ERROR_CHECK(TempBytesWritten <= BytesLeft);
  536. Cursor = (PVOID) (((ULONG_PTR) Cursor) + TempBytesWritten);
  537. BytesLeft -= TempBytesWritten;
  538. BytesWritten += TempBytesWritten;
  539. }
  540. }
  541. *BytesWrittenOut = BytesWritten;
  542. fSuccess = TRUE;
  543. Exit:
  544. return fSuccess;
  545. }
  546. BOOL
  547. SxsEncodeAssemblyIdentity(
  548. IN ULONG Flags,
  549. IN PCASSEMBLY_IDENTITY AssemblyIdentity,
  550. IN const GUID *EncodingGroup OPTIONAL, // use NULL to use any of the SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_* encodings
  551. IN ULONG EncodingFormat,
  552. IN SIZE_T BufferSize,
  553. OUT PVOID Buffer,
  554. OUT SIZE_T *BytesWrittenOrRequired
  555. )
  556. {
  557. BOOL fSuccess = FALSE;
  558. FN_TRACE_WIN32(fSuccess);
  559. SIZE_T TotalSize = 0;
  560. PVOID Cursor = NULL;
  561. SIZE_T i;
  562. PENCODED_ASSEMBLY_IDENTITY_HEADER EncodedAssemblyIdentityHeader = NULL;
  563. PENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER EncodedAssemblyIdentityAttributeHeader = NULL;
  564. ULONG *TempULONGArrayPointer;
  565. SIZE_T BytesWritten = 0;
  566. ULONG AttributeCount, NamespaceCount;
  567. if (BytesWrittenOrRequired != NULL)
  568. *BytesWrittenOrRequired = 0;
  569. if ((Flags != 0) ||
  570. (AssemblyIdentity == NULL) ||
  571. ((BufferSize != 0) && (Buffer == NULL)) ||
  572. ((BufferSize == 0) && (BytesWrittenOrRequired == NULL)))
  573. {
  574. ::SetLastError(ERROR_INVALID_PARAMETER);
  575. goto Exit;
  576. }
  577. if (EncodingGroup != NULL)
  578. {
  579. ::SetLastError(ERROR_SXS_UNKNOWN_ENCODING_GROUP);
  580. goto Exit;
  581. }
  582. if ((EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_BINARY) &&
  583. (EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_TEXTUAL))
  584. {
  585. ::SetLastError(ERROR_SXS_UNKNOWN_ENCODING);
  586. goto Exit;
  587. }
  588. IFFALSE_EXIT(::SxspValidateAssemblyIdentity(0, AssemblyIdentity));
  589. IFFALSE_EXIT(::SxsComputeAssemblyIdentityEncodedSize(0, AssemblyIdentity, EncodingGroup, EncodingFormat, &TotalSize));
  590. if (TotalSize > BufferSize)
  591. {
  592. if (BytesWrittenOrRequired != NULL)
  593. *BytesWrittenOrRequired = TotalSize;
  594. ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
  595. goto Exit;
  596. }
  597. AttributeCount = AssemblyIdentity->AttributeCount;
  598. NamespaceCount = AssemblyIdentity->NamespaceCount;
  599. //
  600. // Let's start filling it in.
  601. //
  602. switch (EncodingFormat)
  603. {
  604. case SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_BINARY:
  605. BytesWritten = 0;
  606. Cursor = Buffer;
  607. EncodedAssemblyIdentityHeader = (PENCODED_ASSEMBLY_IDENTITY_HEADER) Cursor;
  608. Cursor = (PVOID) (((ULONG_PTR) Cursor) + sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER));
  609. BytesWritten += sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER);
  610. EncodedAssemblyIdentityHeader->HeaderSize = sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER);
  611. EncodedAssemblyIdentityHeader->Magic = ENCODED_ASSEMBLY_IDENTITY_HEADER_MAGIC;
  612. EncodedAssemblyIdentityHeader->TotalSize = static_cast<ULONG>(TotalSize);
  613. // turn off any flags not relevant to persisted state
  614. EncodedAssemblyIdentityHeader->Type = AssemblyIdentity->Type;
  615. EncodedAssemblyIdentityHeader->Flags = AssemblyIdentity->Flags & ~(ASSEMBLY_IDENTITY_FLAG_FROZEN);
  616. EncodedAssemblyIdentityHeader->EncodingFlags = 0;
  617. EncodedAssemblyIdentityHeader->AttributeCount = AttributeCount;
  618. EncodedAssemblyIdentityHeader->NamespaceCount = NamespaceCount;
  619. EncodedAssemblyIdentityHeader->ReservedMustBeZero1 = 0;
  620. EncodedAssemblyIdentityHeader->ReservedMustBeZero2 = 0;
  621. EncodedAssemblyIdentityHeader->ReservedMustBeZero3 = 0;
  622. EncodedAssemblyIdentityHeader->ReservedMustBeZero4 = 0;
  623. TempULONGArrayPointer = (ULONG *) Cursor;
  624. Cursor = (PVOID) (TempULONGArrayPointer + AttributeCount);
  625. BytesWritten += (AttributeCount * sizeof(ULONG));
  626. for (i=0; i<AttributeCount; i++)
  627. TempULONGArrayPointer[i] = AssemblyIdentity->AttributePointerArray[i]->WholeAttributeHash;
  628. // sort 'em...
  629. qsort(TempULONGArrayPointer, AttributeCount, sizeof(ULONG), &SxspCompareULONGsForQsort);
  630. TempULONGArrayPointer = (ULONG *) Cursor;
  631. Cursor = (PVOID) (TempULONGArrayPointer + NamespaceCount);
  632. BytesWritten += (sizeof(ULONG) * NamespaceCount);
  633. for (i=0; i<NamespaceCount; i++)
  634. TempULONGArrayPointer[i] = static_cast<ULONG>(AssemblyIdentity->NamespacePointerArray[i]->NamespaceCch);
  635. EncodedAssemblyIdentityAttributeHeader = (PENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER) Cursor;
  636. Cursor = (PVOID) (EncodedAssemblyIdentityAttributeHeader + AttributeCount);
  637. BytesWritten += (AttributeCount * sizeof(ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER));
  638. for (i=0; i<AttributeCount; i++)
  639. {
  640. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE InternalAttribute = AssemblyIdentity->AttributePointerArray[i];
  641. ULONG NamespaceIndex;
  642. // Totally gross linear search to determine the namespace index. Fortunately the common case
  643. // will be a single namespace for all attributes.
  644. for (NamespaceIndex = 0; NamespaceIndex < NamespaceCount; NamespaceIndex++)
  645. {
  646. if (AssemblyIdentity->NamespacePointerArray[NamespaceIndex] == InternalAttribute->Namespace)
  647. break;
  648. }
  649. // If this assert fires, the attribute refers to a namespace that's not in the identity; bad!
  650. INTERNAL_ERROR_CHECK(
  651. (InternalAttribute->Namespace == NULL) ||
  652. (NamespaceIndex < NamespaceCount));
  653. EncodedAssemblyIdentityAttributeHeader[i].NamespaceIndex = NamespaceIndex + 1;
  654. EncodedAssemblyIdentityAttributeHeader[i].NameCch = static_cast<ULONG>(InternalAttribute->Attribute.NameCch);
  655. EncodedAssemblyIdentityAttributeHeader[i].ValueCch = static_cast<ULONG>(InternalAttribute->Attribute.ValueCch);
  656. }
  657. // so much for the fixed length stuff; write the namespaces.
  658. for (i=0; i<NamespaceCount; i++)
  659. {
  660. PWSTR psz = (PWSTR) Cursor;
  661. Cursor = (PVOID) (((ULONG_PTR) psz) + (AssemblyIdentity->NamespacePointerArray[i]->NamespaceCch * sizeof(WCHAR)));
  662. BytesWritten += (AssemblyIdentity->NamespacePointerArray[i]->NamespaceCch * sizeof(WCHAR));
  663. memcpy(
  664. psz,
  665. AssemblyIdentity->NamespacePointerArray[i]->Namespace,
  666. AssemblyIdentity->NamespacePointerArray[i]->NamespaceCch * sizeof(WCHAR));
  667. }
  668. // And the attributes...
  669. for (i=0; i<AttributeCount; i++)
  670. {
  671. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE InternalAttribute = AssemblyIdentity->AttributePointerArray[i];
  672. PWSTR psz;
  673. psz = (PWSTR) Cursor;
  674. Cursor = (PVOID) (((ULONG_PTR) psz) + (InternalAttribute->Attribute.NameCch * sizeof(WCHAR)));
  675. BytesWritten += (InternalAttribute->Attribute.NameCch * sizeof(WCHAR));
  676. memcpy(
  677. psz,
  678. InternalAttribute->Attribute.Name,
  679. InternalAttribute->Attribute.NameCch * sizeof(WCHAR));
  680. psz = (PWSTR) Cursor;
  681. Cursor = (PVOID) (((ULONG_PTR) psz) + InternalAttribute->Attribute.ValueCch * sizeof(WCHAR));
  682. BytesWritten += InternalAttribute->Attribute.ValueCch * sizeof(WCHAR);
  683. memcpy(
  684. psz,
  685. InternalAttribute->Attribute.Value,
  686. InternalAttribute->Attribute.ValueCch * sizeof(WCHAR));
  687. }
  688. if ((BytesWritten % 4) != 0) {
  689. ASSERT((BytesWritten % 4) == sizeof(USHORT));
  690. *((USHORT *) Cursor) = 0;
  691. BytesWritten += sizeof(USHORT);
  692. }
  693. break;
  694. case SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_TEXTUAL:
  695. IFFALSE_EXIT(::SxspEncodeAssemblyIdentityTextually(0, AssemblyIdentity, BufferSize, Buffer, &BytesWritten));
  696. break;
  697. }
  698. INTERNAL_ERROR_CHECK(BytesWritten == TotalSize);
  699. if (BytesWrittenOrRequired != NULL)
  700. *BytesWrittenOrRequired = BytesWritten;
  701. fSuccess = TRUE;
  702. Exit:
  703. return fSuccess;
  704. }
  705. BOOL
  706. SxsDecodeAssemblyIdentity(
  707. ULONG Flags,
  708. IN const GUID *EncodingGroup,
  709. IN ULONG EncodingFormat,
  710. IN SIZE_T BufferSize,
  711. IN const VOID *Buffer,
  712. OUT PASSEMBLY_IDENTITY *AssemblyIdentityOut
  713. )
  714. {
  715. BOOL fSuccess = FALSE;
  716. FN_TRACE_WIN32(fSuccess);
  717. PCENCODED_ASSEMBLY_IDENTITY_HEADER EncodedAssemblyIdentityHeader = NULL;
  718. PCENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER EncodedAssemblyIdentityAttributeHeader = NULL;
  719. PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *AttributePointerArray = NULL;
  720. PCASSEMBLY_IDENTITY_NAMESPACE *NamespacePointerArray = NULL;
  721. PASSEMBLY_IDENTITY AssemblyIdentity = NULL;
  722. ULONG AttributeCount = 0;
  723. ULONG NamespaceCount = 0;
  724. ULONG AttributeArraySize = 0;
  725. ULONG NamespaceArraySize = 0;
  726. ULONG i;
  727. const ULONG *NamespaceLengthArray = NULL;
  728. const ULONG *AttributeHashArray = NULL;
  729. const WCHAR *UnicodeStringArray = NULL;
  730. if (AssemblyIdentityOut != NULL)
  731. *AssemblyIdentityOut = NULL;
  732. if (((Flags & ~(SXS_DECODE_ASSEMBLY_IDENTITY_FLAG_FREEZE)) != 0) ||
  733. (BufferSize < sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER)) ||
  734. (Buffer == NULL) ||
  735. (AssemblyIdentityOut == NULL)) {
  736. ::SetLastError(ERROR_INVALID_PARAMETER);
  737. goto Exit;
  738. }
  739. if (EncodingGroup != NULL)
  740. {
  741. ::SetLastError(ERROR_SXS_UNKNOWN_ENCODING_GROUP);
  742. goto Exit;
  743. }
  744. if ((EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_BINARY) &&
  745. (EncodingFormat != SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_TEXTUAL))
  746. {
  747. ::SetLastError(ERROR_SXS_UNKNOWN_ENCODING);
  748. goto Exit;
  749. }
  750. EncodedAssemblyIdentityHeader = (PCENCODED_ASSEMBLY_IDENTITY_HEADER) Buffer;
  751. if ((EncodedAssemblyIdentityHeader->HeaderSize != sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER)) ||
  752. (EncodedAssemblyIdentityHeader->Magic != ENCODED_ASSEMBLY_IDENTITY_HEADER_MAGIC) ||
  753. (EncodedAssemblyIdentityHeader->TotalSize > BufferSize) ||
  754. (EncodedAssemblyIdentityHeader->Flags != 0) ||
  755. ((EncodedAssemblyIdentityHeader->Type != ASSEMBLY_IDENTITY_TYPE_DEFINITION) &&
  756. (EncodedAssemblyIdentityHeader->Type != ASSEMBLY_IDENTITY_TYPE_REFERENCE) &&
  757. (EncodedAssemblyIdentityHeader->Type != ASSEMBLY_IDENTITY_TYPE_WILDCARD)) ||
  758. (EncodedAssemblyIdentityHeader->EncodingFlags != 0) ||
  759. (EncodedAssemblyIdentityHeader->ReservedMustBeZero1 != 0) ||
  760. (EncodedAssemblyIdentityHeader->ReservedMustBeZero2 != 0) ||
  761. (EncodedAssemblyIdentityHeader->ReservedMustBeZero3 != 0) ||
  762. (EncodedAssemblyIdentityHeader->ReservedMustBeZero4 != 0)) {
  763. ::SetLastError(ERROR_INVALID_PARAMETER);
  764. goto Exit;
  765. }
  766. IFALLOCFAILED_EXIT(AssemblyIdentity = new ASSEMBLY_IDENTITY);
  767. NamespaceCount = EncodedAssemblyIdentityHeader->NamespaceCount;
  768. if (Flags & SXS_DECODE_ASSEMBLY_IDENTITY_FLAG_FREEZE)
  769. {
  770. NamespaceArraySize = NamespaceCount;
  771. }
  772. else if (NamespaceCount == 0)
  773. {
  774. NamespaceArraySize = 8;
  775. }
  776. else
  777. {
  778. NamespaceArraySize = (NamespaceCount + 7) & ~7;
  779. }
  780. if (NamespaceArraySize != 0)
  781. {
  782. IFALLOCFAILED_EXIT(NamespacePointerArray = FUSION_NEW_ARRAY(PCASSEMBLY_IDENTITY_NAMESPACE, NamespaceArraySize));
  783. for (i=0; i<NamespaceArraySize; i++)
  784. NamespacePointerArray[i] = NULL;
  785. }
  786. AttributeCount = EncodedAssemblyIdentityHeader->AttributeCount;
  787. if (Flags & SXS_DECODE_ASSEMBLY_IDENTITY_FLAG_FREEZE)
  788. {
  789. // If we're going to freeze, just perform an exact allocation.
  790. AttributeArraySize = AttributeCount;
  791. }
  792. else if (AttributeCount == 0)
  793. {
  794. AttributeArraySize = 8;
  795. }
  796. else
  797. {
  798. AttributeArraySize = (AttributeCount + 7) & ~7;
  799. }
  800. if (AttributeArraySize != 0)
  801. {
  802. IFALLOCFAILED_EXIT(AttributePointerArray = FUSION_NEW_ARRAY(PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE, AttributeArraySize));
  803. for (i=0; i<AttributeArraySize; i++)
  804. AttributePointerArray[i] = NULL;
  805. }
  806. AttributeHashArray = (const ULONG *) (EncodedAssemblyIdentityHeader + 1);
  807. NamespaceLengthArray = (const ULONG *) (AttributeHashArray + AttributeCount);
  808. EncodedAssemblyIdentityAttributeHeader = (PCENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER) (NamespaceLengthArray + NamespaceCount);
  809. UnicodeStringArray = (const WCHAR *) (EncodedAssemblyIdentityAttributeHeader + AttributeCount);
  810. // Start by building up those namespaces...
  811. for (i=0; i<NamespaceCount; i++)
  812. {
  813. ULONG NamespaceHash = 0;
  814. IFFALSE_EXIT(::FusionpHashUnicodeString(UnicodeStringArray, NamespaceLengthArray[i], &NamespaceHash, 0));
  815. IFFALSE_EXIT(::SxspAllocateAssemblyIdentityNamespace(0, UnicodeStringArray, NamespaceLengthArray[i], NamespaceHash, &NamespacePointerArray[i]));
  816. UnicodeStringArray += NamespaceLengthArray[i];
  817. }
  818. if (AttributeCount != 0)
  819. {
  820. // and now those attributes...
  821. for (i=0; i<AttributeCount; i++)
  822. {
  823. const ULONG NamespaceIndex = EncodedAssemblyIdentityAttributeHeader[i].NamespaceIndex;
  824. const ULONG NameCch = EncodedAssemblyIdentityAttributeHeader[i].NameCch;
  825. const ULONG ValueCch = EncodedAssemblyIdentityAttributeHeader[i].ValueCch;
  826. const WCHAR * const Name = UnicodeStringArray;
  827. const WCHAR * const Value = &UnicodeStringArray[NameCch];
  828. UnicodeStringArray = &Value[ValueCch];
  829. IFFALSE_EXIT(
  830. ::SxspAllocateInternalAssemblyIdentityAttribute(
  831. 0,
  832. NamespacePointerArray[NamespaceIndex],
  833. Name,
  834. NameCch,
  835. Value,
  836. ValueCch,
  837. &AttributePointerArray[i]));
  838. }
  839. // sort 'em...
  840. qsort((PVOID) AttributePointerArray, AttributeCount, sizeof(PINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE), &SxspCompareInternalAttributesForQsort);
  841. }
  842. IFFALSE_EXIT(::SxspHashInternalAssemblyIdentityAttributes(0, AttributeCount, AttributePointerArray, &AssemblyIdentity->Hash));
  843. AssemblyIdentity->Flags = 0;
  844. AssemblyIdentity->Type = EncodedAssemblyIdentityHeader->Type;
  845. AssemblyIdentity->InternalFlags = ASSEMBLY_IDENTITY_INTERNAL_FLAG_ATTRIBUTE_POINTERS_IN_SEPARATE_ALLOCATION | ASSEMBLY_IDENTITY_INTERNAL_FLAG_NAMESPACE_POINTERS_IN_SEPARATE_ALLOCATION;
  846. AssemblyIdentity->AttributePointerArray = AttributePointerArray;
  847. AssemblyIdentity->AttributeCount = AttributeCount;
  848. AssemblyIdentity->AttributeArraySize = AttributeArraySize;
  849. AssemblyIdentity->NamespacePointerArray = NamespacePointerArray;
  850. AssemblyIdentity->NamespaceCount = NamespaceCount;
  851. AssemblyIdentity->NamespaceArraySize = NamespaceArraySize;
  852. AttributePointerArray = NULL;
  853. NamespacePointerArray = NULL;
  854. if (Flags & SXS_DECODE_ASSEMBLY_IDENTITY_FLAG_FREEZE)
  855. AssemblyIdentity->Flags |= ASSEMBLY_IDENTITY_FLAG_FROZEN;
  856. *AssemblyIdentityOut = AssemblyIdentity;
  857. AssemblyIdentity = NULL;
  858. fSuccess = TRUE;
  859. Exit:
  860. //
  861. // REVIEW: Should this be an SxsDestroyAssemblyIdentity
  862. //
  863. if (AssemblyIdentity != NULL)
  864. FUSION_DELETE_SINGLETON(AssemblyIdentity);
  865. if ((AttributeCount != 0) && (AttributePointerArray != NULL))
  866. {
  867. for (i=0; i<AttributeCount; i++)
  868. {
  869. if (AttributePointerArray[i] != NULL)
  870. {
  871. ::SxspDeallocateInternalAssemblyIdentityAttribute(AttributePointerArray[i]);
  872. AttributePointerArray[i] = NULL;
  873. }
  874. }
  875. FUSION_DELETE_ARRAY( AttributePointerArray );
  876. }
  877. if ((NamespaceCount != 0) && (NamespacePointerArray != NULL))
  878. {
  879. for (i=0; i<NamespaceCount; i++)
  880. {
  881. if (NamespacePointerArray[i] != NULL)
  882. {
  883. ::SxspDeallocateAssemblyIdentityNamespace(NamespacePointerArray[i]);
  884. NamespacePointerArray[i] = NULL;
  885. }
  886. }
  887. FUSION_DELETE_ARRAY( NamespacePointerArray );
  888. }
  889. return fSuccess;
  890. }