strlist.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 14k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //----------------------------------------------------------------------------
  2. //
  3. //----------------------------------------------------------------------------
  4. #include "private.h"
  5. #include "strlist.h"
  6. #define TF_THISMODULE   TF_STRINGLIST
  7. //----------------------------------------------------------------------------
  8. // CWCStringList
  9. CWCStringList::CWCStringList()
  10. {
  11.     // We may be able to remove this Clear() call if we guarantee that
  12.     //  1) the new operator zero inits
  13.     //  2) we don't use this class on the stack
  14.     Clear();
  15. }
  16. CWCStringList::~CWCStringList()
  17. {
  18. #ifdef DEBUG
  19.     if (m_iNumStrings > 100)
  20.         SpewHashStats(TRUE);
  21. #endif
  22.     CleanUp();
  23. }
  24. // Clean up any allocated memory
  25. void CWCStringList::CleanUp()
  26. {
  27.     if (!m_fValid)
  28.         return;
  29.     if (m_pBuffer)
  30.     {
  31.         MemFree(m_pBuffer);
  32.         m_pBuffer = NULL;
  33.     }
  34.     if (m_psiStrings)
  35.     {
  36.         MemFree(m_psiStrings);
  37.         m_psiStrings = NULL;
  38.     }
  39.     m_fValid = FALSE;
  40. }
  41. // Clear our internal structures to prepare to be initialized. Assumes we
  42. //  have no allocated memory (call CleanUp())
  43. void CWCStringList::Clear()
  44. {
  45.     m_fValid = FALSE;
  46.     m_iBufEnd = m_iBufSize = m_iNumStrings = m_iMaxStrings = 0;
  47.     m_pBuffer = NULL;
  48.     m_psiStrings = NULL;
  49.     ZeroMemory(m_Hash, sizeof(m_Hash));
  50. }
  51. void CWCStringList::Reset()
  52. {
  53.     if (m_fValid || m_pBuffer || m_psiStrings)
  54.     {
  55.         CleanUp();
  56.         Clear();
  57.     }
  58. }
  59. BOOL CWCStringList::Init(int iInitBufSize)
  60. {
  61.     if (m_fValid)
  62.     {
  63.         DBG("WCStringList::Init called when already initialized");
  64.         Reset();
  65.     }
  66.     if (iInitBufSize <= 0)
  67.     {
  68.         iInitBufSize = DEFAULT_INIT_BUF_SIZE;
  69.     }
  70.     m_iMaxStrings = iInitBufSize >> 5;  // this is relatively arbitrary but doesn't matter much
  71.     m_pBuffer = (LPSTR)MemAlloc(LMEM_FIXED, iInitBufSize);
  72.     m_psiStrings = (LPSTRING_INDEX)MemAlloc(LMEM_FIXED, m_iMaxStrings * sizeof(STRING_INDEX));
  73.     if ((NULL == m_psiStrings) ||
  74.         (NULL == m_pBuffer))
  75.     {
  76.         DBG_WARN("Init() memory allocation failed");
  77.         CleanUp();
  78.         return FALSE;
  79.     }
  80.     *m_pBuffer = 0;
  81.     m_iBufSize = iInitBufSize;
  82.     m_iBufEnd = 0;
  83.     m_fValid = TRUE;
  84.     return TRUE;
  85. }
  86. // Sets up our internal data structures (hash and string_index)
  87. // Sets m_iBufEnd.
  88. // We must already be Init()ialized and the data in m_pBuffer
  89. BOOL CWCStringList::InitializeFromBuffer()
  90. {
  91.     LPCWSTR pNext;
  92.     int iLen;
  93.     if (!m_fValid)
  94.         return FALSE;
  95.     pNext = (LPCWSTR)m_pBuffer;
  96.     while (((LPSTR)pNext-m_pBuffer) < m_iBufSize)
  97.     {
  98.         iLen = lstrlenW(pNext);
  99.         InsertToHash(pNext, iLen, FALSE);
  100.         pNext += iLen+1;
  101.     }
  102.     m_iBufEnd = (int)((LPSTR)pNext - m_pBuffer);
  103.     return TRUE;
  104. }
  105. //
  106. // IPersistStream members
  107. //
  108. // We save
  109. // DWORD containing total length in bytes that follows. Will be
  110. //  multiple of four; may have 0-4 extra pad bytes on the end.
  111. // String data.
  112. //
  113. // Smallest data we store is 4 bytes of zeroes. We still end up taking
  114. //  memory when we get restored. Don't instantiate one of these objects
  115. //  until you're going to use it.
  116. STDMETHODIMP CWCStringList::IsDirty(void)
  117. {
  118.     DBG("CWCStringList::IsDirty returning S_OK (true) as always");
  119.     return S_OK;
  120. }
  121. STDMETHODIMP CWCStringList::Load(IStream *pStm)
  122. {
  123.     HRESULT hr;
  124.     ULONG   cbRead;
  125.     DWORD   dwDataSize;
  126.     DBG("CWCStringList::Load");
  127.     if (NULL==pStm)
  128.         return E_POINTER;
  129.     // Clean up our object
  130.     Reset();
  131.     // Load our data
  132.     hr = pStm->Read(&dwDataSize, sizeof(DWORD), &cbRead);
  133.     if (FAILED(hr) || cbRead != sizeof(DWORD))
  134.         return STG_E_READFAULT;
  135.     if (0 == dwDataSize)
  136.     {
  137.         if (!Init(512))     // Start with small buffer since we're empty
  138.             return E_OUTOFMEMORY;
  139.         return S_OK;
  140.     }
  141.     if (!Init(dwDataSize))
  142.         return E_OUTOFMEMORY;
  143.     ASSERT(dwDataSize <= (DWORD)m_iBufSize);
  144.     // Read in the string data
  145.     hr = pStm->Read(m_pBuffer, dwDataSize, &cbRead);
  146.     if (FAILED(hr) || cbRead != dwDataSize)
  147.         return STG_E_READFAULT;
  148.     // Set up hash tables etc.
  149.     InitializeFromBuffer();
  150.     DBG("CWCStringList::Load success");
  151.     return NOERROR;
  152. }
  153. STDMETHODIMP CWCStringList::Save(IStream *pStm, BOOL fClearDirty)
  154. {
  155.     HRESULT hr;
  156.     ULONG   cbWritten;
  157.     DWORD   dwDataSize, dwZero=0;
  158.     DWORD   dwZeroPad;
  159.     DBG("CWCStringList::Save");
  160.     if (NULL==pStm)
  161.         return E_POINTER;
  162.     // First write our data
  163.     dwDataSize = (m_iBufEnd+3) & 0xFFFFFFFC; // multiple of four
  164.     if ((0 == m_iBufSize) || (0 == m_iNumStrings))
  165.     {
  166.         dwDataSize = 0;
  167.     }
  168.     hr = pStm->Write(&dwDataSize, sizeof(DWORD), &cbWritten);
  169.     if (FAILED(hr) || sizeof(DWORD) != cbWritten)
  170.         return STG_E_WRITEFAULT;
  171.     if (dwDataSize > 0)
  172.     {
  173.         hr = pStm->Write(m_pBuffer, m_iBufSize, &cbWritten);
  174.         if (FAILED(hr) || sizeof(DWORD) != cbWritten)
  175.             return STG_E_WRITEFAULT;
  176.         dwZeroPad = dwDataSize - m_iBufSize;
  177.         ASSERT(dwZeroPad<4);
  178.         if (dwZeroPad && dwZeroPad<4)
  179.         {
  180.             hr = pStm->Write(&dwZero, dwZeroPad, &cbWritten);
  181.             if (FAILED(hr) || (dwZeroPad != cbWritten))
  182.                 return STG_E_WRITEFAULT;
  183.         }
  184.     }
  185.     DBG("CWCStringList::Save success");
  186.     return NOERROR;
  187. }
  188. STDMETHODIMP CWCStringList::GetSizeMax(ULARGE_INTEGER *pcbSize)
  189. {
  190.     DBG("CWCStringList::GetSizeMax");
  191.     if (NULL==pcbSize)
  192.         return E_POINTER;
  193.     pcbSize->LowPart = 0;
  194.     pcbSize->HighPart = 0;
  195.     pcbSize->LowPart = m_iBufEnd + 8;
  196.     return NOERROR;
  197. }
  198. // Returns a BSTR
  199. BSTR CWCStringList::GetBSTR(int iNum)
  200. {
  201.     LPCWSTR lpStr = GetString(iNum);
  202.     return SysAllocStringLen(lpStr, GetStringLen(iNum));
  203. }
  204. // Returns FALSE if string is not found
  205. // Places string index (for GetString()) in *piNum only if string is found.
  206. BOOL CWCStringList::FindString(LPCWSTR lpwstr, int iLen, int *piNum/*=NULL*/)
  207. {
  208.     int             iHash;
  209.     LPSTRING_INDEX  psi;
  210.     if (!lpwstr)
  211.         return FALSE;
  212.     if (iLen < 0)
  213.         iLen = lstrlenW(lpwstr);
  214.     iHash = Hash(lpwstr, iLen);
  215.     for (psi = m_Hash[iHash]; psi; psi = psi->psiNext)
  216.     {
  217.         if ((psi->iLen == iLen) && memcmp(psi->lpwstr, lpwstr, iLen * sizeof(WCHAR)) == 0)
  218.         {
  219.             if (piNum)
  220.                 *piNum = (int) (psi-m_psiStrings);
  221.             return TRUE;        // String is a duplicate
  222.         }
  223.     }
  224.     return FALSE;
  225. }
  226. // returns STRLST_FAIL on failure,
  227. //         STRLST_DUPLICATE if the string already existed, and
  228. //         STRLST_ADDED if it's new
  229. int CWCStringList::AddString(LPCWSTR lpwstr, DWORD_PTR dwData /*=NULL*/, int *piNum /*=NULL*/)
  230. {
  231.     int iSize, iLen;
  232.     if (!lpwstr)
  233.         return STRLST_FAIL;
  234.     iLen = lstrlenW(lpwstr);
  235.     if (!m_fValid || !m_pBuffer)
  236.     {
  237.         DBG_WARN("WCStringList: AddString() called with invalid instance");
  238.         return STRLST_FAIL;
  239.     }
  240.     if (dwData != 0)
  241.         DBG_WARN("Value for dwData passed into CWCStringList::AddString");
  242.     if (FindString(lpwstr, iLen, piNum))
  243.         return STRLST_DUPLICATE;        // String is a duplicate
  244.     // iSize will be size in bytes including null term
  245.     iSize = (iLen+1)*sizeof(WCHAR);
  246.     // Append string to current buffer
  247.     if (iSize >= (m_iBufSize - m_iBufEnd))
  248.     {
  249.         int iOldBufSize = m_iBufSize;
  250.         // Grow buffer.
  251.         m_iBufSize *= 2;     // This way the number of reallocs drops off logarithmically
  252.         if (m_iBufEnd + iSize > m_iBufSize)
  253.         {
  254.             DBG("StringList special growing size");
  255.             m_iBufSize = m_iBufEnd + iSize;
  256.         }
  257.         TraceMsg(TF_THISMODULE,"StringList growing to size %d",m_iBufSize);
  258.         LPSTR pBuf = (LPSTR)MemReAlloc((HLOCAL)m_pBuffer, m_iBufSize, LMEM_MOVEABLE);
  259.         if (!pBuf)
  260.         {
  261.             m_iBufSize = iOldBufSize;
  262.             DBG_WARN("WCStringList: ReAlloc() failure");
  263.             // Realloc failure: our old memory is still present
  264.             return 0;
  265.         }
  266.         // Let's be clever and fix all our pointers instead of getting faults
  267.         if (m_pBuffer != pBuf)
  268.         {
  269.             int i;
  270.             LPSTRING_INDEX psi;
  271.             for (i=0, psi=&m_psiStrings[0]; i<m_iNumStrings; i++, psi++)
  272.             {
  273.                 psi->lpwstr = (LPWSTR)(((LPSTR)psi->lpwstr - m_pBuffer) + pBuf);
  274.             }
  275.             m_pBuffer = pBuf;
  276.         }
  277.     }
  278.     if (piNum)
  279.         *piNum = m_iNumStrings;
  280.     LPWSTR pBufEnd = (LPWSTR)(m_pBuffer + m_iBufEnd);
  281.     StrCpyW(pBufEnd, lpwstr);
  282.     if (!InsertToHash(pBufEnd, iLen, TRUE))
  283.         return 0;
  284.     m_iBufEnd += iSize;
  285.     return STRLST_ADDED;           // indicate we added a new string
  286. }
  287. BOOL CWCStringList::InsertToHash(LPCWSTR lpwstr, int iLen, BOOL fAlreadyHashed)
  288. {
  289.     int iHash = fAlreadyHashed ? m_iLastHash : Hash(lpwstr, iLen);
  290.     // grow psiStrings if needed
  291.     ASSERT(m_iNumStrings <= m_iMaxStrings);
  292.     if (m_iNumStrings >= m_iMaxStrings)
  293.     {
  294.         m_iMaxStrings *= 2;
  295.         TraceMsg(TF_THISMODULE, "StringList growing max strings to %d", m_iMaxStrings);
  296.         LPSTRING_INDEX psiBuf = (LPSTRING_INDEX)MemReAlloc((HLOCAL)m_psiStrings,
  297.             m_iMaxStrings * sizeof(STRING_INDEX), LMEM_MOVEABLE);
  298.         if (!psiBuf)
  299.         {
  300.             // Realloc failure: Old memory still present
  301.             DBG_WARN("WCStringList::InsertToHash() ReAlloc failure");
  302.             m_iMaxStrings /= 2;
  303.             return FALSE;
  304.         }
  305.         // More cleverness
  306.         if (m_psiStrings != psiBuf)
  307.         {
  308.             int i;
  309.             LPSTRING_INDEX psi, *ppsi;
  310.             for (i=0, psi=psiBuf; i<m_iNumStrings; i++, psi++)
  311.             {
  312.                 if (psi->psiNext)
  313.                     psi->psiNext = (psi->psiNext - m_psiStrings) + psiBuf;
  314.             }
  315.             for (i=0, ppsi=m_Hash; i<STRING_HASH_SIZE; i++, ppsi++)
  316.             {
  317.                 if (*ppsi)
  318.                     *ppsi = (*ppsi - m_psiStrings) + psiBuf;
  319.             }
  320.             m_psiStrings = psiBuf;
  321.         }
  322.     }
  323.     m_psiStrings[m_iNumStrings].lpwstr  = lpwstr;
  324.     m_psiStrings[m_iNumStrings].iLen    = iLen;
  325.     m_psiStrings[m_iNumStrings].psiNext = m_Hash[iHash];
  326.     m_Hash[iHash] = &m_psiStrings[m_iNumStrings];
  327.     m_iNumStrings++;
  328.     return TRUE;
  329. }
  330. #ifdef DEBUG
  331. // WARNING: this clobbers the hash
  332. void CWCStringList::SpewHashStats(BOOL fVerbose)
  333. {
  334. /*
  335.     int i;
  336.     for (i = 0; i < STRING_HASH_SIZE; ++i)
  337.     {
  338.         int c = 0;
  339.         for (tagStringIndex *p = m_Hash[i]; p; p = p->psiNext)
  340.             ++c;
  341.         if (c)
  342.             TraceMsg(TF_THISMODULE,"%10d%12d", i, c);
  343.     }
  344. */
  345.  
  346.     TraceMsg(TF_THISMODULE,"### Hash size: %d       Num. entries:%7d", STRING_HASH_SIZE, m_iNumStrings);
  347.     int i,n;
  348.     if (fVerbose)
  349.     {
  350.         TraceMsg(TF_THISMODULE," # of entries    # of keys with that many");
  351.         for (i=0,n=0; n<STRING_HASH_SIZE; i++)
  352.         {
  353.             int k=0;
  354.             for (int j=0; j<STRING_HASH_SIZE; j++)
  355.             {
  356.                 int c=0;
  357.                 for (tagStringIndex* p=m_Hash[j]; p; p=p->psiNext)
  358.                     c++;
  359.                 if (c == i)
  360.                     k++;
  361.             }
  362.             if (k)
  363.             {
  364.                 TraceMsg(TF_THISMODULE,"%10d%12d", i, k);
  365.                 n += k;
  366.             }
  367.         }
  368.     }
  369. /*
  370.     int total=0;
  371.     if (fVerbose)
  372.     {
  373.         TraceMsg(TF_THISMODULE," length   # of strings with that length",1);
  374.         for (i=0,n=0; n<m_iNumStrings; i++)
  375.         {
  376.             int k=0;
  377.             for (int j=0; j<m_iNumStrings; j++)
  378.             {
  379.                 if (m_psiStrings[j].iLen == i)
  380.                     k++;
  381.             }
  382.             if (k)
  383.             {
  384.                 if (fVerbose)
  385.                     TraceMsg(TF_THISMODULE,"%5d%10d", i, k);
  386.                 n += k;
  387.                 total += k*(k+1)/2;
  388.             }
  389.         }
  390.     }
  391.     TraceMsg(TF_THISMODULE,"### Average compares without hash * 100:%5d", total*100/m_iNumStrings);
  392.     total=0;
  393.     for (i=0; i<STRING_HASH_SIZE; i++)
  394.     {
  395.         for (tagStringIndex* p=m_Hash[i]; p; p=p->psiNext)
  396.         {
  397.             if (p->iLen < 0) continue;
  398.             int n=1;
  399.             for (tagStringIndex* q=p->psiNext; q; q=q->psiNext)
  400.             {
  401.                 if (p->iLen == q->iLen)
  402.                 {
  403.                     n++;
  404.                     q->iLen = -1;
  405.                 }
  406.             }
  407.             total += n*(n+1)/2;
  408.         }
  409.     }
  410.     TraceMsg(TF_THISMODULE,"### Average compares with hash * 100:%8d", total*100/m_iNumStrings);
  411. */
  412. }
  413. #endif
  414. //----------------------------------------------------------------------------
  415. // CWCDwordStringList
  416. CWCDwordStringList::CWCDwordStringList() : CWCStringList()
  417. {
  418. }
  419. CWCDwordStringList::~CWCDwordStringList()
  420. {
  421.     if (m_pData)
  422.         MemFree((HLOCAL)m_pData);
  423. }
  424. BOOL CWCDwordStringList::Init(int iInitBufSize/*=-1*/)
  425. {
  426.     if (!CWCStringList::Init(iInitBufSize))
  427.         return FALSE;
  428.     m_pData = (DWORD_PTR*)MemAlloc(LMEM_FIXED, m_iMaxStrings * sizeof(DWORD));
  429.     if (NULL == m_pData)
  430.         return FALSE;
  431.     return TRUE;
  432. }
  433. int CWCDwordStringList::AddString(LPCWSTR psz, DWORD_PTR dwData/*=0*/, int* piNum/*=NULL*/)
  434. {
  435.     int iOldMaxStrings = m_iMaxStrings;     // track changes in m_iMaxStrings by this call:
  436.     int iNum;
  437.     int iResult = CWCStringList::AddString(psz, 0, &iNum);
  438.     if (iResult == 0)
  439.         return 0;
  440.     if (iOldMaxStrings != m_iMaxStrings)    // make sure we have enough data space
  441.     {
  442.         DWORD_PTR *pData;
  443. //      TraceMsg(TF_THISMODULE, "DwordStringList expanding dwords to %d", m_iMaxStrings);
  444.         pData = (DWORD_PTR*)MemReAlloc((HLOCAL)m_pData, m_iMaxStrings * sizeof(DWORD),
  445.             LMEM_MOVEABLE);
  446.         ASSERT(pData);
  447.         if (!pData)
  448.         {
  449.             DBG_WARN("Realloc failure in DwordStringList");
  450.             MemFree(m_pData);
  451.             m_pData = NULL;         // This is bad
  452.             return 0;
  453.         }
  454.         m_pData = pData;
  455.     }
  456.     if (iResult == 2)       // only set data value if this is a new string
  457.     {
  458.         m_pData[iNum] = dwData;
  459.     }
  460.     if (piNum)
  461.         *piNum = iNum;
  462.     return iResult;
  463. }