entries.c

Go to the documentation of this file.
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 doxygen

Winefile Homepage