1 /*!
2 	@file
3 	@author		Albert Semenov
4 	@date		09/2009
5 	@module
6 */
7 #ifndef FILE_SYSTEM_INFO_H_
8 #define FILE_SYSTEM_INFO_H_
9 
10 #include <MyGUI.h>
11 #if MYGUI_PLATFORM == MYGUI_PLATFORM_WIN32
12 #include <windows.h>
13 #include <io.h>
14 #else
15 #include <unistd.h>
16 #include <dirent.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <fnmatch.h>
21 #endif
22 
23 #include <string>
24 #include <vector>
25 #include <locale>
26 
27 namespace common
28 {
29 
30 	struct FileInfo
31 	{
FileInfoFileInfo32 		FileInfo(const std::wstring& _name, bool _folder) : name(_name), folder(_folder) { }
33 		std::wstring name;
34 		bool folder;
35 	};
36 	typedef std::vector<FileInfo> VectorFileInfo;
37 
toLower(const std::wstring & _input)38 	inline std::wstring toLower(const std::wstring& _input)
39 	{
40 		std::wstring result;
41 		result.resize(_input.size());
42 		static std::locale sLocale("");
43 		for (unsigned int i=0; i<_input.size(); ++i)
44 			result[i] = std::tolower(_input[i], sLocale);
45 		return result;
46 	}
47 
sortFiles(const common::FileInfo & left,const common::FileInfo & right)48 	inline bool sortFiles(const common::FileInfo& left, const common::FileInfo& right)
49 	{
50 		if (left.folder < right.folder)
51 			return true;
52 		if (left.folder > right.folder)
53 			return false;
54 
55 		return toLower(left.name) < toLower(right.name);
56 	}
57 
isAbsolutePath(const wchar_t * path)58 	inline bool isAbsolutePath(const wchar_t* path)
59 	{
60 	#if MYGUI_PLATFORM == MYGUI_PLATFORM_WIN32
61 		if (IsCharAlphaW(path[0]) && path[1] == ':')
62 			return true;
63 	#endif
64 		return path[0] == '/' || path[0] == '\\';
65 	}
66 
endWith(const std::wstring & _source,const std::wstring & _value)67 	inline bool endWith(const std::wstring& _source, const std::wstring& _value)
68 	{
69 		size_t count = _value.size();
70 		if (_source.size() < count)
71 			return false;
72 		size_t offset = _source.size() - count;
73 		for (size_t index = 0; index < count; ++ index)
74 		{
75 			if (_source[index + offset] != _value[index])
76 				return false;
77 		}
78 		return true;
79 	}
80 
concatenatePath(const std::wstring & _base,const std::wstring & _name)81 	inline std::wstring concatenatePath(const std::wstring& _base, const std::wstring& _name)
82 	{
83 		if (_base.empty() || isAbsolutePath(_name.c_str()))
84 		{
85 			return _name;
86 		}
87 		else
88 		{
89 			if (endWith(_base, L"\\") || endWith(_base, L"/"))
90 				return _base + _name;
91 
92 #if MYGUI_PLATFORM == MYGUI_PLATFORM_WIN32
93 			return _base + L'\\' + _name;
94 #else
95 			return _base + L'/' + _name;
96 #endif
97 		}
98 	}
99 
isReservedDir(const wchar_t * _fn)100 	inline bool isReservedDir (const wchar_t* _fn)
101 	{
102 		// if "."
103 		return (_fn [0] == '.' && _fn [1] == 0);
104 	}
105 
isParentDir(const wchar_t * _fn)106 	inline bool isParentDir (const wchar_t* _fn)
107 	{
108 		// if ".."
109 		return (_fn [0] == '.' && _fn [1] == '.' && _fn [2] == 0);
110 	}
111 
112 	inline void getSystemFileList(VectorFileInfo& _result, const std::wstring& _folder, const std::wstring& _mask, bool _sorted = true)
113 	{
114 #if MYGUI_PLATFORM == MYGUI_PLATFORM_WIN32
115 		//FIXME add optional parameter?
116 		bool ms_IgnoreHidden = true;
117 
118 		intptr_t lHandle;
119 		int res;
120 		struct _wfinddata_t tagData;
121 
122 		// pattern can contain a directory name, separate it from mask
123 		size_t pos = _mask.find_last_of(L"/\\");
124 		std::wstring directory;
125 		if (pos != _mask.npos)
126 			directory = _mask.substr (0, pos);
127 
128 		std::wstring full_mask = concatenatePath(_folder, _mask);
129 
130 		lHandle = _wfindfirst(full_mask.c_str(), &tagData);
131 		res = 0;
132 		while (lHandle != -1 && res != -1)
133 		{
134 			if (( !ms_IgnoreHidden || (tagData.attrib & _A_HIDDEN) == 0 ) &&
135 				!isReservedDir(tagData.name))
136 			{
137 				_result.push_back(FileInfo(concatenatePath(directory, tagData.name), (tagData.attrib & _A_SUBDIR) != 0));
138 			}
139 			res = _wfindnext( lHandle, &tagData );
140 		}
141 		// Close if we found any files
142 		if (lHandle != -1)
143 			_findclose(lHandle);
144 #else
145 		DIR* dir = opendir(MyGUI::UString(_folder).asUTF8_c_str());
146 		struct dirent* dp;
147 
148 		if (dir == nullptr)
149 		{
150 			/* opendir() failed */
151 			MYGUI_LOG(Error, (std::string("Can't open ") + MyGUI::UString(_folder).asUTF8_c_str()));
152 			return;
153 		}
154 
155 		rewinddir (dir);
156 
157 		while ((dp = readdir (dir)) != nullptr)
158 		{
159 			if ((fnmatch(MyGUI::UString(_mask).asUTF8_c_str(), dp->d_name, 0) == 0) && !isReservedDir(MyGUI::UString(dp->d_name).asWStr_c_str()))
160 			{
161 				struct stat fInfo;
162 				std::string path = MyGUI::UString(_folder).asUTF8() + "/" + dp->d_name;
163 				if (stat(path.c_str(), &fInfo) == -1)perror("stat");
164 				_result.push_back(FileInfo(MyGUI::UString(dp->d_name).asWStr(), (S_ISDIR(fInfo.st_mode))));
165 			}
166 		}
167 
168 		closedir(dir);
169 #endif
170 		if (_sorted)
171 		{
172 			std::sort(_result.begin(), _result.end(), sortFiles);
173 		}
174 	}
175 
getSystemCurrentFolder()176 	inline std::wstring getSystemCurrentFolder()
177 	{
178 #if MYGUI_PLATFORM == MYGUI_PLATFORM_WIN32
179 		wchar_t buff[MAX_PATH+1];
180 		::GetCurrentDirectoryW(MAX_PATH, buff);
181 		return buff;
182 #else
183 #	ifndef PATH_MAX
184 #		define PATH_MAX 256
185 #	endif
186 		char buff[PATH_MAX+1];
187 		return getcwd(buff, PATH_MAX) ? MyGUI::UString(buff).asWStr() : std::wstring();
188 #endif
189 	}
190 
191 	typedef std::vector<std::wstring> VectorWString;
scanFolder(VectorWString & _result,const std::wstring & _folder,bool _recursive,const std::wstring & _mask,bool _fullpath)192 	inline void scanFolder(VectorWString& _result, const std::wstring& _folder, bool _recursive, const std::wstring& _mask, bool _fullpath)
193 	{
194 		std::wstring folder = _folder;
195 		if (!folder.empty() && *folder.rbegin() != '/' && *folder.rbegin() != '\\') folder += L"/";
196 
197 		VectorFileInfo result;
198 		getSystemFileList(result, folder, _mask);
199 
200 		for (VectorFileInfo::const_iterator item = result.begin(); item != result.end(); ++item)
201 		{
202 			if (item->folder) continue;
203 
204 			if (_fullpath)
205 				_result.push_back(folder + item->name);
206 			else
207 				_result.push_back(item->name);
208 		}
209 
210 		if (_recursive)
211 		{
212 			getSystemFileList(result, folder, L"*");
213 
214 			for (VectorFileInfo::const_iterator item = result.begin(); item != result.end(); ++item)
215 			{
216 				if (!item->folder
217 					|| item->name == L".."
218 					|| item->name == L".") continue;
219 				scanFolder(_result, folder + item->name, _recursive, _mask, _fullpath);
220 			}
221 
222 		}
223 	}
224 
225 }
226 
227 #endif // FILE_SYSTEM_INFO_H_
228