1/////////////////////////////////////////////////////////////////////////////
2// Name:        mac/dirmac.cpp
3// Purpose:     wxDir implementation for Mac
4// Author:      Stefan Csomor
5// Modified by:
6// Created:     08.12.99
7// RCS-ID:      $Id: dirmac.cpp 56405 2008-10-17 19:13:33Z SC $
8// Copyright:   (c) 1999 Stefan Csomor <csomor@advanced.ch>
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24    #pragma hdrstop
25#endif
26
27#include "wx/dir.h"
28
29#ifndef WX_PRECOMP
30    #include "wx/intl.h"
31    #include "wx/log.h"
32#endif // PCH
33
34#include "wx/filefn.h"          // for wxDirExists()
35#include "wx/filename.h"
36#include "wx/mac/private.h"
37
38// ----------------------------------------------------------------------------
39// private classes
40// ----------------------------------------------------------------------------
41
42// this class stores everything we need to enumerate the files
43class wxDirData
44{
45public:
46    wxDirData(const wxString& dirname);
47    ~wxDirData();
48
49    void Close() ;
50    void SetFileSpec(const wxString& filespec) { m_filespec = filespec; }
51    void SetFlags(int flags) { m_flags = flags; }
52
53    bool Read(wxString *filename); // reads the next
54    void Rewind() ;
55
56    const wxString& GetName() const { return m_dirname; }
57
58private:
59    FSIterator              m_iterator ;
60
61    wxString m_dirname;
62    wxString m_filespec;
63
64    int      m_flags;
65};
66
67// ============================================================================
68// implementation
69// ============================================================================
70
71// ----------------------------------------------------------------------------
72// wxDirData
73// ----------------------------------------------------------------------------
74
75wxDirData::wxDirData(const wxString& dirname)
76         : m_dirname(dirname)
77{
78    // throw away the trailing slashes
79    size_t n = m_dirname.length();
80    wxCHECK_RET( n, _T("empty dir name in wxDir") );
81
82    while ( n > 0 && wxIsPathSeparator(m_dirname[--n]) )
83        ;
84
85    m_dirname.Truncate(n + 1);
86    m_iterator = NULL ;
87}
88
89wxDirData::~wxDirData()
90{
91    Close() ;
92}
93
94void wxDirData::Close()
95{
96    if ( m_iterator )
97    {
98        FSCloseIterator( m_iterator ) ;
99        m_iterator = NULL ;
100    }
101}
102
103void wxDirData::Rewind()
104{
105    Close() ;
106}
107
108bool wxDirData::Read(wxString *filename)
109{
110    wxString result;
111    OSStatus err = noErr ;
112    if ( NULL == m_iterator )
113    {
114        FSRef dirRef;
115        err = wxMacPathToFSRef( m_dirname , &dirRef ) ;
116        if ( err == noErr )
117        {
118            Boolean isFolder, wasAliased;
119            FSResolveAliasFile( &dirRef, TRUE, &isFolder, &wasAliased );
120            err = FSOpenIterator(&dirRef, kFSIterateFlat, &m_iterator);
121        }
122        if ( err )
123        {
124            Close() ;
125            return false ;
126        }
127    }
128
129    wxString name ;
130    wxString lowerfilespec = m_filespec.Lower();
131
132    while( noErr == err )
133    {
134        HFSUniStr255 uniname ;
135        FSRef fileRef;
136        FSCatalogInfo catalogInfo;
137        ItemCount fetched = 0;
138
139        err = FSGetCatalogInfoBulk( m_iterator, 1, &fetched, NULL, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo , &catalogInfo , &fileRef, NULL, &uniname );
140
141        // expected error codes
142
143        if ( errFSNoMoreItems == err )
144            return false ;
145        if ( afpAccessDenied == err )
146            return false ;
147
148        if ( noErr != err )
149            break ;
150
151        name = wxMacHFSUniStrToString( &uniname ) ;
152        wxString lowername = name.Lower();
153
154        if ( ( name == wxT(".") || name == wxT("..") ) && !(m_flags & wxDIR_DOTDOT) )
155            continue;
156
157        if ( ( name[0U] == '.' ) && !(m_flags & wxDIR_HIDDEN ) )
158            continue ;
159
160        Boolean isFolder, wasAliased;
161        FSResolveAliasFile( &fileRef, TRUE, &isFolder, &wasAliased );
162        if ( wasAliased )
163        {
164            FSGetCatalogInfo( &fileRef, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL );
165        }
166
167        if ( (((FileInfo*)&catalogInfo.finderInfo)->finderFlags & kIsInvisible ) && !(m_flags & wxDIR_HIDDEN ) )
168            continue ;
169
170        // its a dir and we don't want it
171        if ( (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)  && !(m_flags & wxDIR_DIRS) )
172            continue ;
173
174        // its a file but we don't want it
175        if ( (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0  && !(m_flags & wxDIR_FILES ) )
176            continue ;
177
178        if ( m_filespec.empty() || m_filespec == wxT("*.*") || m_filespec == wxT("*") )
179        {
180        }
181        else if ( !wxMatchWild(lowerfilespec, lowername , false) )
182        {
183            continue ;
184        }
185
186        break ;
187    }
188    if ( err != noErr )
189    {
190        return false ;
191    }
192
193    *filename = name ;
194    return true;
195}
196
197// ----------------------------------------------------------------------------
198// wxDir helpers
199// ----------------------------------------------------------------------------
200
201/* static */
202bool wxDir::Exists(const wxString& dir)
203{
204    return wxDirExists(dir);
205}
206
207// ----------------------------------------------------------------------------
208// wxDir construction/destruction
209// ----------------------------------------------------------------------------
210
211wxDir::wxDir(const wxString& dirname)
212{
213    m_data = NULL;
214
215    (void)Open(dirname);
216}
217
218bool wxDir::Open(const wxString& dirname)
219{
220    delete m_data;
221    m_data = new wxDirData(dirname);
222
223    return true;
224}
225
226bool wxDir::IsOpened() const
227{
228    return m_data != NULL;
229}
230
231wxString wxDir::GetName() const
232{
233    wxString name;
234    if ( m_data )
235    {
236        name = m_data->GetName();
237        if ( !name.empty() && (name.Last() == _T('/')) )
238        {
239            // chop off the last (back)slash
240            name.Truncate(name.length() - 1);
241        }
242    }
243
244    return name;
245}
246
247wxDir::~wxDir()
248{
249    delete m_data;
250    m_data = NULL;
251}
252
253// ----------------------------------------------------------------------------
254// wxDir enumerating
255// ----------------------------------------------------------------------------
256
257bool wxDir::GetFirst(wxString *filename,
258                     const wxString& filespec,
259                     int flags) const
260{
261    wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
262
263    m_data->Rewind();
264
265    m_data->SetFileSpec(filespec);
266    m_data->SetFlags(flags);
267
268    return GetNext(filename);
269}
270
271bool wxDir::GetNext(wxString *filename) const
272{
273    wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
274
275    wxCHECK_MSG( filename, false, _T("bad pointer in wxDir::GetNext()") );
276
277    return m_data->Read(filename);
278}
279