#include "stdinc.h" #include "stringpool.h" #include "debmacro.h" #include "fusiontrace.h" // // Implementation of the CStringPoolHeapSegment class: // BOOL CStringPoolHeapSegment::Initialize() { // Nothing to do today but a good placeholder return TRUE; } BOOL CStringPoolHeapSegment::Initialize( const WCHAR *StringIn, ULONG Cch, const WCHAR *&rpStringOut ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); // You shouldn't have gotten here if this was a "big" allocation INTERNAL_ERROR_CHECK(Cch < NUMBER_OF(m_rgchBuffer)); INTERNAL_ERROR_CHECK(m_cchUsed == 0); memcpy(m_rgchBuffer, StringIn, Cch * sizeof(WCHAR)); m_cchUsed = Cch; rpStringOut = m_rgchBuffer; fSuccess = TRUE; Exit: return fSuccess; } BOOL CStringPoolHeapSegment::TryAllocString( const WCHAR *StringIn, ULONG Cch, const WCHAR *&rpStringOut ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); // You shouldn't have gotten here if this was a "big" allocation INTERNAL_ERROR_CHECK(Cch < NUMBER_OF(m_rgchBuffer)); rpStringOut = NULL; if ((NUMBER_OF(m_rgchBuffer) - m_cchUsed) >= Cch) { WCHAR *pwch = &m_rgchBuffer[m_cchUsed]; memcpy(pwch, StringIn, Cch * sizeof(WCHAR)); rpStringOut = pwch; m_cchUsed += Cch; } fSuccess = TRUE; Exit: return fSuccess; } // // Implementation of the CStringPoolSingletonString class: // BOOL CStringPoolSingletonString::Initialize( const WCHAR *StringIn, ULONG Cch, const WCHAR *&rpStringOut ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); WCHAR *prgwch = NULL; INTERNAL_ERROR_CHECK(m_prgwch == NULL); if (Cch != 0) { prgwch = FUSION_NEW_ARRAY(WCHAR, Cch); memcpy(prgwch, StringIn, Cch * sizeof(WCHAR)); m_prgwch = prgwch; } rpStringOut = prgwch; prgwch = NULL; fSuccess = TRUE; Exit: if (prgwch != NULL) FUSION_DELETE_ARRAY(prgwch); return fSuccess; } // // Implementation of the CStringPoolHeap class: // BOOL CStringPoolHeap::Initialize() { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); fSuccess = TRUE; // Exit: return fSuccess; } BOOL CStringPoolHeap::DupString( const WCHAR *StringIn, ULONG Cch, const WCHAR *&rpStringOut ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); CStringPoolSingletonString *pSingleton = NULL; CStringPoolHeapSegment *pSegment = NULL; rpStringOut = NULL; if (Cch > CStringPoolHeapSegment::CchMax()) { // It's too big to ever fit into a segment. Just allocate a singleton for it. IFALLOCFAILED_EXIT(pSingleton = new CStringPoolSingletonString); IFW32FALSE_EXIT(pSingleton->Initialize(StringIn, Cch, rpStringOut)); m_dequeSingletons.AddToTail(pSingleton); pSingleton = NULL; } else { CDequeIterator iter(&m_dequeSegments); for (iter.Reset(); iter.More(); iter.Next()) { IFW32FALSE_EXIT(iter->TryAllocString(StringIn, Cch, rpStringOut)); if (rpStringOut != NULL) break; } if (rpStringOut == NULL) { // I guess we need a new heap segment... IFALLOCFAILED_EXIT(pSegment = new CStringPoolHeapSegment); IFW32FALSE_EXIT(pSegment->Initialize(StringIn, Cch, rpStringOut)); INTERNAL_ERROR_CHECK(rpStringOut != NULL); m_dequeSegments.AddToHead(pSegment); pSegment = NULL; } } fSuccess = TRUE; Exit: if (pSingleton != NULL) FUSION_DELETE_SINGLETON(pSingleton); if (pSegment != NULL) FUSION_DELETE_SINGLETON(pSegment); return fSuccess; } // // Implementation of the CStringPoolEntry class: // BOOL CStringPoolEntry::Initialize( const WCHAR *StringIn, ULONG CchIn, ULONG ulPseudoKey, CStringPoolHeap &rStringHeap ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); // Catch double initializations; a zero PseudoKey is pretty unlikely and we'll just miss the error in that // one case. INTERNAL_ERROR_CHECK(this->PseudoKey == 0); IFW32FALSE_EXIT(rStringHeap.DupString(StringIn, CchIn, this->Buffer)); this->PseudoKey = ulPseudoKey; this->Length = CchIn * sizeof(WCHAR); fSuccess = TRUE; Exit: return fSuccess; } // // Implementation of the CStringPoolEntryClump class: // CStringPoolEntryClump::~CStringPoolEntryClump() { if (m_prgEntries != NULL) FUSION_DELETE_ARRAY(m_prgEntries); m_prgEntries = NULL; m_cEntriesAllocated = 0; m_cEntriesUsed = 0; } BOOL CStringPoolEntryClump::Initialize( ULONG cStringsToAllocate ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); CStringPoolEntry *prgEntries = NULL; ASSERT(cStringsToAllocate != 0); PARAMETER_CHECK(cStringsToAllocate != 0); IFALLOCFAILED_EXIT(prgEntries = FUSION_NEW_ARRAY(CStringPoolEntry, cStringsToAllocate)); m_prgEntries = prgEntries; prgEntries = NULL; m_cEntriesAllocated = cStringsToAllocate; m_cEntriesUsed = 0; fSuccess = TRUE; Exit: if (prgEntries != NULL) FUSION_DELETE_ARRAY(prgEntries); return fSuccess; } BOOL CStringPoolEntryClump::FindOrAddEntry( const WCHAR *StringIn, ULONG CchIn, ULONG ulPseudoKey, CStringPoolHeap &rStringHeap, ULONG &rulPosition, CStringPoolEntryClump::FindOrAddDisposition &rdisposition, const CStringPoolEntry *&rpEntry ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); ULONG i; FindOrAddDisposition disposition = CStringPoolEntryClump::eInvalid; const ULONG BytesIn = CchIn * sizeof(WCHAR); rdisposition = CStringPoolEntryClump::eInvalid; rpEntry = NULL; for (i=0; i(this, CStringPool::ClearDequeEntry); } BOOL CStringPool::Initialize() { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); INTERNAL_ERROR_CHECK(!m_fInitialized); IFW32FALSE_EXIT(m_StringHeap.Initialize()); m_fInitialized = true; m_cEntries = 0; fSuccess = TRUE; Exit: return fSuccess; } BOOL CStringPool::Canonicalize( const WCHAR *StringIn, ULONG CchIn, ULONG ulPseudoKey, ULONG &rulPosition, const WCHAR *&rStringOut ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); ULONG ulPosition = 1; CDequeIterator iter; CStringPoolEntryClump::FindOrAddDisposition disposition = CStringPoolEntryClump::eNoRoom; CStringPoolEntryClump *pNewClump = NULL; const CStringPoolEntry *pEntry = NULL; rulPosition = 0; rStringOut = NULL; iter.Rebind(&m_dequeEntryClumps); for (iter.Reset(); iter.More(); iter.Next()) { ULONG i; IFW32FALSE_EXIT(iter->FindOrAddEntry(StringIn, CchIn, ulPseudoKey, m_StringHeap, i, disposition, pEntry)); if ((disposition == CStringPoolEntryClump::eFound) || (disposition == CStringPoolEntryClump::eAdded)) { if (disposition == CStringPoolEntryClump::eAdded) m_cEntries++; ulPosition += i; break; } else { // No room is equivalent to not found... ASSERT(disposition == CStringPoolEntryClump::eNoRoom); ulPosition += iter->EntriesUsed(); disposition = CStringPoolEntryClump::eNoRoom; } } // If we get here with disposition == eNoRoom, we neither found it nor had room in an existing clump, so we need // to allocate a new clump... if (disposition == CStringPoolEntryClump::eNoRoom) { ULONG i; IFALLOCFAILED_EXIT(pNewClump = new CStringPoolEntryClump); IFW32FALSE_EXIT(pNewClump->Initialize()); IFW32FALSE_EXIT(pNewClump->FindOrAddEntry(StringIn, CchIn, ulPseudoKey, m_StringHeap, i, disposition, pEntry)); m_dequeEntryClumps.AddToTail(pNewClump); pNewClump = NULL; ASSERT(disposition == CStringPoolEntryClump::eAdded); ASSERT(i == 0); m_cEntries++; } INTERNAL_ERROR_CHECK(pEntry != NULL); rulPosition = ulPosition; rStringOut = pEntry->Buffer; fSuccess = TRUE; Exit: if (pNewClump != NULL) FUSION_DELETE_SINGLETON(pNewClump); return fSuccess; } BOOL CStringPool::FillInStringArray( ULONG nArraySize, SXS_XML_STRING *prgStrings, ULONG &rcWritten ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); ULONG i; CDequeIterator iter; if (nArraySize < (m_cEntries + 1)) { ::SetLastError(ERROR_INSUFFICIENT_BUFFER); goto Exit; } iter.Rebind(&m_dequeEntryClumps); // We start filling in at index 1, not zero. We'll manually set zero to be invalid. prgStrings[0].Flags = SXS_XML_STRING_FLAG_INVALID; prgStrings[0].PseudoKey = 0; prgStrings[0].Length = 0; prgStrings[0].Buffer = NULL; i = 1; for (iter.Reset(); iter.More(); iter.Next()) { ULONG cWrittenThisClump = 0; IFW32FALSE_EXIT(iter->FillInStringArray(nArraySize, prgStrings, i, cWrittenThisClump)); INTERNAL_ERROR_CHECK((i + cWrittenThisClump) <= nArraySize); i += cWrittenThisClump; } rcWritten = i; fSuccess = TRUE; Exit: return fSuccess; }