Correctly deallocate buffer
[TortoiseGit.git] / src / Utils / DirFileEnum.cpp
blob3e78de1e4517da404d6c7302a95907967cbf31df
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2005-2006, 2009-2010 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 #include "stdafx.h"
19 #include "DirFileEnum.h"
22 CSimpleFileFind::CSimpleFileFind(const CString &sPath, LPCTSTR pPattern) :
23 m_dError(ERROR_SUCCESS),
24 m_bFirst(TRUE),
25 m_sPathPrefix(sPath)
27 // Add a trailing \ to m_sPathPrefix if it is missing.
28 // Do not add one to "C:" since "C:" and "C:\" are different.
29 int len = m_sPathPrefix.GetLength();
30 if (len != 0)
32 TCHAR ch = sPath[len-1];
33 if (ch != '\\' && (ch != ':' || len != 2))
35 m_sPathPrefix += "\\";
38 if ((len >= 248)&&(m_sPathPrefix.Left(4).Compare(_T("\\\\?\\"))))
39 m_hFindFile = ::FindFirstFile((LPCTSTR)(_T("\\\\?\\") + m_sPathPrefix + pPattern), &m_FindFileData);
40 else
41 m_hFindFile = ::FindFirstFile((LPCTSTR)(m_sPathPrefix + pPattern), &m_FindFileData);
42 if (m_hFindFile == INVALID_HANDLE_VALUE) {
43 m_dError = ::GetLastError();
47 CSimpleFileFind::~CSimpleFileFind()
49 if (m_hFindFile != INVALID_HANDLE_VALUE) {
50 ::FindClose(m_hFindFile);
54 BOOL CSimpleFileFind::FindNextFile()
56 if (m_dError) {
57 return FALSE;
60 if (m_bFirst) {
61 m_bFirst = FALSE;
62 return TRUE;
65 if (!::FindNextFile(m_hFindFile, &m_FindFileData)) {
66 m_dError = ::GetLastError();
67 return FALSE;
70 return TRUE;
73 BOOL CSimpleFileFind::FindNextFileNoDots()
75 BOOL result;
76 do {
77 result = FindNextFile();
78 } while (result && IsDots());
80 return result;
83 BOOL CSimpleFileFind::FindNextFileNoDirectories()
85 BOOL result;
86 do {
87 result = FindNextFile();
88 } while (result && IsDirectory());
90 return result;
95 * Implementation notes:
97 * This is a depth-first traversal. Directories are visited before
98 * their contents.
100 * We keep a stack of directories. The deepest directory is at the top
101 * of the stack, the originally-requested directory is at the bottom.
102 * If we come across a directory, we first return it to the user, then
103 * recurse into it. The finder at the bottom of the stack always points
104 * to the file or directory last returned to the user (except immediately
105 * after creation, when the finder points to the first valid thing we need
106 * to return, but we haven't actually returned anything yet - hence the
107 * m_bIsNew variable).
109 * Errors reading a directory are assumed to be end-of-directory, and
110 * are otherwise ignored.
112 * The "." and ".." psedo-directories are ignored for obvious reasons.
116 CDirFileEnum::CDirStackEntry::CDirStackEntry(CDirStackEntry * seNext,
117 const CString& sDirName)
118 : CSimpleFileFind(sDirName),
119 m_seNext(seNext)
123 CDirFileEnum::CDirStackEntry::~CDirStackEntry()
127 inline void CDirFileEnum::PopStack()
129 CDirStackEntry * seToDelete = m_seStack;
130 m_seStack = seToDelete->m_seNext;
131 delete seToDelete;
134 inline void CDirFileEnum::PushStack(const CString& sDirName)
136 m_seStack = new CDirStackEntry(m_seStack,sDirName);
139 CDirFileEnum::CDirFileEnum(const CString& sDirName) :
140 m_seStack(NULL),
141 m_bIsNew(TRUE)
143 PushStack(sDirName);
146 CDirFileEnum::~CDirFileEnum()
148 while (m_seStack != NULL) {
149 PopStack();
153 BOOL CDirFileEnum::NextFile(CString &sResult, bool* pbIsDirectory, bool bRecurse /* = true */)
155 if (m_bIsNew) {
156 // Special-case first time - haven't found anything yet,
157 // so don't do recurse-into-directory check.
158 m_bIsNew = FALSE;
159 } else if (m_seStack && m_seStack->IsDirectory() && bRecurse) {
160 PushStack(m_seStack->GetFilePath());
163 while (m_seStack && !m_seStack->FindNextFileNoDots()) {
164 // No more files in this directory, try parent.
165 PopStack();
168 if (m_seStack)
170 sResult = m_seStack->GetFilePath();
171 if(pbIsDirectory != NULL)
173 *pbIsDirectory = m_seStack->IsDirectory();
175 return TRUE;
176 } else {
177 return FALSE;