*.js files: keep the style consistent
[TortoiseGit.git] / src / Utils / DirFileEnum.cpp
blob3c654542256bad85a51c8baf14b3b0eb2a46aefe
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2005-2006, 2009-2010 - TortoiseSVN
4 // Copyright (C) 2013 - TortoiseGit
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
20 #include "DirFileEnum.h"
23 CSimpleFileFind::CSimpleFileFind(const CString &sPath, LPCTSTR pPattern) :
24 m_dError(ERROR_SUCCESS),
25 m_bFirst(TRUE),
26 m_sPathPrefix(sPath)
28 // Add a trailing \ to m_sPathPrefix if it is missing.
29 // Do not add one to "C:" since "C:" and "C:\" are different.
30 int len = m_sPathPrefix.GetLength();
31 if (len != 0)
33 TCHAR ch = sPath[len-1];
34 if (ch != '\\' && (ch != ':' || len != 2))
36 m_sPathPrefix += "\\";
39 if ((len >= 248)&&(m_sPathPrefix.Left(4).Compare(_T("\\\\?\\"))))
40 m_hFindFile = ::FindFirstFile((LPCTSTR)(_T("\\\\?\\") + m_sPathPrefix + pPattern), &m_FindFileData);
41 else
42 m_hFindFile = ::FindFirstFile((LPCTSTR)(m_sPathPrefix + pPattern), &m_FindFileData);
43 if (m_hFindFile == INVALID_HANDLE_VALUE) {
44 m_dError = ::GetLastError();
48 CSimpleFileFind::~CSimpleFileFind()
50 if (m_hFindFile != INVALID_HANDLE_VALUE) {
51 ::FindClose(m_hFindFile);
55 BOOL CSimpleFileFind::FindNextFile()
57 if (m_dError) {
58 return FALSE;
61 if (m_bFirst) {
62 m_bFirst = FALSE;
63 return TRUE;
66 if (!::FindNextFile(m_hFindFile, &m_FindFileData)) {
67 m_dError = ::GetLastError();
68 return FALSE;
71 return TRUE;
74 BOOL CSimpleFileFind::FindNextFileNoDots()
76 BOOL result;
77 do {
78 result = FindNextFile();
79 } while (result && IsDots());
81 return result;
84 BOOL CSimpleFileFind::FindNextFileNoDirectories()
86 BOOL result;
87 do {
88 result = FindNextFile();
89 } while (result && IsDirectory());
91 return result;
96 * Implementation notes:
98 * This is a depth-first traversal. Directories are visited before
99 * their contents.
101 * We keep a stack of directories. The deepest directory is at the top
102 * of the stack, the originally-requested directory is at the bottom.
103 * If we come across a directory, we first return it to the user, then
104 * recurse into it. The finder at the bottom of the stack always points
105 * to the file or directory last returned to the user (except immediately
106 * after creation, when the finder points to the first valid thing we need
107 * to return, but we haven't actually returned anything yet - hence the
108 * m_bIsNew variable).
110 * Errors reading a directory are assumed to be end-of-directory, and
111 * are otherwise ignored.
113 * The "." and ".." psedo-directories are ignored for obvious reasons.
117 CDirFileEnum::CDirStackEntry::CDirStackEntry(CDirStackEntry * seNext,
118 const CString& sDirName)
119 : CSimpleFileFind(sDirName),
120 m_seNext(seNext)
124 CDirFileEnum::CDirStackEntry::~CDirStackEntry()
128 inline void CDirFileEnum::PopStack()
130 CDirStackEntry * seToDelete = m_seStack;
131 m_seStack = seToDelete->m_seNext;
132 delete seToDelete;
135 inline void CDirFileEnum::PushStack(const CString& sDirName)
137 m_seStack = new CDirStackEntry(m_seStack,sDirName);
140 CDirFileEnum::CDirFileEnum(const CString& sDirName) :
141 m_seStack(NULL),
142 m_bIsNew(TRUE)
144 PushStack(sDirName);
147 CDirFileEnum::~CDirFileEnum()
149 while (m_seStack != NULL) {
150 PopStack();
154 BOOL CDirFileEnum::NextFile(CString &sResult, bool* pbIsDirectory, bool bRecurse /* = true */)
156 if (m_bIsNew) {
157 // Special-case first time - haven't found anything yet,
158 // so don't do recurse-into-directory check.
159 m_bIsNew = FALSE;
160 } else if (m_seStack && m_seStack->IsDirectory() && bRecurse) {
161 PushStack(m_seStack->GetFilePath());
164 while (m_seStack && !m_seStack->FindNextFileNoDots()) {
165 // No more files in this directory, try parent.
166 PopStack();
169 if (m_seStack)
171 sResult = m_seStack->GetFilePath();
172 if(pbIsDirectory != NULL)
174 *pbIsDirectory = m_seStack->IsDirectory();
176 return TRUE;
177 } else {
178 return FALSE;
182 BOOL CDirFileEnum::NextFileGetSize(UINT64 &iSize, bool* pbIsDirectory, bool bRecurse /* = true */)
184 if (m_bIsNew) {
185 // Special-case first time - haven't found anything yet,
186 // so don't do recurse-into-directory check.
187 m_bIsNew = FALSE;
188 } else if (m_seStack && m_seStack->IsDirectory() && bRecurse) {
189 PushStack(m_seStack->GetFilePath());
192 while (m_seStack && !m_seStack->FindNextFileNoDots()) {
193 // No more files in this directory, try parent.
194 PopStack();
197 if (m_seStack)
199 iSize = m_seStack->GetSize();
200 if(pbIsDirectory != NULL)
202 *pbIsDirectory = m_seStack->IsDirectory();
204 return TRUE;
205 } else {
206 return FALSE;
210 UINT64 CDirFileEnum::GetSize()
212 bool dir;
213 UINT64 iSize = 0, iSize2 = 0;
214 while (NextFileGetSize(iSize2, &dir, true))
215 iSize += iSize2;
216 return iSize;