00001 /* 00002 * Winefile 00003 * 00004 * Copyright 2000, 2003, 2004, 2005, 2008 Martin Fuchs 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 */ 00020 00021 #include "winefile.h" 00022 00023 00024 /* allocate and initialise a directory entry */ 00025 Entry* alloc_entry(void) 00026 { 00027 Entry* entry = (Entry*) heap_alloc(sizeof(Entry)); 00028 00029 #ifdef _SHELL_FOLDERS 00030 entry->pidl = NULL; 00031 entry->folder = NULL; 00032 entry->hicon = 0; 00033 #endif 00034 00035 return entry; 00036 } 00037 00038 /* free a directory entry */ 00039 static void free_entry(Entry* entry) 00040 { 00041 #ifdef _SHELL_FOLDERS 00042 if (entry->hicon && entry->hicon!=(HICON)-1) 00043 DestroyIcon(entry->hicon); 00044 00045 if (entry->folder && entry->folder!=Globals.iDesktop) 00046 IShellFolder_Release(entry->folder); 00047 00048 if (entry->pidl) 00049 IMalloc_Free(Globals.iMalloc, entry->pidl); 00050 #endif 00051 00052 heap_free(entry); 00053 } 00054 00055 /* recursively free all child entries */ 00056 void free_entries(Entry* dir) 00057 { 00058 Entry *entry, *next=dir->down; 00059 00060 if (next) { 00061 dir->down = 0; 00062 00063 do { 00064 entry = next; 00065 next = entry->next; 00066 00067 free_entries(entry); 00068 free_entry(entry); 00069 } while(next); 00070 } 00071 } 00072 00073 00074 /* sort order for different directory/file types */ 00075 enum TYPE_ORDER { 00076 TO_DIR = 0, 00077 TO_DOT = 1, 00078 TO_DOTDOT = 2, 00079 TO_OTHER_DIR = 3, 00080 TO_FILE = 4 00081 }; 00082 00083 /* distinguish between ".", ".." and any other directory names */ 00084 static int TypeOrderFromDirname(LPCTSTR name) 00085 { 00086 if (name[0] == '.') { 00087 if (name[1] == '\0') 00088 return TO_DOT; /* "." */ 00089 00090 if (name[1]=='.' && name[2]=='\0') 00091 return TO_DOTDOT; /* ".." */ 00092 } 00093 00094 return TO_OTHER_DIR; /* anything else */ 00095 } 00096 00097 /* directories first... */ 00098 static int compareType(const WIN32_FIND_DATA* fd1, const WIN32_FIND_DATA* fd2) 00099 { 00100 int order1 = fd1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY? TO_DIR: TO_FILE; 00101 int order2 = fd2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY? TO_DIR: TO_FILE; 00102 00103 /* Handle "." and ".." as special case and move them at the very first beginning. */ 00104 if (order1==TO_DIR && order2==TO_DIR) { 00105 order1 = TypeOrderFromDirname(fd1->cFileName); 00106 order2 = TypeOrderFromDirname(fd2->cFileName); 00107 } 00108 00109 return order2==order1? 0: order1<order2? -1: 1; 00110 } 00111 00112 00113 /* compare two entries by name */ 00114 static int compareName(const void* arg1, const void* arg2) 00115 { 00116 const WIN32_FIND_DATA* fd1 = &(*(const Entry* const*)arg1)->data; 00117 const WIN32_FIND_DATA* fd2 = &(*(const Entry* const*)arg2)->data; 00118 00119 int cmp = compareType(fd1, fd2); 00120 if (cmp) 00121 return cmp; 00122 00123 return lstrcmpi(fd1->cFileName, fd2->cFileName); 00124 } 00125 00126 /* compare two entries by extension string */ 00127 static int compareExt(const void* arg1, const void* arg2) 00128 { 00129 const WIN32_FIND_DATA* fd1 = &(*(const Entry* const*)arg1)->data; 00130 const WIN32_FIND_DATA* fd2 = &(*(const Entry* const*)arg2)->data; 00131 const TCHAR *name1, *name2, *ext1, *ext2; 00132 00133 int cmp = compareType(fd1, fd2); 00134 if (cmp) 00135 return cmp; 00136 00137 name1 = fd1->cFileName; 00138 name2 = fd2->cFileName; 00139 00140 ext1 = _tcsrchr(name1, '.'); 00141 ext2 = _tcsrchr(name2, '.'); 00142 00143 if (ext1) 00144 ext1++; 00145 else 00146 ext1 = sEmpty; 00147 00148 if (ext2) 00149 ext2++; 00150 else 00151 ext2 = sEmpty; 00152 00153 cmp = lstrcmpi(ext1, ext2); 00154 if (cmp) 00155 return cmp; 00156 00157 return lstrcmpi(name1, name2); 00158 } 00159 00160 /* compare two entries by size */ 00161 static int compareSize(const void* arg1, const void* arg2) 00162 { 00163 const WIN32_FIND_DATA* fd1 = &(*(const Entry* const*)arg1)->data; 00164 const WIN32_FIND_DATA* fd2 = &(*(const Entry* const*)arg2)->data; 00165 00166 int cmp = compareType(fd1, fd2); 00167 if (cmp) 00168 return cmp; 00169 00170 cmp = fd2->nFileSizeHigh - fd1->nFileSizeHigh; 00171 00172 if (cmp < 0) 00173 return -1; 00174 else if (cmp > 0) 00175 return 1; 00176 00177 cmp = fd2->nFileSizeLow - fd1->nFileSizeLow; 00178 00179 return cmp<0? -1: cmp>0? 1: 0; 00180 } 00181 00182 /* compare two entries by date */ 00183 static int compareDate(const void* arg1, const void* arg2) 00184 { 00185 const WIN32_FIND_DATA* fd1 = &(*(const Entry* const*)arg1)->data; 00186 const WIN32_FIND_DATA* fd2 = &(*(const Entry* const*)arg2)->data; 00187 00188 int cmp = compareType(fd1, fd2); 00189 if (cmp) 00190 return cmp; 00191 00192 return CompareFileTime(&fd2->ftLastWriteTime, &fd1->ftLastWriteTime); 00193 } 00194 00195 00196 /* array of entry comparison functions */ 00197 00198 static int (*sortFunctions[])(const void* arg1, const void* arg2) = { 00199 compareName, /* SORT_NAME */ 00200 compareExt, /* SORT_EXT */ 00201 compareSize, /* SORT_SIZE */ 00202 compareDate /* SORT_DATE */ 00203 }; 00204 00205 00206 /* sort a list of directory entries by using the given sort order */ 00207 00208 static void SortDirectory(Entry* dir, enum SORT_ORDER sortOrder) 00209 { 00210 Entry* entry = dir->down; 00211 Entry** array, **p; 00212 int len; 00213 00214 len = 0; 00215 for(entry=dir->down; entry; entry=entry->next) 00216 len++; 00217 00218 if (len) { 00219 array = heap_alloc(len*sizeof(Entry*)); 00220 00221 p = array; 00222 for(entry=dir->down; entry; entry=entry->next) 00223 *p++ = entry; 00224 00225 /* call qsort() with the appropriate compare function */ 00226 qsort(array, len, sizeof(array[0]), sortFunctions[sortOrder]); 00227 00228 dir->down = array[0]; 00229 00230 for(p=array; --len; p++) 00231 p[0]->next = p[1]; 00232 00233 (*p)->next = 0; 00234 00235 heap_free(array); 00236 } 00237 } 00238 00239 00240 /* read a directory in one of the file system namespaces using the given sorting order */ 00241 00242 void read_directory(Entry* dir, LPCTSTR path, enum SORT_ORDER sortOrder, HWND hwnd) 00243 { 00244 TCHAR buffer[MAX_PATH]; 00245 Entry* entry; 00246 LPCTSTR s; 00247 PTSTR d; 00248 00249 #ifdef _SHELL_FOLDERS 00250 if (dir->etype == ET_SHELL) 00251 { 00252 read_directory_shell(dir, hwnd); 00253 00254 if (Globals.prescan_node) { 00255 s = path; 00256 d = buffer; 00257 00258 while(*s) 00259 *d++ = *s++; 00260 00261 *d++ = '\\'; 00262 00263 for(entry=dir->down; entry; entry=entry->next) 00264 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 00265 read_directory_shell(entry, hwnd); 00266 SortDirectory(entry, sortOrder); 00267 } 00268 } 00269 } 00270 else 00271 #endif 00272 #if !defined(_NO_EXTENSIONS) && defined(__WINE__) 00273 if (dir->etype == ET_UNIX) 00274 { 00275 read_directory_unix(dir, path); 00276 00277 if (Globals.prescan_node) { 00278 s = path; 00279 d = buffer; 00280 00281 while(*s) 00282 *d++ = *s++; 00283 00284 *d++ = '/'; 00285 00286 for(entry=dir->down; entry; entry=entry->next) 00287 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 00288 lstrcpy(d, entry->data.cFileName); 00289 read_directory_unix(entry, buffer); 00290 SortDirectory(entry, sortOrder); 00291 } 00292 } 00293 } 00294 else 00295 #endif 00296 { 00297 read_directory_win(dir, path); 00298 00299 if (Globals.prescan_node) { 00300 s = path; 00301 d = buffer; 00302 00303 while(*s) 00304 *d++ = *s++; 00305 00306 *d++ = '\\'; 00307 00308 for(entry=dir->down; entry; entry=entry->next) 00309 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 00310 lstrcpy(d, entry->data.cFileName); 00311 read_directory_win(entry, buffer); 00312 SortDirectory(entry, sortOrder); 00313 } 00314 } 00315 } 00316 00317 SortDirectory(dir, sortOrder); 00318 } 00319 00320 00321 /* read the directory tree of a drive in one of the file system namespaces using the given sorting order */ 00322 00323 Entry* read_tree(Root* root, LPCTSTR path, LPITEMIDLIST pidl, LPTSTR drv, enum SORT_ORDER sortOrder, HWND hwnd) 00324 { 00325 #if !defined(_NO_EXTENSIONS) && defined(__WINE__) 00326 static const TCHAR sSlash[] = {'/', '\0'}; 00327 #endif 00328 static const TCHAR sBackslash[] = {'\\', '\0'}; 00329 00330 #ifdef _SHELL_FOLDERS 00331 if (pidl) 00332 { 00333 /* read shell namespace tree */ 00334 root->drive_type = DRIVE_UNKNOWN; 00335 drv[0] = '\\'; 00336 drv[1] = '\0'; 00337 load_string(root->volname, IDS_DESKTOP); 00338 root->fs_flags = 0; 00339 load_string(root->fs, IDS_SHELL); 00340 00341 return read_tree_shell(root, pidl, sortOrder, hwnd); 00342 } 00343 else 00344 #endif 00345 #if !defined(_NO_EXTENSIONS) && defined(__WINE__) 00346 if (*path == '/') 00347 { 00348 /* read unix file system tree */ 00349 root->drive_type = GetDriveType(path); 00350 00351 lstrcat(drv, sSlash); 00352 load_string(root->volname, IDS_ROOT_FS); 00353 root->fs_flags = 0; 00354 load_string(root->fs, IDS_UNIXFS); 00355 00356 lstrcpy(root->path, sSlash); 00357 00358 return read_tree_unix(root, path, sortOrder, hwnd); 00359 } 00360 #endif 00361 00362 /* read WIN32 file system tree */ 00363 root->drive_type = GetDriveType(path); 00364 00365 lstrcat(drv, sBackslash); 00366 GetVolumeInformation(drv, root->volname, _MAX_FNAME, 0, 0, &root->fs_flags, root->fs, _MAX_DIR); 00367 00368 lstrcpy(root->path, drv); 00369 00370 return read_tree_win(root, path, sortOrder, hwnd); 00371 } 00372 00373 00374 /* get full path of specified directory entry */ 00375 00376 void get_path(Entry* dir, PTSTR path) 00377 { 00378 Entry* entry; 00379 int len = 0; 00380 int level = 0; 00381 00382 #ifdef _SHELL_FOLDERS 00383 if (dir->etype == ET_SHELL) { 00384 SFGAOF attribs; 00385 HRESULT hr = S_OK; 00386 00387 path[0] = '\0'; 00388 00389 attribs = 0; 00390 00391 if (dir->folder) 00392 hr = IShellFolder_GetAttributesOf(dir->folder, 1, (LPCITEMIDLIST*)&dir->pidl, &attribs); 00393 00394 if (SUCCEEDED(hr) && (attribs&SFGAO_FILESYSTEM)) { 00395 IShellFolder* parent = dir->up? dir->up->folder: Globals.iDesktop; 00396 00397 hr = path_from_pidl(parent, dir->pidl, path, MAX_PATH); 00398 } 00399 } 00400 else 00401 #endif 00402 { 00403 for(entry=dir; entry; level++) { 00404 LPCTSTR name; 00405 int l; 00406 00407 { 00408 LPCTSTR s; 00409 name = entry->data.cFileName; 00410 s = name; 00411 00412 for(l=0; *s && *s!='/' && *s!='\\'; s++) 00413 l++; 00414 } 00415 00416 if (entry->up) { 00417 if (l > 0) { 00418 memmove(path+l+1, path, len*sizeof(TCHAR)); 00419 memcpy(path+1, name, l*sizeof(TCHAR)); 00420 len += l+1; 00421 00422 #ifndef _NO_EXTENSIONS 00423 if (entry->etype == ET_UNIX) 00424 path[0] = '/'; 00425 else 00426 #endif 00427 path[0] = '\\'; 00428 } 00429 00430 entry = entry->up; 00431 } else { 00432 memmove(path+l, path, len*sizeof(TCHAR)); 00433 memcpy(path, name, l*sizeof(TCHAR)); 00434 len += l; 00435 break; 00436 } 00437 } 00438 00439 if (!level) { 00440 #ifndef _NO_EXTENSIONS 00441 if (entry->etype == ET_UNIX) 00442 path[len++] = '/'; 00443 else 00444 #endif 00445 path[len++] = '\\'; 00446 } 00447 00448 path[len] = '\0'; 00449 } 00450 }
Winefile Source Code Documentation
generated on 15.09.2008 by ![]() |