xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/FileManager/PanelSort.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // PanelSort.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../../C/CpuArch.h"
6 #include "../../../Windows/PropVariant.h"
7 
8 #include "../../PropID.h"
9 
10 #include "Panel.h"
11 
12 using namespace NWindows;
13 
CompareFileNames_ForFolderList(const wchar_t * s1,const wchar_t * s2)14 int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2)
15 {
16   for (;;)
17   {
18     wchar_t c1 = *s1;
19     wchar_t c2 = *s2;
20     if ((c1 >= '0' && c1 <= '9') &&
21         (c2 >= '0' && c2 <= '9'))
22     {
23       for (; *s1 == '0'; s1++);
24       for (; *s2 == '0'; s2++);
25       size_t len1 = 0;
26       size_t len2 = 0;
27       for (; (s1[len1] >= '0' && s1[len1] <= '9'); len1++);
28       for (; (s2[len2] >= '0' && s2[len2] <= '9'); len2++);
29       if (len1 < len2) return -1;
30       if (len1 > len2) return 1;
31       for (; len1 > 0; s1++, s2++, len1--)
32       {
33         if (*s1 == *s2) continue;
34         return (*s1 < *s2) ? -1 : 1;
35       }
36       c1 = *s1;
37       c2 = *s2;
38     }
39     s1++;
40     s2++;
41     if (c1 != c2)
42     {
43       // Probably we need to change the order for special characters like in Explorer.
44       wchar_t u1 = MyCharUpper(c1);
45       wchar_t u2 = MyCharUpper(c2);
46       if (u1 < u2) return -1;
47       if (u1 > u2) return 1;
48     }
49     if (c1 == 0) return 0;
50   }
51 }
52 
CompareFileNames_Le16(const Byte * s1,unsigned size1,const Byte * s2,unsigned size2)53 static int CompareFileNames_Le16(const Byte *s1, unsigned size1, const Byte *s2, unsigned size2)
54 {
55   size1 &= ~1u;
56   size2 &= ~1u;
57   for (unsigned i = 0;; i += 2)
58   {
59     if (i >= size1)
60       return (i >= size2) ? 0 : -1;
61     if (i >= size2)
62       return 1;
63     UInt16 c1 = GetUi16(s1 + i);
64     UInt16 c2 = GetUi16(s2 + i);
65     if (c1 == c2)
66     {
67       if (c1 == 0)
68         return 0;
69       continue;
70     }
71     if (c1 < c2)
72       return -1;
73     return 1;
74   }
75 }
76 
GetExtensionPtr(const UString & name)77 static inline const wchar_t *GetExtensionPtr(const UString &name)
78 {
79   const int dotPos = name.ReverseFind_Dot();
80   return name.Ptr(dotPos < 0 ? name.Len() : (unsigned)dotPos);
81 }
82 
SetSortRawStatus()83 void CPanel::SetSortRawStatus()
84 {
85   _isRawSortProp = false;
86   FOR_VECTOR (i, _columns)
87   {
88     const CPropColumn &prop = _columns[i];
89     if (prop.ID == _sortID)
90     {
91       _isRawSortProp = prop.IsRawProp ? 1 : 0;
92       return;
93     }
94   }
95 }
96 
97 
CompareItems2(LPARAM lParam1,LPARAM lParam2,LPARAM lpData)98 static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
99 {
100   if (lpData == 0)
101     return 0;
102   CPanel *panel = (CPanel*)lpData;
103 
104 
105   PROPID propID = panel->_sortID;
106 
107   if (propID == kpidNoProperty)
108     return MyCompare(lParam1, lParam2);
109 
110   if (panel->_isRawSortProp)
111   {
112     // Sha1, NtSecurity, NtReparse
113     const void *data1;
114     const void *data2;
115     UInt32 dataSize1;
116     UInt32 dataSize2;
117     UInt32 propType1;
118     UInt32 propType2;
119     if (panel->_folderRawProps->GetRawProp((UInt32)lParam1, propID, &data1, &dataSize1, &propType1) != 0) return 0;
120     if (panel->_folderRawProps->GetRawProp((UInt32)lParam2, propID, &data2, &dataSize2, &propType2) != 0) return 0;
121     if (dataSize1 == 0)
122       return (dataSize2 == 0) ? 0 : -1;
123     if (dataSize2 == 0)
124       return 1;
125     if (propType1 != NPropDataType::kRaw) return 0;
126     if (propType2 != NPropDataType::kRaw) return 0;
127     if (propID == kpidNtReparse)
128     {
129       NFile::CReparseShortInfo r1; r1.Parse((const Byte *)data1, dataSize1);
130       NFile::CReparseShortInfo r2; r2.Parse((const Byte *)data2, dataSize2);
131       return CompareFileNames_Le16(
132           (const Byte *)data1 + r1.Offset, r1.Size,
133           (const Byte *)data2 + r2.Offset, r2.Size);
134     }
135   }
136 
137   if (panel->_folderCompare)
138     return panel->_folderCompare->CompareItems((UInt32)lParam1, (UInt32)lParam2, propID, panel->_isRawSortProp);
139 
140   switch (propID)
141   {
142     // if (panel->_sortIndex == 0)
143     case kpidName:
144     {
145       const UString name1 = panel->GetItemName((unsigned)lParam1);
146       const UString name2 = panel->GetItemName((unsigned)lParam2);
147       const int res = CompareFileNames_ForFolderList(name1, name2);
148       /*
149       if (res != 0 || !panel->_flatMode)
150         return res;
151       const UString prefix1 = panel->GetItemPrefix(lParam1);
152       const UString prefix2 = panel->GetItemPrefix(lParam2);
153       return res = CompareFileNames_ForFolderList(prefix1, prefix2);
154       */
155       return res;
156     }
157     case kpidExtension:
158     {
159       const UString name1 = panel->GetItemName((unsigned)lParam1);
160       const UString name2 = panel->GetItemName((unsigned)lParam2);
161       return CompareFileNames_ForFolderList(
162           GetExtensionPtr(name1),
163           GetExtensionPtr(name2));
164     }
165   }
166   /*
167   if (panel->_sortIndex == 1)
168     return MyCompare(file1.Size, file2.Size);
169   return ::CompareFileTime(&file1.MTime, &file2.MTime);
170   */
171 
172   // PROPID propID = panel->_columns[panel->_sortIndex].ID;
173 
174   NCOM::CPropVariant prop1, prop2;
175   // Name must be first property
176   panel->_folder->GetProperty((UInt32)lParam1, propID, &prop1);
177   panel->_folder->GetProperty((UInt32)lParam2, propID, &prop2);
178   if (prop1.vt != prop2.vt)
179     return MyCompare(prop1.vt, prop2.vt);
180   if (prop1.vt == VT_BSTR)
181     return MyStringCompareNoCase(prop1.bstrVal, prop2.bstrVal);
182   return prop1.Compare(prop2);
183 }
184 
185 int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData);
CompareItems(LPARAM lParam1,LPARAM lParam2,LPARAM lpData)186 int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
187 {
188   if (lpData == 0) return 0;
189   if (lParam1 == (int)kParentIndex) return -1;
190   if (lParam2 == (int)kParentIndex) return 1;
191 
192   CPanel *panel = (CPanel*)lpData;
193 
194   const bool isDir1 = panel->IsItem_Folder((unsigned)lParam1);
195   const bool isDir2 = panel->IsItem_Folder((unsigned)lParam2);
196 
197   if (isDir1 && !isDir2) return -1;
198   if (isDir2 && !isDir1) return 1;
199 
200   const int result = CompareItems2(lParam1, lParam2, lpData);
201   return panel->_ascending ? result: (-result);
202 }
203 
204 
205 /*
206 void CPanel::SortItems(int index)
207 {
208   if (index == _sortIndex)
209     _ascending = !_ascending;
210   else
211   {
212     _sortIndex = index;
213     _ascending = true;
214     switch (_columns[_sortIndex].ID)
215     {
216       case kpidSize:
217       case kpidPackedSize:
218       case kpidCTime:
219       case kpidATime:
220       case kpidMTime:
221       _ascending = false;
222       break;
223     }
224   }
225   _listView.SortItems(CompareItems, (LPARAM)this);
226   _listView.EnsureVisible(_listView.GetFocusedItem(), false);
227 }
228 
229 void CPanel::SortItemsWithPropID(PROPID propID)
230 {
231   int index = _columns.FindItem_for_PropID(propID);
232   if (index >= 0)
233     SortItems(index);
234 }
235 */
236 
SortItemsWithPropID(PROPID propID)237 void CPanel::SortItemsWithPropID(PROPID propID)
238 {
239   if (propID == _sortID)
240     _ascending = !_ascending;
241   else
242   {
243     _sortID = propID;
244     _ascending = true;
245     switch (propID)
246     {
247       case kpidSize:
248       case kpidPackSize:
249       case kpidCTime:
250       case kpidATime:
251       case kpidMTime:
252         _ascending = false;
253       break;
254     }
255   }
256   SetSortRawStatus();
257   _listView.SortItems(CompareItems, (LPARAM)this);
258   _listView.EnsureVisible(_listView.GetFocusedItem(), false);
259 }
260 
261 
OnColumnClick(LPNMLISTVIEW info)262 void CPanel::OnColumnClick(LPNMLISTVIEW info)
263 {
264   /*
265   int index = _columns.FindItem_for_PropID(_visibleColumns[info->iSubItem].ID);
266   SortItems(index);
267   */
268   SortItemsWithPropID(_visibleColumns[info->iSubItem].ID);
269 }
270