1 // SysIconUtils.cpp
2 
3 #include "StdAfx.h"
4 
5 #ifndef _UNICODE
6 #include "../../../Common/StringConvert.h"
7 #endif
8 
9 #include "../../../Windows/FileDir.h"
10 
11 #include "SysIconUtils.h"
12 
13 #ifndef _UNICODE
14 extern bool g_IsNT;
15 #endif
16 
GetIconIndexForCSIDL(int csidl)17 int GetIconIndexForCSIDL(int csidl)
18 {
19   LPITEMIDLIST pidl = 0;
20   SHGetSpecialFolderLocation(NULL, csidl, &pidl);
21   if (pidl)
22   {
23     SHFILEINFO shellInfo;
24     SHGetFileInfo(LPCTSTR(pidl), FILE_ATTRIBUTE_NORMAL,
25       &shellInfo, sizeof(shellInfo),
26       SHGFI_PIDL | SHGFI_SYSICONINDEX);
27     IMalloc  *pMalloc;
28     SHGetMalloc(&pMalloc);
29     if (pMalloc)
30     {
31       pMalloc->Free(pidl);
32       pMalloc->Release();
33     }
34     return shellInfo.iIcon;
35   }
36   return 0;
37 }
38 
39 #ifndef _UNICODE
40 typedef int (WINAPI * SHGetFileInfoWP)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags);
41 
42 struct CSHGetFileInfoInit
43 {
44   SHGetFileInfoWP shGetFileInfoW;
CSHGetFileInfoInitCSHGetFileInfoInit45   CSHGetFileInfoInit()
46   {
47     shGetFileInfoW = (SHGetFileInfoWP)
48     ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW");
49   }
50 } g_SHGetFileInfoInit;
51 #endif
52 
MySHGetFileInfoW(LPCWSTR pszPath,DWORD attrib,SHFILEINFOW * psfi,UINT cbFileInfo,UINT uFlags)53 static DWORD_PTR MySHGetFileInfoW(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags)
54 {
55   #ifdef _UNICODE
56   return SHGetFileInfo
57   #else
58   if (g_SHGetFileInfoInit.shGetFileInfoW == 0)
59     return 0;
60   return g_SHGetFileInfoInit.shGetFileInfoW
61   #endif
62   (pszPath, attrib, psfi, cbFileInfo, uFlags);
63 }
64 
GetRealIconIndex(CFSTR path,DWORD attrib,int & iconIndex)65 DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex)
66 {
67   #ifndef _UNICODE
68   if (!g_IsNT)
69   {
70     SHFILEINFO shellInfo;
71     DWORD_PTR res = ::SHGetFileInfo(fs2fas(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
72       sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
73     iconIndex = shellInfo.iIcon;
74     return res;
75   }
76   else
77   #endif
78   {
79     SHFILEINFOW shellInfo;
80     DWORD_PTR res = ::MySHGetFileInfoW(fs2us(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
81       sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
82     iconIndex = shellInfo.iIcon;
83     return res;
84   }
85 }
86 
87 /*
88 DWORD_PTR GetRealIconIndex(const UString &fileName, DWORD attrib, int &iconIndex, UString *typeName)
89 {
90   #ifndef _UNICODE
91   if (!g_IsNT)
92   {
93     SHFILEINFO shellInfo;
94     shellInfo.szTypeName[0] = 0;
95     DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
96         sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
97     if (typeName)
98       *typeName = GetUnicodeString(shellInfo.szTypeName);
99     iconIndex = shellInfo.iIcon;
100     return res;
101   }
102   else
103   #endif
104   {
105     SHFILEINFOW shellInfo;
106     shellInfo.szTypeName[0] = 0;
107     DWORD_PTR res = ::MySHGetFileInfoW(fileName, FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
108         sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
109     if (typeName)
110       *typeName = shellInfo.szTypeName;
111     iconIndex = shellInfo.iIcon;
112     return res;
113   }
114 }
115 */
116 
FindInSorted_Attrib(const CRecordVector<CAttribIconPair> & vect,DWORD attrib,int & insertPos)117 static int FindInSorted_Attrib(const CRecordVector<CAttribIconPair> &vect, DWORD attrib, int &insertPos)
118 {
119   unsigned left = 0, right = vect.Size();
120   while (left != right)
121   {
122     unsigned mid = (left + right) / 2;
123     DWORD midAttrib = vect[mid].Attrib;
124     if (attrib == midAttrib)
125       return mid;
126     if (attrib < midAttrib)
127       right = mid;
128     else
129       left = mid + 1;
130   }
131   insertPos = left;
132   return -1;
133 }
134 
FindInSorted_Ext(const CObjectVector<CExtIconPair> & vect,const wchar_t * ext,int & insertPos)135 static int FindInSorted_Ext(const CObjectVector<CExtIconPair> &vect, const wchar_t *ext, int &insertPos)
136 {
137   unsigned left = 0, right = vect.Size();
138   while (left != right)
139   {
140     unsigned mid = (left + right) / 2;
141     int compare = MyStringCompareNoCase(ext, vect[mid].Ext);
142     if (compare == 0)
143       return mid;
144     if (compare < 0)
145       right = mid;
146     else
147       left = mid + 1;
148   }
149   insertPos = left;
150   return -1;
151 }
152 
GetIconIndex(DWORD attrib,const wchar_t * fileName)153 int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UString *typeName */)
154 {
155   int dotPos = -1;
156   unsigned i;
157   for (i = 0;; i++)
158   {
159     wchar_t c = fileName[i];
160     if (c == 0)
161       break;
162     if (c == '.')
163       dotPos = i;
164   }
165 
166   /*
167   if (MyStringCompareNoCase(fileName, L"$Recycle.Bin") == 0)
168   {
169     char s[256];
170     sprintf(s, "SPEC i = %3d, attr = %7x", _attribMap.Size(), attrib);
171     OutputDebugStringA(s);
172     OutputDebugStringW(fileName);
173   }
174   */
175 
176   if ((attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 || dotPos < 0)
177   {
178     int insertPos = 0;
179     int index = FindInSorted_Attrib(_attribMap, attrib, insertPos);
180     if (index >= 0)
181     {
182       // if (typeName) *typeName = _attribMap[index].TypeName;
183       return _attribMap[index].IconIndex;
184     }
185     CAttribIconPair pair;
186     GetRealIconIndex(
187         #ifdef UNDER_CE
188         FTEXT("\\")
189         #endif
190         FTEXT("__DIR__")
191         , attrib, pair.IconIndex
192         // , pair.TypeName
193         );
194 
195     /*
196     char s[256];
197     sprintf(s, "i = %3d, attr = %7x", _attribMap.Size(), attrib);
198     OutputDebugStringA(s);
199     */
200 
201     pair.Attrib = attrib;
202     _attribMap.Insert(insertPos, pair);
203     // if (typeName) *typeName = pair.TypeName;
204     return pair.IconIndex;
205   }
206 
207   const wchar_t *ext = fileName + dotPos + 1;
208   int insertPos = 0;
209   int index = FindInSorted_Ext(_extMap, ext, insertPos);
210   if (index >= 0)
211   {
212     const CExtIconPair &pa = _extMap[index];
213     // if (typeName) *typeName = pa.TypeName;
214     return pa.IconIndex;
215   }
216 
217   for (i = 0;; i++)
218   {
219     wchar_t c = ext[i];
220     if (c == 0)
221       break;
222     if (c < L'0' || c > L'9')
223       break;
224   }
225   if (i != 0 && ext[i] == 0)
226   {
227     // GetRealIconIndex is too slow for big number of split extensions: .001, .002, .003
228     if (!SplitIconIndex_Defined)
229     {
230       GetRealIconIndex(
231           #ifdef UNDER_CE
232           FTEXT("\\")
233           #endif
234           FTEXT("__FILE__.001"), 0, SplitIconIndex);
235       SplitIconIndex_Defined = true;
236     }
237     return SplitIconIndex;
238   }
239 
240   CExtIconPair pair;
241   pair.Ext = ext;
242   GetRealIconIndex(us2fs(fileName + dotPos), attrib, pair.IconIndex);
243   _extMap.Insert(insertPos, pair);
244   // if (typeName) *typeName = pair.TypeName;
245   return pair.IconIndex;
246 }
247 
248 /*
249 int CExtToIconMap::GetIconIndex(DWORD attrib, const UString &fileName)
250 {
251   return GetIconIndex(attrib, fileName, NULL);
252 }
253 */