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.

652 lines
18 KiB

  1. /*--------------------------------------------------------------------------*
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1992 - 1998.
  5. *
  6. * File: strtable.inl
  7. *
  8. * Contents: Inline functions for strtable.h
  9. *
  10. * History: 25-Jun-98 jeffro Created
  11. *
  12. *--------------------------------------------------------------------------*/
  13. #ifndef STRTABLE_INL
  14. #define STRTABLE_INL
  15. #pragma once
  16. #include "macros.h" // for THROW_ON_FAIL
  17. #include "stgio.h"
  18. /*+-------------------------------------------------------------------------*
  19. * operator>>
  20. *
  21. * Reads a IdentifierRange<T> from a stream.
  22. *--------------------------------------------------------------------------*/
  23. template<class T>
  24. inline IStream& operator>> (IStream& stm, IdentifierRange<T>& range)
  25. {
  26. stm >> range.idMin >> range.idMax;
  27. if (range.idMin > range.idMax)
  28. _com_issue_error (E_FAIL);
  29. return (stm);
  30. }
  31. /*+-------------------------------------------------------------------------*
  32. * operator<<
  33. *
  34. * Writes a IdentifierRange<T> to a stream.
  35. *--------------------------------------------------------------------------*/
  36. template<class T>
  37. inline IStream& operator<< (IStream& stm, const IdentifierRange<T>& range)
  38. {
  39. return (stm << range.idMin << range.idMax);
  40. }
  41. /*+-------------------------------------------------------------------------*
  42. * CIdentifierPool<T>::CIdentifierPool
  43. *
  44. *
  45. *--------------------------------------------------------------------------*/
  46. template<class T>
  47. inline CIdentifierPool<T>::CIdentifierPool (T idMin_, T idMax_)
  48. : m_idAbsoluteMin (idMin_),
  49. m_idAbsoluteMax (idMax_),
  50. m_idNextAvailable (idMin_)
  51. {
  52. ASSERT (m_idAbsoluteMin <= m_idAbsoluteMax);
  53. m_AvailableIDs.push_front (Range (m_idAbsoluteMin, m_idAbsoluteMax));
  54. ASSERT (m_StaleIDs.empty());
  55. }
  56. template<class T>
  57. inline CIdentifierPool<T>::CIdentifierPool (IStream& stm)
  58. {
  59. stm >> *this;
  60. }
  61. /*+-------------------------------------------------------------------------*
  62. * CIdentifierPool<T>::Reserve
  63. *
  64. *
  65. *--------------------------------------------------------------------------*/
  66. template<class T>
  67. T CIdentifierPool<T>::Reserve ()
  68. {
  69. /*
  70. * if no more IDs are available, recycle the stale IDs
  71. */
  72. if (m_AvailableIDs.empty())
  73. {
  74. m_AvailableIDs.splice (m_AvailableIDs.end(), m_StaleIDs);
  75. ASSERT (m_StaleIDs.empty());
  76. }
  77. /*
  78. * if still no more IDs are available, throw an exception
  79. */
  80. if (m_AvailableIDs.empty())
  81. throw (pool_exhausted());
  82. /*
  83. * get the first ID from the first ID range
  84. */
  85. Range& FirstRange = m_AvailableIDs.front();
  86. T idReserved = FirstRange.idMin;
  87. /*
  88. * if we get here, we're going to return an ID, make sure it's the one
  89. * we though it was going to be
  90. */
  91. ASSERT (idReserved == m_idNextAvailable);
  92. /*
  93. * if the first ID range is now empty, remove it; otherwise,
  94. * remove the ID we just reserved from the available range
  95. */
  96. if (FirstRange.idMin == FirstRange.idMax)
  97. m_AvailableIDs.pop_front();
  98. else
  99. FirstRange.idMin++;
  100. /*
  101. * remember the next available ID
  102. */
  103. if (!m_AvailableIDs.empty())
  104. m_idNextAvailable = m_AvailableIDs.front().idMin;
  105. else if (!m_StaleIDs.empty())
  106. m_idNextAvailable = m_StaleIDs.front().idMin;
  107. else
  108. m_idNextAvailable = m_idAbsoluteMin;
  109. return (idReserved);
  110. }
  111. /*+-------------------------------------------------------------------------*
  112. * CIdentifierPool<T>::Release
  113. *
  114. *
  115. *--------------------------------------------------------------------------*/
  116. template<class T>
  117. bool CIdentifierPool<T>::Release (T idRelease)
  118. {
  119. /*
  120. * if the ID to be released falls outside
  121. * the range managed by this pool, fail
  122. */
  123. if ((idRelease < m_idAbsoluteMin) || (idRelease > m_idAbsoluteMax))
  124. {
  125. ASSERT (false);
  126. return (false);
  127. }
  128. /*
  129. * put the released ID in the stale pool
  130. */
  131. return (AddToRangeList (m_StaleIDs, idRelease));
  132. }
  133. /*+-------------------------------------------------------------------------*
  134. * CIdentifierPool<T>::IsValid
  135. *
  136. *
  137. *--------------------------------------------------------------------------*/
  138. template<class T>
  139. bool CIdentifierPool<T>::IsValid () const
  140. {
  141. if (m_idAbsoluteMin > m_idAbsoluteMax)
  142. return (false);
  143. if (!IsRangeListValid (m_AvailableIDs))
  144. return (false);
  145. if (!IsRangeListValid (m_StaleIDs))
  146. return (false);
  147. return (true);
  148. }
  149. /*+-------------------------------------------------------------------------*
  150. * CIdentifierPool<T>::IsRangeListValid
  151. *
  152. *
  153. *--------------------------------------------------------------------------*/
  154. template<class T>
  155. bool CIdentifierPool<T>::IsRangeListValid (const RangeList& rl) const
  156. {
  157. RangeList::const_iterator it;
  158. for (it = rl.begin(); it != rl.end(); ++it)
  159. {
  160. if ((it->idMin < m_idAbsoluteMin) ||
  161. (it->idMax > m_idAbsoluteMax))
  162. return (false);
  163. }
  164. return (true);
  165. }
  166. /*+-------------------------------------------------------------------------*
  167. * CIdentifierPool<T>::ScGenerate
  168. *
  169. *
  170. *--------------------------------------------------------------------------*/
  171. template<class T>
  172. SC CIdentifierPool<T>::ScGenerate (const RangeList& rlInUseIDs)
  173. {
  174. DECLARE_SC (sc, _T("CIdentifierPool<T>::ScGenerate"));
  175. m_AvailableIDs.clear();
  176. m_StaleIDs.clear();
  177. /*
  178. * Invert the in-use IDs. We'll then have a collection of all the
  179. * ID's that are not in use. Note that not all of these ID's are
  180. * necessarily "available", since some may be stale.
  181. */
  182. RangeList rlNotInUseIDs = rlInUseIDs;
  183. sc = ScInvertRangeList (rlNotInUseIDs);
  184. if (sc)
  185. return (sc);
  186. /*
  187. * Find the range containing the next available ID.
  188. */
  189. RangeList::iterator it;
  190. for (it = rlNotInUseIDs.begin(); it != rlNotInUseIDs.end(); ++it)
  191. {
  192. /*
  193. * if this range contains the next available ID, we've found a hit
  194. */
  195. if ((m_idNextAvailable >= it->idMin) && (m_idNextAvailable <= it->idMax))
  196. {
  197. /*
  198. * if the next available ID is at the beginning of this range,
  199. * things are simple; we can just break out of the loop
  200. */
  201. if (m_idNextAvailable == it->idMin)
  202. break;
  203. /*
  204. * otherwise, we need to split the current range into two
  205. * adjacent ranges so the code below that copies to the
  206. * stale and available ranges can work; then we can break out
  207. * of the loop
  208. */
  209. Range range (m_idNextAvailable, it->idMax);
  210. it->idMax = m_idNextAvailable - 1;
  211. it = rlNotInUseIDs.insert (++it, range);
  212. break;
  213. }
  214. }
  215. /*
  216. * confirm that we found one
  217. */
  218. ASSERT (it != rlNotInUseIDs.end());
  219. /*
  220. * everything before the next available ID that's not it use is stale;
  221. * everything after the next available ID that's not in use is available;
  222. */
  223. std::copy (rlNotInUseIDs.begin(), it, std::back_inserter(m_StaleIDs));
  224. std::copy (it, rlNotInUseIDs.end(), std::back_inserter(m_AvailableIDs));
  225. return (sc);
  226. }
  227. /*+-------------------------------------------------------------------------*
  228. * CIdentifierPool<T>::AddToRangeList
  229. *
  230. * This adds an identifier to the specified range list.
  231. *
  232. * This really should be a member function on a RangeList class, like so:
  233. *
  234. * class RangeList : public std::list<Range>
  235. * {
  236. * public:
  237. * bool Add (const Range& rangeToAdd);
  238. * bool Add (T tAdd);
  239. * };
  240. *
  241. * but compiler bugs prevent it.
  242. *--------------------------------------------------------------------------*/
  243. template<class T>
  244. bool CIdentifierPool<T>::AddToRangeList (RangeList& rl, T idAdd)
  245. {
  246. return (AddToRangeList (rl, Range (idAdd, idAdd)));
  247. }
  248. template<class T>
  249. bool CIdentifierPool<T>::AddToRangeList (RangeList& l, const Range& rangeToAdd)
  250. {
  251. RangeList::iterator it;
  252. for (it = l.begin(); it != l.end(); ++it)
  253. {
  254. Range& rangeT = *it;
  255. /*
  256. * the range to add shouldn't overlap the existing range in any way
  257. */
  258. if (((rangeToAdd.idMin >= rangeT.idMin) && (rangeToAdd.idMin <= rangeT.idMax)) ||
  259. ((rangeToAdd.idMax >= rangeT.idMin) && (rangeToAdd.idMax <= rangeT.idMax)))
  260. {
  261. ASSERT (false);
  262. return (false);
  263. }
  264. /*
  265. * If the range to add is immediately to the left of the current
  266. * range (that is, the upper bound of the range to add is immediately
  267. * adjacent to the lower bound of the current range), it can be
  268. * absorbed into the current range and we're done.
  269. *
  270. * Note that we don't have to worry about coalescing this range
  271. * with the preceeding range. That case would have been covered
  272. * by the next clause, in the preceeding iteration of this loop.
  273. */
  274. if (rangeToAdd.idMax == (rangeT.idMin - 1))
  275. {
  276. rangeT.idMin = rangeToAdd.idMin;
  277. return (true);
  278. }
  279. /*
  280. * If the range to add is immediately to the right of the current
  281. * range (that is, the lower bound of the range to add is immediately
  282. * adjacent to the upper bound of the current range), it can be
  283. * absorbed into the current range and we're done.
  284. */
  285. else if (rangeToAdd.idMin == (rangeT.idMax + 1))
  286. {
  287. rangeT.idMax = rangeToAdd.idMax;
  288. /*
  289. * Now check the next available range (if there is one).
  290. * If it begins where the current range now ends, then
  291. * the two ranges can be coalesced into a single range.
  292. */
  293. if (++it != l.end())
  294. {
  295. Range& rangeNext = *it;
  296. ASSERT (rangeT.idMax < rangeNext.idMin);
  297. if (rangeT.idMax == (rangeNext.idMin - 1))
  298. {
  299. rangeT.idMax = rangeNext.idMax;
  300. l.erase (it);
  301. }
  302. }
  303. return (true);
  304. }
  305. /*
  306. * If the upper bound of the range to insert is less than the
  307. * lower bound of the current available range, we need to insert
  308. * the new range here. The insertion is handled outside the loop.
  309. */
  310. else if (rangeToAdd.idMax < rangeT.idMin)
  311. break;
  312. }
  313. /*
  314. * If we get here, then we need to create a new available range
  315. * to the left of the current iterator, which will address the
  316. * end of the list if the ID is greater than the current maximum
  317. * available ID.
  318. */
  319. ASSERT ((it == l.end()) || (rangeToAdd.idMax < (it->idMin - 1)));
  320. l.insert (it, rangeToAdd);
  321. return (true);
  322. }
  323. /*+-------------------------------------------------------------------------*
  324. * CIdentifierPool<T>::ScInvertRangeList
  325. *
  326. * Changes rlInvert into a range list containing all elements between
  327. * m_idAbsoluteMin and m_idAbsoluteMax that were not originally in
  328. * rlInvert.
  329. *
  330. * So, if the range looks like this before inversion:
  331. *
  332. * +----+----+ +----+----+
  333. * m_idAbsoluteMin | 5 | 10 | --------> | 15 | 20 | m_idAbsoluteMax
  334. * +----+----+ +----+----+
  335. *
  336. * it will look like this after inversion:
  337. *
  338. * +-----------------+----+ +----+----+ +----+-----------------+
  339. * | m_idAbsoluteMin | 4 | --------> | 11 | 14 | --------> | 21 | m_idAbsoluteMax |
  340. * +-----------------+----+ +----+----+ +----+-----------------+
  341. *--------------------------------------------------------------------------*/
  342. template<class T>
  343. SC CIdentifierPool<T>::ScInvertRangeList (RangeList& rlInvert) const
  344. {
  345. DECLARE_SC (sc, _T("CIdentifierPool::ScInvertRangeList"));
  346. /*
  347. * if there's nothing in the list to invert, the inverted
  348. * list will contain a single range spanning min to max
  349. */
  350. if (rlInvert.empty())
  351. {
  352. rlInvert.push_front (Range (m_idAbsoluteMin, m_idAbsoluteMax));
  353. return (sc);
  354. }
  355. /*
  356. * determine whether we'll need to add ranges on the front or back,
  357. * and initialize the ranges we'll add if we will
  358. */
  359. Range rFirst;
  360. bool fAddFirstRange = (rlInvert.front().idMin > m_idAbsoluteMin);
  361. if (fAddFirstRange)
  362. {
  363. rFirst.idMin = m_idAbsoluteMin;
  364. rFirst.idMax = rlInvert.front().idMin - 1;
  365. }
  366. Range rLast;
  367. bool fAddLastRange = (rlInvert.back().idMax < m_idAbsoluteMax);
  368. if (fAddLastRange)
  369. {
  370. rLast.idMin = rlInvert.back().idMax + 1;
  371. rLast.idMax = m_idAbsoluteMax;
  372. }
  373. /*
  374. * Change rlInvert to contain ranges that represent the gaps
  375. * between the ranges it currently contains. The size of rlInvert
  376. * will be one less than its original size when this process is
  377. * complete.
  378. */
  379. RangeList::iterator it = rlInvert.begin();
  380. RangeList::iterator itNext = ++rlInvert.begin();
  381. while (itNext != rlInvert.end())
  382. {
  383. /*
  384. * morph this range into the range representing the gap between
  385. * this range and the next one
  386. */
  387. it->idMin = it->idMax + 1;
  388. it->idMax = itNext->idMin - 1;
  389. /*
  390. * advance the iterators
  391. */
  392. it = itNext++;
  393. }
  394. /*
  395. * remove the extraneous node at the end of the list
  396. */
  397. rlInvert.pop_back();
  398. /*
  399. * append to the beginning and/or end, if necessary
  400. */
  401. if (fAddFirstRange)
  402. rlInvert.push_front (rFirst);
  403. if (fAddLastRange)
  404. rlInvert.push_back (rLast);
  405. return (sc);
  406. }
  407. /*+-------------------------------------------------------------------------*
  408. * operator>>
  409. *
  410. * Reads a CIdentifierPool<T> from a stream
  411. *--------------------------------------------------------------------------*/
  412. template<class T>
  413. IStream& operator>> (IStream& stm, CIdentifierPool<T>& pool)
  414. {
  415. /*
  416. * read the min and max IDs from the stream
  417. */
  418. stm >> pool.m_idAbsoluteMin >> pool.m_idAbsoluteMax;
  419. /*
  420. * read the available and stale IDs
  421. */
  422. stm >> pool.m_AvailableIDs >> pool.m_StaleIDs;
  423. /*
  424. * find out how big the stream is
  425. */
  426. STATSTG statstg;
  427. HRESULT hr = stm.Stat (&statstg, STATFLAG_NONAME);
  428. if (FAILED (hr))
  429. _com_issue_error (hr);
  430. /*
  431. * get our seek position
  432. */
  433. ULARGE_INTEGER uliSeekPos;
  434. LARGE_INTEGER liOffset;
  435. liOffset.QuadPart = 0;
  436. hr = stm.Seek (liOffset, STREAM_SEEK_CUR, &uliSeekPos);
  437. if (FAILED (hr))
  438. _com_issue_error (hr);
  439. /*
  440. * Older files won't have saved the next available ID. If it's there,
  441. * read it; if not, use a default value for pool.m_idNextAvailable.
  442. */
  443. if (statstg.cbSize.QuadPart > uliSeekPos.QuadPart)
  444. {
  445. stm >> pool.m_idNextAvailable;
  446. }
  447. else
  448. {
  449. if (!pool.m_AvailableIDs.empty())
  450. pool.m_idNextAvailable = pool.m_AvailableIDs.front().idMin;
  451. else
  452. pool.m_idNextAvailable = pool.m_idAbsoluteMin;
  453. }
  454. /*
  455. * validate what we read
  456. */
  457. if (!pool.IsValid ())
  458. _com_issue_error (E_FAIL);
  459. return (stm);
  460. }
  461. /*+-------------------------------------------------------------------------*
  462. * operator<<
  463. *
  464. * Writes a CIdentifierPool<T> to a stream.
  465. *--------------------------------------------------------------------------*/
  466. template<class T>
  467. IStream& operator<< (IStream& stm, const CIdentifierPool<T>& pool)
  468. {
  469. /*
  470. * write the min and max IDs to the stream
  471. */
  472. stm << pool.m_idAbsoluteMin << pool.m_idAbsoluteMax;
  473. /*
  474. * Write an empty collection of available and stale IDs to keep the
  475. * stream format the same as previous versions. Beginning with MMC 2.0,
  476. * the available and stale IDs will be regenerated from the next available
  477. * ID and in-use IDs after the string table is read in. This is done to
  478. * minimize the data that needs to be saved with the new XML file format.
  479. */
  480. CIdentifierPool<T>::RangeList rlEmpty;
  481. stm << rlEmpty; // available IDs
  482. stm << rlEmpty; // stale IDs
  483. /*
  484. * write the next available ID
  485. */
  486. stm << pool.m_idNextAvailable;
  487. return (stm);
  488. }
  489. template<class T>
  490. void CIdentifierPool<T>::Persist(CPersistor &persistor)
  491. {
  492. persistor.PersistAttribute(XML_ATTR_ID_POOL_ABSOLUTE_MIN, m_idAbsoluteMin);
  493. persistor.PersistAttribute(XML_ATTR_ID_POOL_ABSOLUTE_MAX, m_idAbsoluteMax);
  494. persistor.PersistAttribute(XML_ATTR_ID_POOL_NEXT_AVAILABLE, m_idNextAvailable);
  495. }
  496. /*+-------------------------------------------------------------------------*
  497. * CIdentifierPool<T>::Dump
  498. *
  499. *
  500. *--------------------------------------------------------------------------*/
  501. #ifdef DBG
  502. template<class T>
  503. void CIdentifierPool<T>::DumpRangeList (const RangeList& l) const
  504. {
  505. int cEntries = 0;
  506. for (RangeList::const_iterator it = l.begin(); it != l.end(); ++it)
  507. {
  508. Trace (tagStringTable, _T("Range %d:min=%d, max=%d"),
  509. ++cEntries, (int) it->idMin, (int) it->idMax);
  510. }
  511. }
  512. template<class T>
  513. void CIdentifierPool<T>::Dump () const
  514. {
  515. Trace (tagStringTable, _T("Next available ID: %d"), m_idNextAvailable);
  516. Trace (tagStringTable, _T("Available IDs:"));
  517. DumpRangeList (m_AvailableIDs);
  518. Trace (tagStringTable, _T("Stale IDs:"));
  519. DumpRangeList (m_StaleIDs);
  520. }
  521. #endif // DBG
  522. /*+-------------------------------------------------------------------------*
  523. * operator>>
  524. *
  525. *
  526. *--------------------------------------------------------------------------*/
  527. inline IStorage& operator>> (IStorage& stg, CComObject<CMasterStringTable>& mst)
  528. {
  529. return (stg >> static_cast<CMasterStringTable&>(mst));
  530. }
  531. /*+-------------------------------------------------------------------------*
  532. * operator<<
  533. *
  534. *
  535. *--------------------------------------------------------------------------*/
  536. inline IStorage& operator<< (IStorage& stg, const CComObject<CMasterStringTable>& mst)
  537. {
  538. return (stg << static_cast<const CMasterStringTable&>(mst));
  539. }
  540. #endif /* STRTABLE_INL */