📄 systemiconlibrary.cpp
字号:
//////////////////////////////////////////////////////////////////////
// FileFury
// Copyright (c) 2000 Tenebril Incorporated
// All rights reserved.
//
// This source code is governed by the Tenebril open source
// license (http://www.tenebril.com/developers/opensource/license.html)
//
// For more information on this and other open source applications,
// visit the Tenebril OpenSource page:
// http://www.tenebril.com/developers/opensource
//
//////////////////////////////////////////////////////////////////////
// SystemIconLibrary.cpp: implementation of the CSystemIconLibrary class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Oscar.h"
#include "SystemIconLibrary.h"
#include "IconLibraryDlg.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSystemIconLibrary::CSystemIconLibrary()
{
m_bContinueRefresh = TRUE;
m_pTrieRoot = new TrieNode;
memset((void *)m_pTrieRoot, 0, sizeof(TrieNode));
m_pTrieRoot->nIndex[0] = m_pTrieRoot->nIndex[1] = m_pTrieRoot->nIndex[2] = -1;
memset((void *)m_nSpecialIcon, 0, sizeof(m_nSpecialIcon));
UpdateSpecialIcons();
}
CSystemIconLibrary::~CSystemIconLibrary()
{
// Delete the entire trie.
PostDeleteEntries(m_pTrieRoot);
}
BOOL CSystemIconLibrary::Refresh(CFileSystem *pFS, CWnd *pStatusWnd)
{
// Recursively traverse the entire local filesystem, adding all
// icons. This procedure can be stopped at any time by calling the
// StopRefresh function.
TCHAR szDrives[512];
TCHAR *pDrive;
BOOL bHasSelected = FALSE;
m_cRefMutex.Lock(); // Don't walk over memory.
m_bContinueRefresh = TRUE;
m_cRefMutex.Unlock();
if ( !pFS->GetLogicalDriveStrings( sizeof(szDrives), szDrives ) )
{
ASSERT(0);
return FALSE;
}
pDrive = szDrives;
while( *pDrive )
{
// Check to see if we should break.
m_cRefMutex.Lock();
if(!m_bContinueRefresh) { m_cRefMutex.Unlock(); return TRUE; };
m_cRefMutex.Unlock();
// Ping only non-removable disks; we don't want to have drives spin
if(pFS->GetDriveType(pDrive) != DRIVE_REMOVABLE)
{
CString cszDrivePath;
cszDrivePath = pDrive;
RefreshPath(cszDrivePath, pStatusWnd);
}
pDrive += strlen( pDrive ) + 1;
}
return TRUE;
}
int CSystemIconLibrary::FindIcon(LPCTSTR czFileName, int nType)
{
TrieNode *pEntry = m_pTrieRoot;
CString cszName = czFileName;
ASSERT(sizeof(TCHAR) == 1); // Our trie only has 256 entries.
ASSERT(pEntry);
ASSERT(nType >= 0 && nType < 3);
cszName.MakeLower();
// Get the extension only.
if(cszName.ReverseFind(_T('.')) >= 0)
cszName = cszName.Right(cszName.GetLength() -
cszName.ReverseFind(_T('.')) - 1);
else
return UnknownIcon(nType);
if(cszName.GetLength() > 3)
return UnknownIcon(nType);
// Get the icon out of the trie.
for(int i = 0; i < cszName.GetLength(); i++)
{
TCHAR tc = cszName.GetAt(i);
int nCharID = (int)tc;
ASSERT(nCharID >= 0 && nCharID < 256);
pEntry = (TrieNode *)pEntry->Next[nCharID];
if(!pEntry) return UnknownIcon(nType); // No trie entry.
}
if(pEntry->nIndex[nType] < 0)
return UnknownIcon(nType);
return pEntry->nIndex[nType];
}
BOOL CSystemIconLibrary::UpdateIcon(LPCTSTR czFileName, UINT nID, int nType,
CWnd *pStatusWnd)
{
TrieNode *pEntry = m_pTrieRoot;
TrieNode *pNewEntry;
CString cszName = czFileName;
ASSERT(sizeof(TCHAR) == 1); // Our trie only has 256 entries.
ASSERT(pEntry);
ASSERT(nType >= 0 && nType < 3);
// Not case-sensitive.
cszName.MakeLower();
// Get the extension only.
if(cszName.ReverseFind(_T('.')) >= 0)
cszName = cszName.Right(cszName.GetLength() -
cszName.ReverseFind(_T('.')) - 1);
else
return FALSE; // Unknown icon
// Only standard extensions.
if(cszName.GetLength() > 3)
return FALSE;
// Make sure we don't add disallowed extensions.
if(cszName.CompareNoCase(_T("exe")) == 0)
return FALSE;
// Get to the correct trie entry.
for(int i = 0; i < cszName.GetLength(); i++)
{
TCHAR tc = cszName.GetAt(i);
int nCharID = (int)tc;
ASSERT(nCharID >= 0 && nCharID < 256);
pNewEntry = (TrieNode *)pEntry->Next[nCharID];
if(!pNewEntry)
{
// Allocate a new branch.
pEntry->Next[nCharID] = (char *)(new TrieNode);
memset((void *)pEntry->Next[nCharID], 0, sizeof(TrieNode));
pEntry->nIndex[0] = pEntry->nIndex[1] = pEntry->nIndex[2] = -1;
pNewEntry = (TrieNode *)pEntry->Next[nCharID];
ASSERT(pNewEntry);
if(pStatusWnd)
{
// Cast it.
CIconLibraryDlg *pIconDlg = (CIconLibraryDlg *)pStatusWnd;
pIconDlg->UpdateStatus(cszName);
}
TRACE(cszName + CString("\n"));
}
pEntry = pNewEntry;
}
// Set the information.
pEntry->nIndex[nType] = nID;
return TRUE;
}
BOOL CSystemIconLibrary::StopRefresh()
{
m_cRefMutex.Lock(); // Don't walk over memory.
m_bContinueRefresh = FALSE;
m_cRefMutex.Unlock();
return TRUE;
}
BOOL CSystemIconLibrary::RefreshPath(LPCTSTR czPath, CWnd *pStatusWnd)
{
// Search this path, and recurse downwards.
// We need to create our own file system handle to ensure
// that FindFile's don't hit. This isn't perfect; refresh
// took a CFileSystem parameter, which tends to imply that
// that is the file system we should be using here.
CFileSystem cFS;
CString cszPath = czPath;
cszPath += CString(_T("*.*"));
BOOL bFind = cFS.FindFile(cszPath);
while ( bFind )
{
// Check to see if we should break.
m_cRefMutex.Lock();
if(!m_bContinueRefresh) { m_cRefMutex.Unlock(); return TRUE; };
m_cRefMutex.Unlock();
bFind = cFS.FindNextFile();
if(cFS.IsDots())
continue;
if(cFS.IsDirectory())
{
// Recurse downwards.
CString cszNewPath = cFS.GetFilePath();
cszNewPath += CString(_T("\\"));
RefreshPath(cszNewPath, pStatusWnd);
}
// Add the icon.
UINT nIconID[3];
CString cszFilePath = cFS.GetFilePath();
SHFILEINFO shInfo;
// TODO: Handle cross-icons.
// Skip this if we've already added it.
if(FindIcon(cszFilePath, 0) >= 0)
continue;
// Get the icon id's.
cFS.FillFileInfo(cszFilePath, &shInfo, SHGFI_ICON | SHGFI_SMALLICON);
nIconID[SMALL_ICON] = shInfo.iIcon;
cFS.FillFileInfo(cszFilePath, &shInfo, SHGFI_ICON | SHGFI_LARGEICON);
nIconID[LARGE_ICON] = shInfo.iIcon;
// Can't do this; crashes some (poorly-written) callback DLLs.
// cFS.FillFileInfo(cszFilePath, &shInfo, SHGFI_ICON | SHGFI_OPENICON);
// nIconID[OPEN_ICON] = shInfo.iIcon;
// Store the icon information.
for(int i = 0; i < 3; i++)
UpdateIcon(cszFilePath, nIconID[i], i, pStatusWnd);
}
return TRUE;
}
BOOL CSystemIconLibrary::PostDeleteEntries(TrieNode *pEntry)
{
if(!pEntry) return FALSE;
for(int i = 0; i < 256; i++)
{
if(pEntry->Next[i])
PostDeleteEntries((TrieNode *)pEntry->Next[i]);
}
// Now do the post-delete.
delete pEntry;
return TRUE;
}
char *CSystemIconLibrary::ToBuffer(UINT &nSize)
{
int nAlloc = 1024;
UINT nEntries = 0;
nSize = 0;
SerialTrieNode *pSNode = new SerialTrieNode[nAlloc];
ASSERT(pSNode);
// Recursively serialize the trie.
TCHAR tcBuffer[3];
memset((void *)tcBuffer, 0, sizeof(tcBuffer));
SerializeEntries(m_pTrieRoot, &pSNode,
nAlloc, nEntries, tcBuffer);
// Allocate memory for an end-of-stream entry.
nEntries += 1;
if((int)nEntries == nAlloc)
{
nAlloc += 1;
SerialTrieNode *pNewSNode = new SerialTrieNode[nAlloc];
ASSERT(pNewSNode);
memcpy((void *)pNewSNode, (void *)pSNode,
sizeof(SerialTrieNode) * (nAlloc - 1));
delete pSNode;
pSNode = pNewSNode;
}
// Append an end-of-stream entry.
memset((void *)&pSNode[nEntries - 1], 0, sizeof(SerialTrieNode));
pSNode[nEntries - 1].nIndex[0] =
pSNode[nEntries - 1].nIndex[1] = pSNode[nEntries - 1].nIndex[2] = -5;
nSize = nEntries * sizeof(SerialTrieNode);
char *pMemPtr = (char *)pSNode;
return (char *)pSNode;
}
BOOL CSystemIconLibrary::SerializeEntries(TrieNode *pEntry,
SerialTrieNode **ppSNode,
int &nAlloc,
UINT &nSize,
TCHAR tcSoFar[3])
{
SerialTrieNode *pSNode = *ppSNode;
// TODO: Add failure memory deletion.
if(!pEntry || !pSNode)
return FALSE;
// Add the current entry.
SerialTrieNode stNode;
memcpy((void *)stNode.nIndex, (void *)pEntry->nIndex, sizeof(UINT) * 3);
memcpy((void *)stNode.Ext, (void *)tcSoFar, sizeof(TCHAR) * 3);
// Allocate more memory if necessary.
nSize += 1;
if((int)nSize == nAlloc)
{
nAlloc += 1024;
SerialTrieNode *pNewSNode = new SerialTrieNode[nAlloc];
ASSERT(pNewSNode);
memcpy((void *)pNewSNode, (void *)pSNode,
sizeof(SerialTrieNode) * (nAlloc - 1024));
delete pSNode;
pSNode = pNewSNode;
*ppSNode = pNewSNode;
}
// Push the new entry in.
memcpy((void *)&pSNode[nSize - 1], (void *)&stNode, sizeof(SerialTrieNode));
// Now add children.
for(int i = 0; i < 256; i++)
{
if(!pEntry->Next[i]) continue;
TCHAR tcBelow[3];
memcpy((void *)tcBelow, tcSoFar, sizeof(TCHAR) * 3);
// Presumes spaces after the '\0' are also '\0'.
if(tcBelow[0] == _T('\0'))
tcBelow[0] = (TCHAR)i;
else if(tcBelow[1] == _T('\0'))
tcBelow[1] = (TCHAR)i;
else if(tcBelow[2] == _T('\0'))
tcBelow[2] = (TCHAR)i;
SerializeEntries((TrieNode *)pEntry->Next[i],
ppSNode, nAlloc, nSize, tcBelow);
}
return TRUE;
}
int CSystemIconLibrary::FromBuffer(char *cBuffer)
{
ASSERT(cBuffer != NULL);
if(!cBuffer) return 0;
// We don't store the special entries; these are recomputed
// each time the program is run.
// Clear the trie.
PostDeleteEntries(m_pTrieRoot);
m_pTrieRoot = new TrieNode;
memset((void *)m_pTrieRoot, 0, sizeof(TrieNode));
// Loop over the entries, adding each.
int i = 0, j;
SerialTrieNode *pSNode = (SerialTrieNode *)cBuffer;
while(1)
{
// Break when we hit the end.
if(pSNode[i].Ext[0] == _T('\0') &&
pSNode[i].Ext[1] == _T('\0') &&
pSNode[i].Ext[2] == _T('\0') &&
pSNode[i].nIndex[0] == -5 &&
pSNode[i].nIndex[1] == -5 &&
pSNode[i].nIndex[2] == -5)
{
break;
}
// Add the current item.
CString cszFakeName;
cszFakeName = CString(_T("a.")) + pSNode[i].Ext;
for(j = 0; j < 3; j++)
UpdateIcon(cszFakeName, pSNode[i].nIndex[j], j);
i++;
}
return i;
}
BOOL CSystemIconLibrary::UpdateSpecialIcon(int nSpecial, int nIcon, int nType)
{
ASSERT(nSpecial >= 0 && nSpecial < 2);
ASSERT(nType >= 0 && nType < 3);
m_nSpecialIcon[nSpecial][nType] = nIcon;
return TRUE;
}
int CSystemIconLibrary::FindSpecialIcon(int nSpecial, int nType)
{
ASSERT(nSpecial >= 0 && nSpecial < 2);
ASSERT(nType >= 0 && nType < 3);
return m_nSpecialIcon[nSpecial][nType];
}
BOOL CSystemIconLibrary::UpdateSpecialIcons()
{
// Use the local file system to find the sought icons.
CFileSystem cFS;
TCHAR szDrives[512];
TCHAR *pDrive;
if ( !cFS.GetLogicalDriveStrings( sizeof(szDrives), szDrives ) )
return FALSE;
pDrive = szDrives;
while( *pDrive )
{
// Search only non-removable disks; we don't want to have drives spin
if(cFS.GetDriveType(pDrive) != DRIVE_REMOVABLE)
{
// We need to find the icons for a small drive, small folder,
// small open folder, and large folder.
CString cszDriveRoot = pDrive;
SHFILEINFO shFinfo;
// First, the drive.
if ( !cFS.FillFileInfo( cszDriveRoot,
&shFinfo,
SHGFI_ICON | SHGFI_SMALLICON ) )
return FALSE;
UpdateSpecialIcon(SPECIALICON_DRIVE, shFinfo.iIcon, SMALL_ICON);
UpdateSpecialIcon(SPECIALICON_DRIVE, shFinfo.iIcon, OPEN_ICON);
// Second, the folders.
// We need to find a folder.
CString cszRootSearch = cszDriveRoot;
cszRootSearch += _T("*.*");
BOOL bFind = cFS.FindFile(cszRootSearch);
while(bFind)
{
bFind = cFS.FindNextFile();
if(cFS.IsDirectory())
{
// We found it. Get the icons.
CString cszDirName = cFS.GetFilePath();
if ( !cFS.FillFileInfo( cszDirName,
&shFinfo,
SHGFI_ICON | SHGFI_SMALLICON ) )
return FALSE;
UpdateSpecialIcon(SPECIALICON_FOLDER, shFinfo.iIcon, SMALL_ICON);
if ( !cFS.FillFileInfo( cszDirName,
&shFinfo,
SHGFI_ICON | SHGFI_OPENICON | SHGFI_SMALLICON ) )
return FALSE;
UpdateSpecialIcon(SPECIALICON_FOLDER, shFinfo.iIcon, OPEN_ICON);
if ( !cFS.FillFileInfo( cszDirName,
&shFinfo,
SHGFI_ICON | SHGFI_LARGEICON ) )
return FALSE;
UpdateSpecialIcon(SPECIALICON_FOLDER, shFinfo.iIcon, LARGE_ICON);
// Now we're done.
return TRUE;
}
}
}
pDrive += strlen( pDrive ) + 1; // Search all non-removable drives.
}
return FALSE;
}
int CSystemIconLibrary::UnknownIcon(int nType)
{
// Get the app.
COscarApp *pApp = (COscarApp *)AfxGetApp();
ASSERT(pApp);
ASSERT(nType >= 0 && nType < 2);
if(nType < 0 || nType > 1) nType = 0;
return pApp->m_nUnknownIcon[nType];
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -