// TitleC.cpp -- Implementation for class CTitleCollection #include "StdAfx.h" #include "TextSet.h" #include "Tokens.h" #include "TitleC.h" #include "Memex.h" CTitleCollection *CTitleCollection::NewTitleCollection(CTextSet **papts, UINT ctsSlots, CPersist *pPersistRelations) { CTitleCollection *ptc= NULL; __try { ptc= New CTitleCollection(); ptc->AttachParameters(papts, ctsSlots, pPersistRelations); } __finally { if (_abnormal_termination() && ptc) { delete ptc; ptc= NULL; } } return ptc; } CTitleCollection::CTitleCollection() : #ifdef _DEBUG CTokenList(FALSE, "TitleCollection") #else // _DEBUG CTokenList(FALSE) #endif // _DEBUG { m_ctsSlots = 0; m_cTitles = 0; m_patsi = NULL; m_paiTitleStart = NULL; m_pati = NULL; m_paptiSorted = NULL; m_paiCategoryMaps = NULL; m_pisActiveTitles = NULL; m_fFromFile = FALSE; } CTitleCollection::~CTitleCollection() { if (m_pati ) VFree(m_pati ); if (m_paptiSorted ) VFree(m_paptiSorted ); if (m_paiTitleStart ) VFree(m_paiTitleStart ); if (m_paiCategoryMaps) VFree(m_paiCategoryMaps); if (m_pisActiveTitles) DetachRef(m_pisActiveTitles); if (m_patsi) { UINT c= m_ctsSlots; for (; c--; ) if (m_patsi[c].pts) DetachRef(m_patsi[c].pts); VFree(m_patsi); } } void CTitleCollection::AttachParameters(CTextSet **papts, UINT ctsSlots, CPersist *pPersistRelations) { m_fFromFile= BOOL(pPersistRelations); m_patsi= (PTextSetInfo) VAlloc(TRUE, ctsSlots * sizeof(TextSetInfo)); m_ctsSlots = ctsSlots; UINT c; for (c= ctsSlots; c--; ) { CTextSet *pts= papts[c]; if (!pts) continue; InstallTextSet(c, pts); } if (m_fFromFile) ReconstructRelations(pPersistRelations); InvalidateRepresentatives(pPersistRelations); } typedef struct _TitleRelationHeader { UINT ctsSlots; UINT cTitles; } TitleRelationHeader, *PTitleRelationHeader; void CTitleCollection::ReconstructRelations(CPersist *pPersistRelations) { CTokenList::ConnectImage2(pPersistRelations, TRUE); // We set the PREVIOUSLY_PRESENT flag for every text set we encounter. // That's necessary to skip the call to ReconstructCollection in InvalidateRepresentatives. // For similar reasons we also set the PREVIOUSLY_ACTIVE flag. UINT c= m_ctsSlots; for (; c--; ) { if (IsPresent(c)) m_patsi[c].fFlags |= PREVIOUSLY_PRESENT; if (IsActive (c)) m_patsi[c].fFlags |= PREVIOUSLY_ACTIVE; } ASSERT(!m_pisActiveTitles); AttachRef(m_pisActiveTitles, CIndicatorSet::NewIndicatorSet(m_cd, TRUE)); BuildTitleStarts(); PTitleRelationHeader ptrh= PTitleRelationHeader(pPersistRelations->ReserveTableSpace(sizeof(TitleRelationHeader))); ASSERT(m_ctsSlots == ptrh->ctsSlots && m_cTitles == ptrh->cTitles); m_paiCategoryMaps = PUINT(VAlloc(FALSE, m_cTitles * sizeof(UINT))); PDESCRIPTOR *ppd; for (c= m_cd, ppd= m_ppdSorted + m_cd; c--; ) m_paiCategoryMaps[*--ppd - m_pd] = c; m_pati= (PTitleInfo) VAlloc(TRUE, m_cTitles * sizeof(TitleInfo)); PTitleInfo pti = m_pati + m_cTitles; PTextSetInfo ptsi; for (ptsi= m_patsi + m_ctsSlots, c= m_ctsSlots; c--; ) { if (!(PRESENT & (--ptsi)->fFlags)) continue; CTextSet *pts = ptsi->pts; CTokenList *ptl = pts->TitleList(); UINT cd = pts->TopicCount(); for (; cd--; ) { (--pti)->iaTSSlot = c; pti ->iPartition = cd; } } } void CTitleCollection::BuildTitleStarts() { m_paiTitleStart= PUINT(VAlloc(FALSE, (m_ctsSlots + 1) * sizeof(UINT))); PUINT piStart = m_paiTitleStart; PTextSetInfo ptsi = m_patsi; UINT c = m_ctsSlots; for (m_cTitles= 0, *piStart++= 0; c--; ptsi++) { if (ptsi->fFlags & PRESENT) m_cTitles += ptsi->cd; *piStart++= m_cTitles; } } void CTitleCollection::ConstructCollection() { BuildTitleStarts(); m_pati= (PTitleInfo) VAlloc(TRUE, m_cTitles * sizeof(TitleInfo)); m_paptiSorted= (PTitleInfo *) VAlloc(FALSE, m_cTitles * sizeof(PTitleInfo)); PTitleInfo pti = m_pati + m_cTitles; PTitleInfo *ppti = m_paptiSorted + m_cTitles; m_lcidSorting = LCID(-1); // an invalid LCID value BOOL fLCID_Initialed = FALSE; PTextSetInfo ptsi; UINT c; for (ptsi= m_patsi + m_ctsSlots, c= m_ctsSlots; c--; ) { if (!(PRESENT & (--ptsi)->fFlags)) continue; CTextSet *pts= ptsi->pts; if (fLCID_Initialed) { if (m_lcidSorting != pts->SortingLCID()) m_lcidSorting = LCID(-1); } else { m_lcidSorting = pts->SortingLCID(); fLCID_Initialed = TRUE; } pts->SyncIndices(); CTokenList *ptl= pts->TitleList(); INT cbMaxTitle= ptl->MaxWidthToken(); if (cbMaxTitle > m_cbMaxLength) m_cbMaxLength= cbMaxTitle; UINT cd = ptl->m_cd; PDESCRIPTOR *ppd = ptl->m_ppdSorted + cd; PTitleInfo ptiBase = pti -= cd; PDESCRIPTOR pdBase = ptl->m_pd; for (; cd--; ) { PDESCRIPTOR pd = *--ppd; UINT iPartition = pd - pdBase; PTitleInfo ptiTarget = ptiBase + iPartition; ptiTarget->pd= pd; ptiTarget->iaTSSlot = c; ptiTarget->iPartition = iPartition; *--ppti= ptiTarget; } } CombineTitleLists(m_paptiSorted, m_paiTitleStart, m_ctsSlots, &ppti, &c); ASSERT(c == m_cTitles); if (m_ctsSlots > 1) { VFree(m_paptiSorted); m_paptiSorted= ppti; } if (m_paiCategoryMaps) { VFree(m_paiCategoryMaps); m_paiCategoryMaps= NULL; } } BOOL CTitleCollection::InvalidateRepresentatives(CPersist *pPersistRelations) { UINT fChanges = 0; UINT c; for (c= m_ctsSlots; c--; ) { UINT fFlags= m_patsi[c].fFlags; ASSERT((fFlags & (PRESENT | ACTIVE)) != ACTIVE); fChanges |= (fFlags & CURRENT_STATE) ^ ((fFlags & PREVIOUS_STATE) >> TIME_SHIFT); } if (!fChanges) return TRUE; if (fChanges & PRESENT) ReconstructCollection(); if (fChanges & ACTIVE || !m_paiCategoryMaps) ReconstructRepresentatives(); PTextSetInfo ptsi= m_patsi; for (c= m_ctsSlots; c--; ++ptsi) { UINT fOptions= ptsi->fFlags & (PRESENT | ACTIVE); ptsi->fFlags &= ~(PRESENT | ACTIVE | PREVIOUSLY_PRESENT | PREVIOUSLY_ACTIVE); ptsi->fFlags |= fOptions | (fOptions << TIME_SHIFT); } return TRUE; } void CTitleCollection::ReconstructCollection() { if (!m_pati) { ConstructCollection(); return; } ASSERT(FALSE); // Collection Change to be completed... } void CTitleCollection::ConstructRepresentatives() { ASSERT(!m_paiCategoryMaps); UINT c = m_ctsSlots; PTextSetInfo ptsi = m_patsi; PTitleInfo *ppti; UINT cwcDisplayImages = 0; UINT cwcSortKeyImages = 0; for (c= m_cTitles, ppti= m_paptiSorted; c--; ) { PDESCRIPTOR pd = (*ppti++)->pd; cwcDisplayImages += CwDisplay(pd); cwcSortKeyImages += CbImage (pd); } PWCHAR pwcDisplayImages = NULL; PWCHAR pwcSortKeyImages = NULL; PDESCRIPTOR pdTitles = NULL; PDESCRIPTOR *ppdSortedTitles = NULL; __try { ValidateHeap(); pdTitles = PDESCRIPTOR (VAlloc(FALSE, (m_cTitles+1) * sizeof(DESCRIPTOR ))); ppdSortedTitles = (PDESCRIPTOR *) VAlloc(FALSE, m_cTitles * sizeof(PDESCRIPTOR)); pwcDisplayImages = PWCHAR(VAlloc(FALSE, cwcDisplayImages * sizeof(WCHAR))); pwcSortKeyImages = PWCHAR(VAlloc(FALSE, cwcSortKeyImages * sizeof(WCHAR))); ValidateHeap(); PWCHAR pwcDisplay = pwcDisplayImages; PWCHAR pwcSortKey = pwcSortKeyImages; PDESCRIPTOR pd; PDESCRIPTOR *ppd; PTitleInfo pti; for (c= m_cTitles, pti= m_pati, pd= pdTitles; c--; pti++, pd++) { PDESCRIPTOR pdTS = pti->pd; pti->pd = pd; *pd = *pdTS; UINT cwcDisplay = CwDisplay(pdTS); UINT cwcSortKey = CbImage (pdTS); pd->iTextSet = pti->iaTSSlot; pd->pwDisplay = pwcDisplay; pd->pbImage = pwcSortKey; CopyMemory(pwcDisplay, pdTS->pwDisplay, cwcDisplay * sizeof(WCHAR)); CopyMemory(pwcSortKey, pdTS->pbImage , cwcSortKey * sizeof(WCHAR)); pwcDisplay += cwcDisplay; pwcSortKey += cwcSortKey; } ValidateHeap(); pd->pwDisplay = pwcDisplay; // To set a limit on the length of the last display image. pd->pbImage = pwcSortKey; // To set a limit on the length of the last sort key. ValidateHeap(); m_paiCategoryMaps = (PUINT) VAlloc(FALSE, m_cTitles * sizeof(UINT)); #ifdef _DEBUG FillMemory(m_paiCategoryMaps, m_cTitles * sizeof(UINT), UCHAR(-1)); #endif // _DEBUG for (c= m_cTitles, ppd= ppdSortedTitles + m_cTitles, ppti= m_paptiSorted + m_cTitles; c--; ) { PDESCRIPTOR pd = (*--ppti)->pd; *--ppd = pd; m_paiCategoryMaps[pd - pdTitles] = c; } ValidateHeap(); } __finally { if (_abnormal_termination()) { if(pwcDisplayImages) { VFree(pwcDisplayImages); pwcDisplayImages = NULL; } if(pwcSortKeyImages) { VFree(pwcSortKeyImages); pwcSortKeyImages = NULL; } if(pdTitles ) { VFree(pdTitles ); pdTitles = NULL; } if(ppdSortedTitles ) { VFree(ppdSortedTitles ); ppdSortedTitles = NULL; } } } InitialTokenList(pwcDisplayImages, cwcDisplayImages, pdTitles, m_cTitles, m_lcidSorting, pwcSortKeyImages, cwcSortKeyImages, ppdSortedTitles, NULL ); NotifyViewers (ShapeChange); NotifyInterface(ShapeChange); } void CTitleCollection::ReconstructRepresentatives() { if (!m_paiCategoryMaps) ConstructRepresentatives(); ChangeRef(m_pisActiveTitles, CIndicatorSet::NewIndicatorSet(m_cd)); PDESCRIPTOR *ppd; UINT c; for (c= m_cd, ppd= m_ppdSorted + m_cd; c--; ) { if ((m_patsi[(*--ppd)->iTextSet].fFlags & ACTIVE)) m_pisActiveTitles->RawSetBit(c); } m_pisActiveTitles->InvalidateCache(); } #if 0 WORD auCredits[] = { 0x2d30, 0x4420, 0x7665, 0x6c65, 0x706f, 0x656d, 0x746e, 0x5420, 0x6165, 0x206d, 0x002d, 0x5231, 0x6e6f, 0x4d20, 0x7275, 0x6172, 0x0079, 0x5231, 0x646f, 0x656e, 0x2079, 0x6f4b, 0x6e72, 0x3100, 0x6952, 0x6863, 0x7261, 0x2064, 0x614b, 0x7a74, 0x3100, 0x6f4a, 0x6e68, 0x4820, 0x6c61, 0x006c, 0x4b31, 0x6972, 0x6873, 0x616e, 0x4e20, 0x7261, 0x6465, 0x7964, 0x3100, 0x6152, 0x706c, 0x2068, 0x6157, 0x646c, 0x6e65, 0x3100, 0x794c, 0x6e6e, 0x4220, 0x6f72, 0x6e77, 0x6c65, 0x006c, 0x4d31, 0x6369, 0x6168, 0x6c65, 0x4620, 0x202e, 0x2e43, 0x4320, 0x6972, 0x6b63, 0x3100, 0x0020, 0x0032, 0x2d30, 0x5520, 0x6573, 0x2072, 0x6e49, 0x6574, 0x6672, 0x6361, 0x2065, 0x6544, 0x6973, 0x6e67, 0x2d20, 0x3100, 0x6f52, 0x206e, 0x754d, 0x7272, 0x7961, 0x3100, 0x6f52, 0x6e64, 0x7965, 0x4b20, 0x726f, 0x006e, 0x4731, 0x7961, 0x656c, 0x5020, 0x6369, 0x656b, 0x006e, 0x4931, 0x6572, 0x656e, 0x5020, 0x7361, 0x6574, 0x6e72, 0x6361, 0x006b, 0x5431, 0x6d61, 0x2069, 0x6542, 0x7475, 0x6c65, 0x3100, 0x7553, 0x617a, 0x206e, 0x614d, 0x6172, 0x6873, 0x0069, 0x4b31, 0x6e65, 0x2074, 0x7553, 0x6c6c, 0x7669, 0x6e61, 0x3100, 0x6550, 0x7274, 0x2061, 0x6f48, 0x6666, 0x616d, 0x006e, 0x4a31, 0x6e61, 0x2065, 0x6144, 0x6c69, 0x7965, 0x3100, 0x0020, 0x0032, 0x2d30, 0x4720, 0x6f6c, 0x6162, 0x696c, 0x617a, 0x6974, 0x6e6f, 0x2d20, 0x3100, 0x6f52, 0x206e, 0x754d, 0x7272, 0x7961, 0x3100, 0x6952, 0x6863, 0x7261, 0x2064, 0x614b, 0x7a74, 0x3100, 0x7341, 0x756d, 0x2073, 0x7246, 0x7965, 0x6174, 0x0067, 0x2031, 0x6120, 0x616b, 0x4420, 0x2e72, 0x5520, 0x696e, 0x6f63, 0x6564, 0x3100, 0x6f4c, 0x6972, 0x4820, 0x656f, 0x7472, 0x0068, 0x4331, 0x7461, 0x6568, 0x6972, 0x656e, 0x5720, 0x7369, 0x6973, 0x6b6e, 0x3100, 0x2e4b, 0x4420, 0x202e, 0x6843, 0x6e61, 0x0067, 0x2031, 0x3200, 0x3000, 0x202d, 0x6554, 0x7473, 0x6e69, 0x2067, 0x002d, 0x5431, 0x6d69, 0x4c20, 0x7765, 0x7369, 0x3100, 0x6152, 0x646e, 0x6c61, 0x206c, 0x7453, 0x6d69, 0x7370, 0x6e6f, 0x3100, 0x0020, 0x0032, 0x2d30, 0x4220, 0x7275, 0x6165, 0x6375, 0x6172, 0x7963, 0x4320, 0x6e6f, 0x7274, 0x6c6f, 0x2d20, 0x3100, 0x614d, 0x6972, 0x6e6f, 0x4820, 0x676f, 0x6e61, 0x3100, 0x694e, 0x6f63, 0x656c, 0x4d20, 0x7469, 0x6b73, 0x676f, 0x3100, 0x6952, 0x6b63, 0x5320, 0x6765, 0x6c61, 0x3100, 0x6154, 0x6d6d, 0x2079, 0x7453, 0x6565, 0x656c, 0x3100, 0x0020, 0x0032, 0x2d30, 0x5320, 0x6570, 0x6963, 0x6c61, 0x5420, 0x6168, 0x6b6e, 0x2073, 0x002d, 0x4331, 0x7268, 0x7369, 0x4d20, 0x7275, 0x6172, 0x2079, 0x3100, 0x6c45, 0x7a69, 0x6261, 0x7465, 0x2068, 0x6f4b, 0x6e72, 0x3100, 0x694c, 0x206e, 0x7548, 0x6e61, 0x0067, 0x5331, 0x7269, 0x7369, 0x6168, 0x4420, 0x6e6f, 0x6974, 0x6572, 0x6464, 0x0079, 0x2031, 0x3200, 0x0000, 0x6e45, 0x2064, 0x666f, 0x6420, 0x7461, 0x0061, 0x0000 }; UINT cnCode = 0; UINT cbData = sizeof(auCredits); UINT offData = 0; #endif // 0 void CTitleCollection::RecordRelations(CPersist *pPersistDiskImage) { PUINT paiPermute= NULL; CTokenList::StoreImage2(pPersistDiskImage, TRUE); PTitleRelationHeader ptrh= (PTitleRelationHeader) (pPersistDiskImage->ReserveTableSpace(sizeof(TitleRelationHeader))); ptrh->ctsSlots = m_ctsSlots; ptrh->cTitles = m_cTitles; #if 0 offData = pPersistDiskImage->NextOffset(); cnCode = pPersistDiskImage->Encode(PBYTE(auCredits), cbData); #endif // 0 } void CTitleCollection::CombineTitleLists(PTitleInfo *paptiSets, PUINT paiTitleStarts, UINT ctiSets, PTitleInfo **ppptiSorted, PUINT pcti ) { PTitleInfo *paptiSortedLeft = NULL, *paptiSortedRight = NULL; PTitleInfo *paptiSortedResult= NULL; UINT cFirst = 0; UINT cSecond = 0; __try { if (ctiSets == 1) { *ppptiSorted = paptiSets + *paiTitleStarts; *pcti = *(paiTitleStarts + 1) - *paiTitleStarts; __leave; } UINT ctiLeft = 0, ctiRight = 0; cFirst = ctiSets / 2; cSecond = ctiSets - cFirst; CombineTitleLists(paptiSets, paiTitleStarts, cFirst, &paptiSortedLeft, &ctiLeft); CombineTitleLists(paptiSets, paiTitleStarts + cFirst, cSecond, &paptiSortedRight, &ctiRight); UINT ctiResult= ctiLeft + ctiRight; paptiSortedResult= (PTitleInfo *) VAlloc(FALSE, ctiResult * sizeof(PTitleInfo)); MergeImageRefSets((PVOID *) paptiSortedResult, ctiResult, (PVOID *) paptiSortedLeft, ctiLeft, (PVOID *) paptiSortedRight, ctiRight, CompareTitleInfo ); *ppptiSorted = paptiSortedResult; paptiSortedResult= NULL; *pcti = ctiResult; } __finally { if (paptiSortedLeft && cFirst > 1) { VFree(paptiSortedLeft ); paptiSortedLeft = NULL; } if (paptiSortedRight && cSecond > 1) { VFree(paptiSortedRight); paptiSortedRight = NULL; } if (_abnormal_termination() && paptiSortedResult) { VFree(paptiSortedResult); paptiSortedResult= NULL; } } } int __cdecl CTitleCollection::CompareTitleInfo(const void *pvL, const void *pvR) { return CompareImagesLR(&(*(const TitleInfo **) pvL)->pd, &(*(const TitleInfo **) pvR)->pd); } UINT CTitleCollection::MapToTitleLists(CIndicatorSet * pisTitles, PTitleInfo *paptiLists, UINT cLists) { PUINT paiBuffer= NULL; UINT cTitlesFound= 0; __try { ASSERT(cLists >= m_ctsSlots); UINT cTitles= pisTitles? pisTitles->SelectionCount() : m_cd; UINT cChunk= C_INDICES_CHUNK; if (cChunk > cTitles) cChunk= cTitles; paiBuffer= PUINT(VAlloc(FALSE, cChunk * sizeof(UINT))); ZeroMemory(paptiLists, cLists * sizeof(PTokenInfo)); UINT iTitleFirst; for (iTitleFirst= 0; cTitles; iTitleFirst += cChunk, cTitles -= cChunk) { if (cChunk > cTitles) cChunk= cTitles; UINT c, i; PUINT pi; if (pisTitles) pisTitles->MarkedItems(iTitleFirst, PINT(paiBuffer), cChunk); else for (i= iTitleFirst, c= cChunk, pi= paiBuffer; c--; ) *pi++ = i++; for (c= cChunk, pi= paiBuffer + cChunk; c--; ) { PTitleInfo pti= m_pati + (m_ppdSorted[*--pi] - m_pd); UINT iSlot= pti->iaTSSlot; ASSERT(m_patsi[iSlot].fFlags & PRESENT); if (!(ACTIVE & m_patsi[iSlot].fFlags)) continue; ++cTitlesFound; pti->ptiNext= paptiLists[iSlot]; paptiLists[iSlot]= pti; } } } __finally { if (paiBuffer) { VFree(paiBuffer); paiBuffer= NULL; } } return cTitlesFound; }