windows-nt/Source/XPSP1/NT/base/win32/fusion/utils/stringpool.cpp
2020-09-26 16:20:57 +08:00

475 lines
11 KiB
C++

#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<CStringPoolHeapSegment, FIELD_OFFSET(CStringPoolHeapSegment, m_leLinks)> 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<m_cEntriesUsed; i++)
{
if (m_prgEntries[i].PseudoKey == ulPseudoKey)
{
if (m_prgEntries[i].Length == BytesIn)
{
if (memcmp(StringIn, m_prgEntries[i].Buffer, BytesIn) == 0)
break;
}
}
}
if (i != m_cEntriesUsed)
{
// If we bailed out of the loop early, we must have found it.
disposition = CStringPoolEntryClump::eFound;
rulPosition = i;
rpEntry = &m_prgEntries[i];
}
else
{
// It's not already there; is there space for it?
if (m_cEntriesUsed != m_cEntriesAllocated)
{
IFW32FALSE_EXIT(m_prgEntries[m_cEntriesUsed].Initialize(StringIn, CchIn, ulPseudoKey, rStringHeap));
disposition = CStringPoolEntryClump::eAdded;
rpEntry = &m_prgEntries[m_cEntriesUsed];
rulPosition = m_cEntriesUsed++;
}
else
{
// Nope, keep going...
disposition = CStringPoolEntryClump::eNoRoom;
}
}
rdisposition = disposition;
fSuccess = TRUE;
Exit:
return fSuccess;
}
BOOL
CStringPoolEntryClump::FillInStringArray(
ULONG nArraySize,
SXS_XML_STRING *prgStrings,
ULONG iCurrent,
ULONG &rcWritten
)
{
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
ULONG i;
rcWritten = 0;
PARAMETER_CHECK(iCurrent < nArraySize);
PARAMETER_CHECK((iCurrent + m_cEntriesUsed) <= nArraySize);
for (i=0; i<m_cEntriesUsed; i++)
prgStrings[iCurrent++] = m_prgEntries[i];
rcWritten = m_cEntriesUsed;
fSuccess = TRUE;
Exit:
return fSuccess;
}
CStringPool::~CStringPool()
{
m_dequeEntryClumps.Clear<CStringPool>(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<CStringPoolEntryClump, FIELD_OFFSET(CStringPoolEntryClump, m_leEntryChain)> 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<CStringPoolEntryClump, FIELD_OFFSET(CStringPoolEntryClump, m_leEntryChain)> 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;
}