entries.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2003, 2004, 2005 Martin Fuchs
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 
00020  //
00021  // Explorer clone
00022  //
00023  // entries.cpp
00024  //
00025  // Martin Fuchs, 23.07.2003
00026  //
00027 
00028 
00029 #include <precomp.h>
00030 
00031 //#include "entries.h"
00032 
00033 
00034  // allocate and initialise a directory entry
00035 Entry::Entry(ENTRY_TYPE etype)
00036  :  _etype(etype)
00037 {
00038     _up = NULL;
00039     _next = NULL;
00040     _down = NULL;
00041     _expanded = false;
00042     _scanned = false;
00043     _bhfi_valid = false;
00044     _level = 0;
00045     _icon_id = ICID_UNKNOWN;
00046     _display_name = _data.cFileName;
00047     _type_name = NULL;
00048     _content = NULL;
00049 }
00050 
00051 Entry::Entry(Entry* parent, ENTRY_TYPE etype)
00052  :  _up(parent),
00053     _etype(etype)
00054 {
00055     _next = NULL;
00056     _down = NULL;
00057     _expanded = false;
00058     _scanned = false;
00059     _bhfi_valid = false;
00060     _level = 0;
00061     _icon_id = ICID_UNKNOWN;
00062     _shell_attribs = 0;
00063     _display_name = _data.cFileName;
00064     _type_name = NULL;
00065     _content = NULL;
00066 }
00067 
00068 Entry::Entry(const Entry& other)
00069 {
00070     _next = NULL;
00071     _down = NULL;
00072     _up = NULL;
00073 
00074     assert(!other._next);
00075     assert(!other._down);
00076     assert(!other._up);
00077 
00078     _expanded = other._expanded;
00079     _scanned = other._scanned;
00080     _level = other._level;
00081 
00082     _data = other._data;
00083 
00084     _shell_attribs = other._shell_attribs;
00085     _display_name = other._display_name==other._data.cFileName? _data.cFileName: _tcsdup(other._display_name);
00086     _type_name = other._type_name? _tcsdup(other._type_name): NULL;
00087     _content = other._content? _tcsdup(other._content): NULL;
00088 
00089     _etype = other._etype;
00090     _icon_id = other._icon_id;
00091 
00092     _bhfi = other._bhfi;
00093     _bhfi_valid = other._bhfi_valid;
00094 }
00095 
00096  // free a directory entry
00097 Entry::~Entry()
00098 {
00099     if (_icon_id > ICID_NONE)
00100         g_Globals._icon_cache.free_icon(_icon_id);
00101 
00102     if (_display_name != _data.cFileName)
00103         free(_display_name);
00104 
00105     if (_type_name)
00106         free(_type_name);
00107 
00108     if (_content)
00109         free(_content);
00110 
00111     if (_down)
00112         delete _down;
00113 }
00114 
00115 
00116  // read directory tree and expand to the given location
00117 Entry* Entry::read_tree(const void* path, SORT_ORDER sortOrder, int scan_flags)
00118 {
00119     CONTEXT("Entry::read_tree()");
00120 
00121     WaitCursor wait;
00122 
00123     Entry* entry = this;
00124 
00125     for(const void*p=path; p && entry; ) {
00126         entry->smart_scan(sortOrder, scan_flags);
00127 
00128         if (entry->_down)
00129             entry->_expanded = true;
00130 
00131         Entry* found = entry->find_entry(p);
00132         p = entry->get_next_path_component(p);
00133 
00134         entry = found;
00135     }
00136 
00137     return entry;
00138 }
00139 
00140 
00141 void Entry::read_directory_base(SORT_ORDER sortOrder, int scan_flags)
00142 {
00143     CONTEXT("Entry::read_directory_base()");
00144 
00145      // call into subclass
00146     read_directory(scan_flags);
00147 
00148 #ifndef ROSSHELL
00149     if (g_Globals._prescan_nodes) { ///@todo _prescan_nodes should not be used for reading the start menu.
00150         for(Entry*entry=_down; entry; entry=entry->_next)
00151             if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
00152                 entry->read_directory(scan_flags);
00153                 entry->sort_directory(sortOrder);
00154             }
00155     }
00156 #endif
00157 
00158     sort_directory(sortOrder);
00159 }
00160 
00161 
00162 Root::Root()
00163 {
00164     memset(this, 0, sizeof(Root));
00165 }
00166 
00167 Root::~Root()
00168 {
00169     if (_entry) {
00170         _entry->free_subentries();
00171         delete _entry;
00172     }
00173 }
00174 
00175 
00176  // sort order for different directory/file types
00177 enum TYPE_ORDER {
00178     TO_DIR,
00179     TO_DOT,
00180     TO_DOTDOT,
00181     TO_OTHER_DIR,
00182     TO_VIRTUAL_FOLDER,
00183     TO_FILE
00184 };
00185 
00186  // distinguish between ".", ".." and any other directory names
00187 static TYPE_ORDER TypeOrderFromDirname(LPCTSTR name)
00188 {
00189     if (name[0] == '.') {
00190         if (name[1] == '\0')
00191             return TO_DOT;      // "."
00192 
00193         if (name[1]=='.' && name[2]=='\0')
00194             return TO_DOTDOT;   // ".."
00195     }
00196 
00197     return TO_OTHER_DIR;        // any other directory
00198 }
00199 
00200  // directories first...
00201 static int compareType(const Entry* entry1, const Entry* entry2)
00202 {
00203     const WIN32_FIND_DATA* fd1 = &entry1->_data;
00204     const WIN32_FIND_DATA* fd2 = &entry2->_data;
00205 
00206     TYPE_ORDER order1 = fd1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY? TO_DIR: TO_FILE;
00207     TYPE_ORDER order2 = fd2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY? TO_DIR: TO_FILE;
00208 
00209      // Handle "." and ".." as special case and move them at the very first beginning.
00210     if (order1==TO_DIR && order2==TO_DIR) {
00211         order1 = TypeOrderFromDirname(fd1->cFileName);
00212         order2 = TypeOrderFromDirname(fd2->cFileName);
00213 
00214          // Move virtual folders after physical folders
00215         if (!(entry1->_shell_attribs & SFGAO_FILESYSTEM))
00216             order1 = TO_VIRTUAL_FOLDER;
00217 
00218         if (!(entry2->_shell_attribs & SFGAO_FILESYSTEM))
00219             order2 = TO_VIRTUAL_FOLDER;
00220     }
00221 
00222     return order2==order1? 0: order1<order2? -1: 1;
00223 }
00224 
00225 
00226 static int compareNothing(const void* arg1, const void* arg2)
00227 {
00228     return -1;
00229 }
00230 
00231 static int compareName(const void* arg1, const void* arg2)
00232 {
00233     const Entry* entry1 = *(const Entry**)arg1;
00234     const Entry* entry2 = *(const Entry**)arg2;
00235 
00236     int cmp = compareType(entry1, entry2);
00237     if (cmp)
00238         return cmp;
00239 
00240     return lstrcmpi(entry1->_data.cFileName, entry2->_data.cFileName);
00241 }
00242 
00243 static int compareExt(const void* arg1, const void* arg2)
00244 {
00245     const Entry* entry1 = *(const Entry**)arg1;
00246     const Entry* entry2 = *(const Entry**)arg2;
00247     const TCHAR *name1, *name2, *ext1, *ext2;
00248 
00249     int cmp = compareType(entry1, entry2);
00250     if (cmp)
00251         return cmp;
00252 
00253     name1 = entry1->_data.cFileName;
00254     name2 = entry2->_data.cFileName;
00255 
00256     ext1 = _tcsrchr(name1, TEXT('.'));
00257     ext2 = _tcsrchr(name2, TEXT('.'));
00258 
00259     if (ext1)
00260         ++ext1;
00261     else
00262         ext1 = TEXT("");
00263 
00264     if (ext2)
00265         ++ext2;
00266     else
00267         ext2 = TEXT("");
00268 
00269     cmp = lstrcmpi(ext1, ext2);
00270     if (cmp)
00271         return cmp;
00272 
00273     return lstrcmpi(name1, name2);
00274 }
00275 
00276 static int compareSize(const void* arg1, const void* arg2)
00277 {
00278     const Entry* entry1 = *(const Entry**)arg1;
00279     const Entry* entry2 = *(const Entry**)arg2;
00280 
00281     int cmp = compareType(entry1, entry2);
00282     if (cmp)
00283         return cmp;
00284 
00285     cmp = entry2->_data.nFileSizeHigh - entry1->_data.nFileSizeHigh;
00286 
00287     if (cmp < 0)
00288         return -1;
00289     else if (cmp > 0)
00290         return 1;
00291 
00292     cmp = entry2->_data.nFileSizeLow - entry1->_data.nFileSizeLow;
00293 
00294     return cmp<0? -1: cmp>0? 1: 0;
00295 }
00296 
00297 static int compareDate(const void* arg1, const void* arg2)
00298 {
00299     const Entry* entry1 = *(const Entry**)arg1;
00300     const Entry* entry2 = *(const Entry**)arg2;
00301 
00302     int cmp = compareType(entry1, entry2);
00303     if (cmp)
00304         return cmp;
00305 
00306     return CompareFileTime(&entry2->_data.ftLastWriteTime, &entry1->_data.ftLastWriteTime);
00307 }
00308 
00309 
00310 static int (*sortFunctions[])(const void* arg1, const void* arg2) = {
00311     compareNothing, // SORT_NONE
00312     compareName,    // SORT_NAME
00313     compareExt,     // SORT_EXT
00314     compareSize,    // SORT_SIZE
00315     compareDate     // SORT_DATE
00316 };
00317 
00318 
00319 void Entry::sort_directory(SORT_ORDER sortOrder)
00320 {
00321     if (sortOrder != SORT_NONE) {
00322         Entry* entry = _down;
00323         Entry** array, **p;
00324         int len;
00325 
00326         len = 0;
00327         for(entry=_down; entry; entry=entry->_next)
00328             ++len;
00329 
00330         if (len) {
00331             array = (Entry**) alloca(len*sizeof(Entry*));
00332 
00333             p = array;
00334             for(entry=_down; entry; entry=entry->_next)
00335                 *p++ = entry;
00336 
00337              // call qsort with the appropriate compare function
00338             qsort(array, len, sizeof(array[0]), sortFunctions[sortOrder]);
00339 
00340             _down = array[0];
00341 
00342             for(p=array; --len; p++)
00343                 (*p)->_next = p[1];
00344 
00345             (*p)->_next = 0;
00346         }
00347     }
00348 }
00349 
00350 
00351 void Entry::smart_scan(SORT_ORDER sortOrder, int scan_flags)
00352 {
00353     CONTEXT("Entry::smart_scan()");
00354 
00355     if (!_scanned) {
00356         free_subentries();
00357         read_directory_base(sortOrder, scan_flags); ///@todo We could use IShellFolder2::GetDefaultColumn to determine sort order.
00358     }
00359 }
00360 
00361 
00362 
00363 int Entry::extract_icon(ICONCACHE_FLAGS flags)
00364 {
00365     TCHAR path[MAX_PATH];
00366 
00367     ICON_ID icon_id = ICID_NONE;
00368 
00369     if (_etype!=ET_SHELL && get_path(path, COUNTOF(path)))  // not for ET_SHELL to display the correct desktop icon
00370         if (!(flags & ICF_MIDDLE))  // not for ICF_MIDDLE to extract 24x24 icons because SHGetFileInfo() doesn't support this icon size
00371             icon_id = g_Globals._icon_cache.extract(path, flags);
00372 
00373     if (icon_id == ICID_NONE) {
00374         if (!(flags & ICF_OVERLAYS)) {
00375             IExtractIcon* pExtract;
00376             if (SUCCEEDED(GetUIObjectOf(0, IID_IExtractIcon, (LPVOID*)&pExtract))) {
00377                 unsigned gil_flags = 0;
00378                 int idx;
00379 
00380                 if (flags & ICF_OPEN)
00381                     gil_flags |= GIL_OPENICON;
00382 
00383                 if (SUCCEEDED(pExtract->GetIconLocation(GIL_FORSHELL, path, COUNTOF(path), &idx, &gil_flags))) {
00384                     if (gil_flags & GIL_NOTFILENAME)
00385                         icon_id = g_Globals._icon_cache.extract(pExtract, path, idx, flags);
00386                     else {
00387                         if (idx == -1)
00388                             idx = 0;    // special case for some control panel applications ("System")
00389 
00390                         icon_id = g_Globals._icon_cache.extract(path, idx, flags);
00391                     }
00392 
00393                 /* using create_absolute_pidl() [see below] results in more correct icons for some control panel applets (NVidia display driver).
00394                     if (icon_id == ICID_NONE) {
00395                         SHFILEINFO sfi;
00396 
00397                         if (SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_ICON|SHGFI_SMALLICON))
00398                             icon_id = g_Globals._icon_cache.add(sfi.hIcon)._id;
00399                     } */
00400                 /*
00401                     if (icon_id == ICID_NONE) {
00402                         LPBYTE b = (LPBYTE) alloca(0x10000);
00403                         SHFILEINFO sfi;
00404 
00405                         FILE* file = fopen(path, "rb");
00406                         if (file) {
00407                             int l = fread(b, 1, 0x10000, file);
00408                             fclose(file);
00409 
00410                             if (l)
00411                                 icon_id = g_Globals._icon_cache.add(CreateIconFromResourceEx(b, l, TRUE, 0x00030000, 16, 16, LR_DEFAULTCOLOR));
00412                         }
00413                     } */
00414                 }
00415             }
00416         }
00417 
00418         if (icon_id == ICID_NONE) {
00419             const ShellPath& pidl_abs = create_absolute_pidl();
00420             LPCITEMIDLIST pidl = pidl_abs;
00421 
00422             icon_id = g_Globals._icon_cache.extract(pidl, flags);
00423         }
00424     }
00425 
00426     return icon_id;
00427 }
00428 
00429 int Entry::safe_extract_icon(ICONCACHE_FLAGS flags)
00430 {
00431     try {
00432         return extract_icon(flags);
00433     } catch(COMException&) {
00434         // ignore unexpected exceptions while extracting icons
00435     }
00436 
00437     return ICID_NONE;
00438 }
00439 
00440 
00441 BOOL Entry::launch_entry(HWND hwnd, UINT nCmdShow)
00442 {
00443     TCHAR cmd[MAX_PATH];
00444 
00445     if (!get_path(cmd, COUNTOF(cmd)))
00446         return FALSE;
00447 
00448      // add path to the recent file list
00449     SHAddToRecentDocs(SHARD_PATH, cmd);
00450 
00451       // start program, open document...
00452     return launch_file(hwnd, cmd, nCmdShow);
00453 }
00454 
00455 
00456  // local replacement implementation for SHBindToParent()
00457  // (derived from http://www.geocities.com/SiliconValley/2060/articles/shell-helpers.html)
00458 static HRESULT my_SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, VOID** ppv, LPCITEMIDLIST* ppidlLast)
00459 {
00460     HRESULT hr;
00461 
00462     if (!ppv)
00463         return E_POINTER;
00464 
00465     // There must be at least one item ID.
00466     if (!pidl || !pidl->mkid.cb)
00467         return E_INVALIDARG;
00468 
00469      // Get the desktop folder as root.
00470     ShellFolder desktop;
00471 /*  IShellFolderPtr desktop;
00472     hr = SHGetDesktopFolder(&desktop);
00473     if (FAILED(hr))
00474         return hr; */
00475 
00476     // Walk to the penultimate item ID.
00477     LPCITEMIDLIST marker = pidl;
00478     for (;;)
00479     {
00480         LPCITEMIDLIST next = reinterpret_cast<LPCITEMIDLIST>(
00481             marker->mkid.abID - sizeof(marker->mkid.cb) + marker->mkid.cb);
00482         if (!next->mkid.cb)
00483             break;
00484         marker = next;
00485     }
00486 
00487     if (marker == pidl)
00488     {
00489         // There was only a single item ID, so bind to the root folder.
00490         hr = desktop->QueryInterface(riid, ppv);
00491     }
00492     else
00493     {
00494         // Copy the ID list, truncating the last item.
00495         int length = marker->mkid.abID - pidl->mkid.abID;
00496         if (LPITEMIDLIST parent_id = reinterpret_cast<LPITEMIDLIST>(
00497             malloc(length + sizeof(pidl->mkid.cb))))
00498         {
00499             LPBYTE raw_data = reinterpret_cast<LPBYTE>(parent_id);
00500             memcpy(raw_data, pidl, length);
00501             memset(raw_data + length, 0, sizeof(pidl->mkid.cb));
00502             hr = desktop->BindToObject(parent_id, 0, riid, ppv);
00503             free(parent_id);
00504         }
00505         else
00506             return E_OUTOFMEMORY;
00507     }
00508 
00509     // Return a pointer to the last item ID.
00510     if (ppidlLast)
00511         *ppidlLast = marker;
00512 
00513     return hr;
00514 }
00515 #define USE_MY_SHBINDTOPARENT
00516 
00517 HRESULT Entry::do_context_menu(HWND hwnd, const POINT& pos, CtxMenuInterfaces& cm_ifs)
00518 {
00519     ShellPath shell_path = create_absolute_pidl();
00520     LPCITEMIDLIST pidl_abs = shell_path;
00521 
00522     if (!pidl_abs)
00523         return S_FALSE; // no action for registry entries, etc.
00524 
00525 #ifdef USE_MY_SHBINDTOPARENT
00526     IShellFolder* parentFolder;
00527     LPCITEMIDLIST pidlLast;
00528 
00529      // get and use the parent folder to display correct context menu in all cases -> correct "Properties" dialog for directories, ...
00530     HRESULT hr = my_SHBindToParent(pidl_abs, IID_IShellFolder, (LPVOID*)&parentFolder, &pidlLast);
00531 
00532     if (SUCCEEDED(hr)) {
00533         hr = ShellFolderContextMenu(parentFolder, hwnd, 1, &pidlLast, pos.x, pos.y, cm_ifs);
00534 
00535         parentFolder->Release();
00536     }
00537 
00538     return hr;
00539 #else
00540     static DynamicFct<HRESULT(WINAPI*)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*)> SHBindToParent(TEXT("SHELL32"), "SHBindToParent");
00541 
00542     if (SHBindToParent) {
00543         IShellFolder* parentFolder;
00544         LPCITEMIDLIST pidlLast;
00545 
00546          // get and use the parent folder to display correct context menu in all cases -> correct "Properties" dialog for directories, ...
00547         HRESULT hr = (*SHBindToParent)(pidl_abs, IID_IShellFolder, (LPVOID*)&parentFolder, &pidlLast);
00548 
00549         if (SUCCEEDED(hr)) {
00550             hr = ShellFolderContextMenu(parentFolder, hwnd, 1, &pidlLast, pos.x, pos.y, cm_ifs);
00551 
00552             parentFolder->Release();
00553         }
00554 
00555         return hr;
00556     } else {
00557         /**@todo use parent folder instead of desktop folder
00558         Entry* dir = _up;
00559 
00560         ShellPath parent_path;
00561 
00562         if (dir)
00563             parent_path = dir->create_absolute_pidl();
00564         else
00565             parent_path = DesktopFolderPath();
00566 
00567         ShellPath shell_path = create_relative_pidl(parent_path);
00568         LPCITEMIDLIST pidl = shell_path;
00569 
00570         ShellFolder parent_folder = parent_path;
00571         return ShellFolderContextMenu(parent_folder, hwnd, 1, &pidl, pos.x, pos.y);
00572         */
00573         return ShellFolderContextMenu(GetDesktopFolder(), hwnd, 1, &pidl_abs, pos.x, pos.y, cm_ifs);
00574     }
00575 #endif
00576 }
00577 
00578 
00579 HRESULT Entry::GetUIObjectOf(HWND hWnd, REFIID riid, LPVOID* ppvOut)
00580 {
00581     TCHAR path[MAX_PATH];
00582 /*
00583     if (!get_path(path, COUNTOF(path)))
00584         return E_FAIL;
00585 
00586     ShellPath shell_path(path);
00587 
00588     IShellFolder* pFolder;
00589     LPCITEMIDLIST pidl_last = NULL;
00590 
00591     static DynamicFct<HRESULT(WINAPI*)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*)> SHBindToParent(TEXT("SHELL32"), "SHBindToParent");
00592 
00593     if (!SHBindToParent)
00594         return E_NOTIMPL;
00595 
00596     HRESULT hr = (*SHBindToParent)(shell_path, IID_IShellFolder, (LPVOID*)&pFolder, &pidl_last);
00597     if (FAILED(hr))
00598         return hr;
00599 
00600     ShellFolder shell_folder(pFolder);
00601 
00602     shell_folder->Release();
00603 
00604     return shell_folder->GetUIObjectOf(hWnd, 1, &pidl_last, riid, NULL, ppvOut);
00605 */
00606     if (!_up)
00607         return E_INVALIDARG;
00608 
00609     if (!_up->get_path(path, COUNTOF(path)))
00610         return E_FAIL;
00611 
00612     ShellPath shell_path(path);
00613     ShellFolder shell_folder(shell_path);
00614 
00615 #ifdef UNICODE
00616     LPWSTR wname = _data.cFileName;
00617 #else
00618     WCHAR wname[MAX_PATH];
00619     MultiByteToWideChar(CP_ACP, 0, _data.cFileName, -1, wname, COUNTOF(wname));
00620 #endif
00621 
00622     LPITEMIDLIST pidl_last = NULL;
00623     HRESULT hr = shell_folder->ParseDisplayName(hWnd, NULL, wname, NULL, &pidl_last, NULL);
00624 
00625     if (FAILED(hr))
00626         return hr;
00627 
00628     hr = shell_folder->GetUIObjectOf(hWnd, 1, (LPCITEMIDLIST*)&pidl_last, riid, NULL, ppvOut);
00629 
00630     ShellMalloc()->Free((void*)pidl_last);
00631 
00632     return hr;
00633 }
00634 
00635 
00636  // get full path of specified directory entry
00637 bool Entry::get_path_base ( PTSTR path, size_t path_count, ENTRY_TYPE etype ) const
00638 {
00639     int level = 0;
00640     size_t len = 0;
00641     size_t l = 0;
00642     LPCTSTR name = NULL;
00643     TCHAR buffer[MAX_PATH];
00644 
00645     if (!path || path_count==0)
00646         return false;
00647 
00648     const Entry* entry;
00649     if ( path_count > 1 )
00650     {
00651         for(entry=this; entry; level++) {
00652             l = 0;
00653 
00654             if (entry->_etype == etype) {
00655                 name = entry->_data.cFileName;
00656 
00657                 for(LPCTSTR s=name; *s && *s!=TEXT('/') && *s!=TEXT('\\'); s++)
00658                     ++l;
00659 
00660                 if (!entry->_up)
00661                     break;
00662             } else {
00663                 if (entry->get_path(buffer, COUNTOF(buffer))) {
00664                     l = _tcslen(buffer);
00665                     name = buffer;
00666 
00667                     /* special handling of drive names */
00668                     if (l>0 && buffer[l-1]=='\\' && path[0]=='\\')
00669                         --l;
00670 
00671                     if ( len+l >= path_count )
00672                     {
00673                         if ( l + 1 > path_count )
00674                             len = 0;
00675                         else
00676                             len = path_count - l - 1;
00677                     }
00678                     memmove(path+l, path, len*sizeof(TCHAR));
00679                     if ( l+1 >= path_count )
00680                         l = path_count - 1;
00681                     memcpy(path, name, l*sizeof(TCHAR));
00682                     len += l;
00683                 }
00684 
00685                 entry = NULL;
00686                 break;
00687             }
00688 
00689             if (l > 0) {
00690                 if ( len+l+1 >= path_count )
00691                 {
00692                     /* compare to 2 here because of terminator plus the '\\' we prepend */
00693                     if ( l + 2 > path_count )
00694                         len = 0;
00695                     else
00696                         len = path_count - l - 2;
00697                 }
00698                 memmove(path+l+1, path, len*sizeof(TCHAR));
00699                 /* compare to 2 here because of terminator plus the '\\' we prepend */
00700                 if ( l+2 >= path_count )
00701                     l = path_count - 2;
00702                 memcpy(path+1, name, l*sizeof(TCHAR));
00703                 len += l+1;
00704 
00705 #ifndef _NO_WIN_FS
00706                 if (etype == ET_WINDOWS && entry->_up && !(entry->_up->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))  // a NTFS stream?
00707                     path[0] = TEXT(':');
00708                 else
00709 #endif
00710                     path[0] = TEXT('\\');
00711             }
00712 
00713             entry = entry->_up;
00714         }
00715 
00716         if (entry) {
00717             if ( len+l >= path_count )
00718             {
00719                 if ( l + 1 > path_count )
00720                     len = 0;
00721                 else
00722                     len = path_count - l - 1;
00723             }
00724             memmove(path+l, path, len*sizeof(TCHAR));
00725             if ( l+1 >= path_count )
00726                 l = path_count - 1;
00727             memcpy(path, name, l*sizeof(TCHAR));
00728             len += l;
00729         }
00730 
00731         if ( !level && (len+1 < path_count) )
00732             path[len++] = TEXT('\\');
00733     }
00734 
00735     path[len] = TEXT('\0');
00736 
00737     return true;
00738 }
00739 
00740  // recursively free all child entries
00741 void Entry::free_subentries()
00742 {
00743     Entry *entry, *next=_down;
00744 
00745     if (next) {
00746         _down = 0;
00747 
00748         do {
00749             entry = next;
00750             next = entry->_next;
00751 
00752             entry->free_subentries();
00753             delete entry;
00754         } while(next);
00755     }
00756 }
00757 
00758 
00759 Entry* Root::read_tree(LPCTSTR path, int scan_flags)
00760 {
00761     Entry* entry;
00762 
00763     if (path && *path)
00764         entry = _entry->read_tree(path, _sort_order);
00765     else {
00766         entry = _entry->read_tree(NULL, _sort_order);
00767 
00768         _entry->smart_scan();
00769 
00770         if (_entry->_down)
00771             _entry->_expanded = true;
00772     }
00773 
00774     return entry;
00775 }
00776 
00777 
00778 Entry* Root::read_tree(LPCITEMIDLIST pidl, int scan_flags)
00779 {
00780     return _entry->read_tree(pidl, _sort_order);
00781 }

ROS Explorer Source Code Documentation
generated on 02.01.2013 by doxygen

ROS Explorer Homepage