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.

427 lines
14 KiB

  1. #pragma once
  2. #include "basic.h"
  3. #include "encode.h"
  4. // there are 3 types of pool:
  5. // (1). case-insensitive string pool
  6. // (2). case-sensitive string pool
  7. // (3). GUID pool
  8. #define MAX_DWORD 0xFFFF
  9. typedef enum _sxs_pool_type_{
  10. SXS_POOL_TYPE_UNIDENTIFIED,
  11. SXS_POOL_TYPE_GUID,
  12. SXS_POOL_TYPE_CASE_INSENSITIVE_STRING,
  13. SXS_POOL_TYPE_CASE_SENSITIVE_STRING
  14. }SXS_POOL_TYPE;
  15. // default action is error if already exist in the pool
  16. #define SXS_POOL_ADD_IF_ALREADY_IN_POOL_IGNORE 0x0001
  17. #define SXS_STRING_POOL_DEFAULT_SIZE_IN_BYTE 1024
  18. #define SXS_GUID_POOL_DEFAULT_SIZE_IN_BYTE 1024
  19. #define SXS_POOL_DEFAULT_INDEX_TABLE_SIZE 32
  20. #define SXS_POOL_INDEXTABLE_PROBE_ONLY 0x0000
  21. #define SXS_POOL_INDEXTABLE_PROBE_IF_NOT_EXIST_INSERT_DATA 0x0001
  22. #define SXS_POOL_ADD_CONVERTED_DATA_INTO_POOL 0x0001
  23. #define SXS_POOL_ADD_DATA_INTOP_OOL_CONVERT_FIRST 0x0002
  24. /*
  25. class SXS_POOL_INDEX_ENTRY{
  26. private:
  27. inline VOID SetOffset(DWORD offset) {m_offset = offset;};
  28. virtual VOID SetLength(DWORD length) = 0;
  29. inline DWORD GetOffset() const {return m_offset; }
  30. virtual DWORD GetLength() const = 0;
  31. DWORD m_offset;
  32. }
  33. */
  34. class SXS_POOL_INDEX_ENTRY{
  35. public:
  36. SXS_POOL_INDEX_ENTRY(){}
  37. virtual VOID SetIndexEntry(DWORD offset, DWORD length) = 0;
  38. virtual VOID GetIndexEntry(DWORD & offset, DWORD * length) = 0;
  39. inline DWORD GetOffset() const {return m_offset;}
  40. inline VOID SetOffset(DWORD offset) {m_offset = offset;}
  41. protected:
  42. DWORD m_offset;
  43. };
  44. class SXS_STRING_POOL_INDEX_ENTRY : public SXS_POOL_INDEX_ENTRY{
  45. public:
  46. inline VOID SetIndexEntry(DWORD offset, DWORD length) { m_offset = offset; m_length = length;}
  47. inline VOID GetIndexEntry(DWORD & offset, DWORD * length){ offset = m_offset; ASSERT(length != NULL); *length = m_length;}
  48. inline DWORD GetLength() const { return m_length; }
  49. private:
  50. DWORD m_length;
  51. };
  52. class SXS_GUID_POOL_INDEX_ENTRY : public SXS_POOL_INDEX_ENTRY{
  53. public:
  54. inline VOID SetIndexEntry(DWORD offset, DWORD length = 0){ m_offset = offset; }
  55. inline VOID GetIndexEntry(DWORD & offset, DWORD * length = NULL) {offset = m_offset; }
  56. };
  57. class SXS_POOL_DATA{
  58. public:
  59. SXS_POOL_DATA(DWORD dwUnitSize):m_dwCount(1), m_dwUnitSize(dwUnitSize){}
  60. SXS_POOL_DATA(DWORD dwUnitSize, DWORD c):m_dwCount(c), m_dwUnitSize(dwUnitSize){}
  61. inline BOOL IsContentEqual(SXS_POOL_DATA & b)
  62. {
  63. if (this->GetSizeInByte() == b.GetSizeInByte())
  64. return (memcmp(this->GetPtr(), b.GetPtr(), GetSizeInByte()) == 0);
  65. return FALSE;
  66. }
  67. inline DWORD GetSizeInByte() const { return m_dwCount * m_dwUnitSize; }
  68. virtual PBYTE GetPtr() const = 0;
  69. protected:
  70. DWORD m_dwCount;
  71. DWORD m_dwUnitSize;
  72. };
  73. template <typename TSimpleDataType>
  74. class SXS_SIMPLEDATA_POOL_DATA : public SXS_POOL_DATA
  75. {
  76. public:
  77. SXS_SIMPLEDATA_POOL_DATA(TSimpleDataType & d): m_data(d) {SXS_SIMPLEDATA_POOL_DATA(); }
  78. SXS_SIMPLEDATA_POOL_DATA(TSimpleDataType d): m_data(d) {SXS_SIMPLEDATA_POOL_DATA(); }
  79. inline VOID SetValue(const TSimpleDataType & data) {m_data = data;}
  80. inline VOID GetValue(TSimpleDataType & data) {data = m_data;}
  81. inline PBYTE GetPtr() const { return (PBYTE)&m_data; }; // since it is already a ref
  82. protected:
  83. TSimpleDataType & m_data;
  84. SXS_SIMPLEDATA_POOL_DATA():SXS_POOL_DATA(sizeof(TSimpleDataType)){}
  85. };
  86. //
  87. // this class is never been reassigned, that is, once it is assigned value, it will keep this value until it is deconstructed
  88. //
  89. template <typename TCHAR>
  90. class SXS_STRING_DATA : public SXS_POOL_DATA{
  91. public:
  92. SXS_STRING_DATA():
  93. m_pstrData(NULL), m_fMemoryAllocatedInside(false), m_fValueAssigned(false), SXS_POOL_DATA(sizeof(TCHAR), 0), m_Cch(m_dwCount){}
  94. ~SXS_STRING_DATA()
  95. {
  96. if (m_fMemoryAllocatedInside) {
  97. FUSION_FREE_ARRAY(m_pstrData);
  98. }
  99. }
  100. NTSTATUS NtAssign(PCWSTR Str, DWORD Cch);
  101. NTSTATUS NtAssign(PBYTE Str, DWORD Ccb);
  102. NTSTATUS NtResize(DWORD cch)
  103. {
  104. NTSTATUS Status = STATUS_SUCCESS;
  105. FN_TRACE_NTSTATUS(Status);
  106. INTERNAL_ERROR_CHECK(m_fValueAssigned == false);
  107. INTERNAL_ERROR_CHECK(m_pstrData == NULL);
  108. IFALLOCFAILED_EXIT(m_pstrData = FUSION_NEW_ARRAY(TCHAR, cch));
  109. m_Cch = cch;
  110. FN_EPILOG;
  111. }
  112. inline VOID Clean() const {ASSERT(m_pstrData != NULL); m_pstrData[0] = 0;}
  113. inline DWORD GetCch() const { return m_Cch; }
  114. inline TCHAR* GetStr() const { return m_pstrData;}
  115. inline TCHAR* GetBuffer() { return m_pstrData;}
  116. inline PBYTE GetPtr() const { return (PBYTE)m_pstrData; }; // since it is already a ref
  117. private:
  118. TCHAR* m_pstrData; // offset in the pool
  119. DWORD &m_Cch; // length of TCHAR
  120. bool m_fValueAssigned;
  121. bool m_fMemoryAllocatedInside;
  122. };
  123. template <typename TInputData, typename TIndexTableData, typename TPoolData, DWORD dwPoolSize = 0, DWORD dwIndexTableSize = 0>
  124. class SxsPool{
  125. public:
  126. SxsPool():m_fInitialized(false), m_ePooltype(SXS_POOL_TYPE_UNIDENTIFIED), m_dwPoolSizeInByte(0),
  127. m_pbPool(NULL), m_cursor(NULL), m_IndexData(NULL), m_IndexTableSize(0), m_cConflict(0) {}
  128. ~SxsPool(){
  129. switch(m_ePooltype)
  130. {
  131. default:
  132. ASSERT(FALSE); // never happen
  133. break;
  134. case SXS_POOL_TYPE_UNIDENTIFIED:
  135. {
  136. ASSERT(m_pbPool == NULL);
  137. ASSERT(m_dwPoolSizeInByte == 0);
  138. ASSERT(m_cursor == NULL);
  139. ASSERT(m_IndexData == NULL);
  140. ASSERT(m_IndexTableSize == 0);
  141. break;
  142. }
  143. case SXS_POOL_TYPE_GUID:
  144. case SXS_POOL_TYPE_CASE_INSENSITIVE_STRING:
  145. case SXS_POOL_TYPE_CASE_SENSITIVE_STRING:
  146. {
  147. FUSION_DELETE_BLOB(m_pbPool);
  148. FUSION_FREE_ARRAY(m_IndexData);
  149. break;
  150. }
  151. }// end of switch
  152. }
  153. NTSTATUS Initialize(IN SXS_POOL_TYPE ePoolType)
  154. {
  155. NTSTATUS Status = STATUS_SUCCESS;
  156. FN_TRACE_NTSTATUS(Status);
  157. PARAMETER_CHECK((ePooltype == SXS_GUID_POOL) ||
  158. (ePooltype == SXS_CASE_INSENSITIVE_STRING_POOL) ||
  159. (ePooltype == SXS_CASE_SENSITIVE_STRING_POOL));
  160. INTERNAL_ERROR_CHECK(m_fInitialized == false);
  161. m_fInitialized = true;
  162. m_ePooltype = ePooltype;
  163. m_dwPoolSizeInByte = dwPoolSize;
  164. if (m_dwPoolSizeInByte == 0)
  165. m_dwPoolSizeInByte = (ePooltype != SXS_GUID_POOL ? SXS_STRING_POOL_DEFAULT_SIZE_IN_BYTE : SXS_GUID_POOL_DEFAULT_SIZE_IN_BYTE);
  166. IFALLOCFAILED_EXIT(m_pbPool = FUSION_NEW_BLOB(m_dwPoolSizeInByte));
  167. m_cursor = NULL;
  168. m_IndexTableSize = dwIndexTableSize > 0 ? dwIndexTableSize : SXS_POOL_DEFAULT_INDEX_TABLE_SIZE;
  169. IFALLOCFAILED_EXIT(m_IndexData = FUSION_NEW_ARRAY(TIndexTableData, m_IndexTableSize));
  170. ZeroMemory(m_IndexData, sizeof(TIndexTableData) * m_IndexTableSize);
  171. FN_EPILOG;
  172. }
  173. // Function:
  174. //
  175. // adding a string/guid into pool, adding entry to index table
  176. // return the index in the index table
  177. // this function is used mostly
  178. //
  179. NTSTATUS Add(
  180. IN DWORD dwFlags,
  181. IN const TInputData& data,
  182. OUT BOOL& fAlreadyExist,
  183. OUT DWORD& dwIndexInTable
  184. )
  185. {
  186. NTSTATUS Status = STATUS_SUCCESS;
  187. FN_TRACE_NTSTATUS(Status);
  188. DWORD dwIndex;
  189. TIndexTableData dataInIndexTable;
  190. TPoolData poolData;
  191. ULONG ulHash;
  192. PARAMETER_CHECK((dwFlags & ~SXS_POOL_ADD_IF_ALREADY_IN_POOL_IGNORE) == 0);
  193. INTERNAL_ERROR_CHECK(m_fInitialized == true);
  194. IF_NOT_NTSTATUS_SUCCESS_EXIT(ConverInputDataIntoPoolData(0, data, poolData));
  195. IF_NOT_NTSTATUS_SUCCESS_EXIT(HashData(0, data, ulHash));
  196. // check whether the data has already in the pool and whether this is allowed
  197. IF_NOT_NTSTATUS_SUCCESS_EXIT(LocateEntryInIndexTable(0, poolData, ulHash, fAlreadyExist, dwIndex));
  198. if ((fAlreadyExist) && (!(dwFlags & SXS_POOL_ADD_IF_ALREADY_IN_POOL_IGNORE)))
  199. {
  200. Status = STATUS_DUPLICATE_NAME;
  201. goto Exit;
  202. }
  203. IF_NOT_NTSTATUS_SUCCESS_EXIT(SaveDataIntoPool(0, dwIndex, poolData));
  204. dwIndexInTable = dwIndex;
  205. FN_EPILOG;
  206. }
  207. // Function:
  208. //
  209. // fetch data (string or a guid) from pool
  210. // if data == NULL, length will be returned about the required bytes
  211. //
  212. NTSTATUS FetchDataFromPool(
  213. IN DWORD dwFlags,
  214. IN DWORD dwIndex,
  215. OUT TInputData & data
  216. )
  217. {
  218. NTSTATUS Status = STATUS_SUCCESS;
  219. FN_TRACE_NTSTATUS(Status);
  220. TPoolData PoolData;
  221. PARAMETER_CHECK(dwFlags == 0);
  222. IF_NOT_NTSTATUS_SUCCESS_EXIT(GetDataFromPoolBasedOnIndexTable(m_IndexData[dwIndex], PoolData));
  223. IF_NOT_NTSTATUS_SUCCESS_EXIT(ConvertPoolDataToOutputData(0, PoolData, data));
  224. FN_EPILOG;
  225. }
  226. private:
  227. // private functions
  228. // functions must be instantiated
  229. inline VOID SetIndexTableEntry(TIndexTableData & entry, DWORD offset, DWORD length =0);
  230. NTSTATUS GetDataFromPoolBasedOnIndexTable(
  231. IN TIndexTableData & indexData,
  232. OUT TPoolData & pooldata
  233. );
  234. NTSTATUS HashData(
  235. IN DWORD dwFlags,
  236. IN const TInputData& data,
  237. OUT ULONG& ulHashValue
  238. );
  239. NTSTATUS ConvertPoolDataToOutputData(
  240. IN DWORD dwFlags,
  241. IN TPoolData & dataInPool,
  242. OUT TInputData & dataOut
  243. );
  244. NTSTATUS ConverInputDataIntoPoolData(
  245. IN DWORD dwFlags,
  246. IN const TInputData & dataOut,
  247. OUT TPoolData & dataInPool
  248. );
  249. // "real" template functions
  250. NTSTATUS ExtendPool(DWORD dwMiniRequirement)
  251. {
  252. NTSTATUS Status = STATUS_SUCCESS;
  253. FN_TRACE_NTSTATUS(Status);
  254. BYTE * tpool = NULL;
  255. DWORD dwExtend = MAX(dwMiniRequirement, m_dwPoolSizeInByte / 2);
  256. if ( dwExtend + m_dwPoolSizeInByte > MAX_DWORD)
  257. {
  258. Status = STATUS_INTEGER_OVERFLOW;
  259. goto Exit;
  260. }
  261. IFALLOCFAILED_EXIT(tpool = FUSION_NEW_BLOB(dwExtend + m_dwPoolSizeInByte));
  262. DWORD dwOccupied = m_cursor - m_pbPool;
  263. memcpy(tpool, m_pbPool, dwOccupied);
  264. FUSION_DELETE_BLOB(m_pbPool);
  265. m_pbPool = tpool;
  266. tpool = NULL;
  267. m_dwPoolSizeInByte = dwExtend + m_dwPoolSizeInByte;
  268. m_cursor = m_pbPool + dwOccupied;
  269. Exit:
  270. if (tpool != NULL)
  271. FUSION_DELETE_BLOB(tpool);
  272. return Status;
  273. }
  274. NTSTATUS LocateEntryInIndexTable(
  275. IN DWORD dwFlags,
  276. IN const TPoolData& poolData,
  277. IN ULONG ulHash,
  278. OUT BOOL& fAlreadyExist,
  279. OUT DWORD& dwIndexOut
  280. )
  281. {
  282. NTSTATUS Status = STATUS_SUCCESS;
  283. FN_TRACE_NTSTATUS(Status);
  284. ULONG ulHash2;
  285. ULONG ulIndex;
  286. TPoolData StoredData;
  287. DWORD dwSizeMask = m_IndexTableSize - 1;
  288. BOOL fExist = false;
  289. PARAMETER_CHECK(dwFlags == 0);
  290. fAlreadyExist = FALSE;
  291. ulIndex = ulHash & dwSizeMask;
  292. ulHash2 = ((ulHash * 17) & dwSizeMask) | 1;
  293. while(1) {
  294. if (m_IndexData[ulIndex].GetOffset() == 0) // index empty
  295. break;
  296. IF_NOT_NTSTATUS_SUCCESS_EXIT(GetDataFromPoolBasedOnIndexTable(m_IndexData[ulIndex], StoredData));
  297. if (StoredData.IsContentEqual(const_cast<TPoolData &>(poolData)))
  298. {
  299. fExist = TRUE;
  300. break;
  301. }
  302. // rehash
  303. ulIndex = (ulIndex + ulHash2) & dwSizeMask;
  304. m_cConflict ++;
  305. }
  306. fAlreadyExist = fExist;
  307. dwIndexOut = (DWORD)ulIndex;
  308. FN_EPILOG;
  309. }
  310. NTSTATUS SaveDataIntoPool(
  311. IN DWORD dwFlags,
  312. IN DWORD dwEntryIndexTable,
  313. IN const TPoolData & poolData
  314. )
  315. {
  316. NTSTATUS Status = STATUS_SUCCESS;
  317. FN_TRACE_NTSTATUS(Status);
  318. PARAMETER_CHECK(dwFlags == 0);
  319. DWORD dwRequiredDataSizeInByte = poolData.GetSizeInByte();
  320. if ( dwRequiredDataSizeInByte > m_dwPoolSizeInByte - (m_cursor - m_pbPool))
  321. {
  322. IF_NOT_NTSTATUS_SUCCESS_EXIT(ExtendPool(dwRequiredDataSizeInByte));
  323. }
  324. memcpy(m_cursor, poolData.GetPtr(), dwRequiredDataSizeInByte);
  325. m_IndexData[dwEntryIndexTable].SetIndexEntry(m_cursor - m_pbPool, poolData.GetCch());
  326. m_cursor += dwRequiredDataSizeInByte;
  327. FN_EPILOG;
  328. }
  329. // private data member
  330. bool m_fInitialized;
  331. SXS_POOL_TYPE m_ePooltype;
  332. PBYTE m_pbPool;
  333. DWORD m_dwPoolSizeInByte;
  334. PBYTE m_cursor;
  335. TIndexTableData* m_IndexData; // only needed for string pool
  336. DWORD m_IndexTableSize;
  337. // for statistics purpose
  338. DWORD m_cConflict;
  339. DWORD m_cSearch;
  340. };
  341. typedef SXS_STRING_DATA<BYTE> SXS_STRING_POOL_DATA;
  342. typedef SXS_STRING_DATA<WCHAR> SXS_STRING_POOL_INPUT_DATA;
  343. typedef SXS_SIMPLEDATA_POOL_DATA<GUID> SXS_GUID_POOL_DATA;
  344. typedef SxsPool<SXS_STRING_POOL_INPUT_DATA, SXS_STRING_POOL_INDEX_ENTRY, SXS_STRING_POOL_DATA> SXS_STRING_POOL;
  345. typedef SxsPool<GUID, SXS_GUID_POOL_INDEX_ENTRY, SXS_GUID_POOL_DATA> SXS_GUID_POOL;