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
14extern bool g_IsNT;
15#endif
16
17int 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
40typedef int (WINAPI * SHGetFileInfoWP)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags);
41
42struct CSHGetFileInfoInit
43{
44  SHGetFileInfoWP shGetFileInfoW;
45  CSHGetFileInfoInit()
46  {
47    shGetFileInfoW = (SHGetFileInfoWP)
48    ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW");
49  }
50} g_SHGetFileInfoInit;
51#endif
52
53static 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
65DWORD_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/*
88DWORD_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
117static 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
135static 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
153int 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/*
249int CExtToIconMap::GetIconIndex(DWORD attrib, const UString &fileName)
250{
251  return GetIconIndex(attrib, fileName, NULL);
252}
253*/