merged: Platinum from linuxport branches
[xbmc:xbmc-antiquated.git] / xbmc / lib / libUPnP / Platinum / ThirdParty / Neptune / Source / System / Win32 / NptWin32Directory.cpp
1 /*****************************************************************\r
2 |\r
3 |      Neptune - Directory :: Win32 Implementation\r
4 |\r
5 |      (c) 2004 Sylvain Rebaud\r
6 |      Author: Sylvain Rebaud (sylvain@rebaud.com)\r
7 |\r
8  ****************************************************************/\r
9 \r
10 /*----------------------------------------------------------------------\r
11 |   includes\r
12 +---------------------------------------------------------------------*/\r
13 #if defined(_XBOX)\r
14 #include <xtl.h>\r
15 #else\r
16 #include <windows.h>\r
17 #endif\r
18 \r
19 #include "NptConfig.h"\r
20 #include "NptTypes.h"\r
21 #include "NptDirectory.h"\r
22 #include "NptDebug.h"\r
23 #include "NptResults.h"\r
24 #include "NptUtils.h"\r
25 \r
26 /*----------------------------------------------------------------------\r
27 |   constants\r
28 +---------------------------------------------------------------------*/\r
29 const char* const NPT_DIR_DELIMITER_STR = "\\";\r
30 const char        NPT_DIR_DELIMITER_CHR = '\\'; \r
31 \r
32 /*----------------------------------------------------------------------\r
33 |   NPT_Win32DirectoryEntry\r
34 +---------------------------------------------------------------------*/\r
35 class NPT_Win32DirectoryEntry : public NPT_DirectoryEntryInterface\r
36 {\r
37 public:\r
38     // methods\r
39     NPT_Win32DirectoryEntry(const char* path);\r
40     virtual ~NPT_Win32DirectoryEntry();\r
41 \r
42     // NPT_DirectoryEntryInterface methods\r
43     virtual NPT_Result GetInfo(NPT_DirectoryEntryInfo& info);\r
44 \r
45 private:\r
46     // members\r
47     NPT_String m_Path;\r
48 };\r
49 \r
50 /*----------------------------------------------------------------------\r
51 |   NPT_Win32DirectoryEntry::NPT_Win32DirectoryEntry\r
52 +---------------------------------------------------------------------*/\r
53 NPT_Win32DirectoryEntry::NPT_Win32DirectoryEntry(const char* path) :\r
54     m_Path(path)\r
55 {  \r
56     // replace delimiters with the proper one for the platform\r
57     m_Path.Replace((NPT_DIR_DELIMITER_CHR == '/')?'\\':'/', NPT_DIR_DELIMITER_CHR);\r
58 \r
59     // remove trailing slashes\r
60     m_Path.TrimRight(NPT_DIR_DELIMITER_CHR);\r
61 }\r
62 \r
63 /*----------------------------------------------------------------------\r
64 |   NPT_Win32DirectoryEntry::~NPT_Win32DirectoryEntry\r
65 +---------------------------------------------------------------------*/\r
66 NPT_Win32DirectoryEntry::~NPT_Win32DirectoryEntry()\r
67 {\r
68 }\r
69 \r
70 /*----------------------------------------------------------------------\r
71 |   NPT_Win32DirectoryEntry::GetInfo\r
72 +---------------------------------------------------------------------*/\r
73 NPT_Result\r
74 NPT_Win32DirectoryEntry::GetInfo(NPT_DirectoryEntryInfo& info)\r
75 {   \r
76     // FindFirstFile doesn't work for root directories such as C: \r
77     if (m_Path.GetLength() == 2 && m_Path[1] == ':') {\r
78         // Make sure there's always a trailing delimiter for root directories\r
79         DWORD attributes = GetFileAttributes(m_Path + NPT_DIR_DELIMITER_CHR);\r
80         if (attributes == -1) return NPT_ERROR_NO_SUCH_ITEM;\r
81 \r
82         NPT_ASSERT(attributes & FILE_ATTRIBUTE_DIRECTORY);\r
83 \r
84         info.size = 0;\r
85         info.type = NPT_DIRECTORY_TYPE;\r
86     } else {\r
87         WIN32_FIND_DATA filedata;\r
88         HANDLE sizeHandle = FindFirstFile(m_Path, &filedata);\r
89         if (sizeHandle == INVALID_HANDLE_VALUE) {\r
90             FindClose(sizeHandle);\r
91             return NPT_ERROR_NO_SUCH_ITEM;\r
92         }\r
93 \r
94         info.size = (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0 : ((NPT_UInt64)filedata.nFileSizeHigh << 32) | filedata.nFileSizeLow;\r
95         info.type = (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? NPT_DIRECTORY_TYPE : NPT_FILE_TYPE;\r
96 \r
97         FindClose(sizeHandle);\r
98     }\r
99 \r
100     return NPT_SUCCESS;\r
101 }\r
102 \r
103 /*----------------------------------------------------------------------\r
104 |   NPT_DirectoryEntry::NPT_DirectoryEntry\r
105 +---------------------------------------------------------------------*/\r
106 NPT_DirectoryEntry::NPT_DirectoryEntry(const char* path)\r
107 {\r
108     m_Delegate = new NPT_Win32DirectoryEntry(path);\r
109 }\r
110 \r
111 /*----------------------------------------------------------------------\r
112 |   NPT_Win32Directory\r
113 +---------------------------------------------------------------------*/\r
114 class NPT_Win32Directory : public NPT_DirectoryInterface\r
115 {\r
116 public:\r
117     // methods\r
118     NPT_Win32Directory(const char* path);\r
119     virtual ~NPT_Win32Directory();\r
120 \r
121     // NPT_DirectoryInterface methods\r
122     virtual NPT_Result GetInfo(NPT_DirectoryInfo& info);\r
123     virtual NPT_Result GetNextEntry(NPT_String& name, NPT_DirectoryEntryInfo* info = NULL);\r
124 \r
125 private:\r
126     // members\r
127     NPT_String   m_Path;\r
128     HANDLE       m_SearchHandle;\r
129     NPT_Cardinal m_Count;\r
130     bool         m_Validated;\r
131 };\r
132 \r
133 /*----------------------------------------------------------------------\r
134 |   NPT_Win32Directory::NPT_Win32Directory\r
135 +---------------------------------------------------------------------*/\r
136 NPT_Win32Directory::NPT_Win32Directory(const char* path) :\r
137     m_Path(path),\r
138     m_SearchHandle(NULL),\r
139     m_Count(0),\r
140     m_Validated(false)\r
141 {\r
142     // replace delimiters with the proper one for the platform\r
143     m_Path.Replace((NPT_DIR_DELIMITER_CHR == '/')?'\\':'/', NPT_DIR_DELIMITER_CHR);\r
144 \r
145     // remove trailing slashes\r
146     m_Path.TrimRight(NPT_DIR_DELIMITER_CHR);\r
147 }\r
148 \r
149 /*----------------------------------------------------------------------\r
150 |   NPT_Win32Directory::~NPT_Win32Directory\r
151 +---------------------------------------------------------------------*/\r
152 NPT_Win32Directory::~NPT_Win32Directory()\r
153 {\r
154     if (m_SearchHandle != NULL) {\r
155         FindClose(m_SearchHandle);\r
156     }\r
157 }\r
158 \r
159 /*----------------------------------------------------------------------\r
160 |   NPT_Win32Directory::GetInfo\r
161 +---------------------------------------------------------------------*/\r
162 NPT_Result\r
163 NPT_Win32Directory::GetInfo(NPT_DirectoryInfo& info)\r
164 {\r
165     if (!m_Validated) {\r
166         NPT_CHECK(NPT_Directory::GetEntryCount(m_Path, m_Count));\r
167         m_Validated = true;\r
168     }\r
169 \r
170     info.entry_count = m_Count;\r
171     return NPT_SUCCESS;\r
172 }\r
173 \r
174 /*----------------------------------------------------------------------\r
175 |   NPT_Win32Directory::GetNextEntry\r
176 +---------------------------------------------------------------------*/\r
177 NPT_Result\r
178 NPT_Win32Directory::GetNextEntry(NPT_String& name, NPT_DirectoryEntryInfo* info)\r
179 {\r
180     WIN32_FIND_DATA filedata;\r
181 \r
182     // reset output params first\r
183     name = "";\r
184 \r
185     if (m_SearchHandle == NULL) {\r
186         NPT_String root_path = m_Path;\r
187         NPT_DirectoryAppendToPath(root_path, "*");\r
188 \r
189         m_SearchHandle = FindFirstFile(root_path, &filedata);\r
190         if (m_SearchHandle == INVALID_HANDLE_VALUE) {\r
191             m_SearchHandle = NULL;\r
192             switch (GetLastError()) {\r
193                 case ERROR_FILE_NOT_FOUND:\r
194                 case ERROR_PATH_NOT_FOUND:\r
195                 case ERROR_NO_MORE_FILES:\r
196                     return NPT_ERROR_NO_SUCH_ITEM;\r
197 \r
198                 default:\r
199                     return NPT_FAILURE;\r
200             }\r
201         } \r
202     } else {\r
203         if (FindNextFile(m_SearchHandle, &filedata) == 0) {\r
204             // no more entries?\r
205             if (GetLastError() == ERROR_NO_MORE_FILES) \r
206                 return NPT_ERROR_NO_SUCH_ITEM;\r
207 \r
208             return NPT_FAILURE;\r
209         }\r
210     }\r
211 \r
212     // discard system specific files/shortcuts\r
213     if (NPT_StringsEqual(filedata.cFileName, ".") || NPT_StringsEqual(filedata.cFileName, "..")) {\r
214         return GetNextEntry(name, info);\r
215     }\r
216 \r
217     // assign output params\r
218     name = filedata.cFileName;\r
219     if (info) {\r
220         info->size = (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0 : ((NPT_UInt64)filedata.nFileSizeHigh << 32) | filedata.nFileSizeLow;\r
221         info->type = (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? NPT_DIRECTORY_TYPE : NPT_FILE_TYPE;\r
222     }\r
223 \r
224     return NPT_SUCCESS;\r
225 }\r
226 \r
227 /*----------------------------------------------------------------------\r
228 |   NPT_Directory::NPT_Directory\r
229 +---------------------------------------------------------------------*/\r
230 NPT_Directory::NPT_Directory(const char* path)\r
231 {\r
232     m_Delegate = new NPT_Win32Directory(path);\r
233 }\r
234 \r
235 /*----------------------------------------------------------------------\r
236 |   NPT_Directory::GetEntryCount\r
237 +---------------------------------------------------------------------*/\r
238 NPT_Result \r
239 NPT_Directory::GetEntryCount(const char* path, NPT_Cardinal& count)\r
240 {\r
241     WIN32_FIND_DATA filedata;\r
242     HANDLE          handle;\r
243     NPT_Result      res = NPT_SUCCESS;\r
244     NPT_String      root_path = path;\r
245 \r
246     // reset output params first\r
247     count = 0;    \r
248 \r
249     // replace delimiters with the proper one for the platform\r
250     root_path.Replace((NPT_DIR_DELIMITER_CHR == '/')?'\\':'/', NPT_DIR_DELIMITER_CHR);\r
251     // remove trailing slashes\r
252     root_path.TrimRight(NPT_DIR_DELIMITER_CHR);\r
253 \r
254     // verify it's a directory and not a file\r
255     NPT_DirectoryEntryInfo info;\r
256     NPT_CHECK(NPT_DirectoryEntry::GetInfo(root_path, info));\r
257     if (info.type == NPT_FILE_TYPE) return NPT_ERROR_INVALID_PARAMETERS;\r
258 \r
259     // start enumerating files\r
260     NPT_DirectoryAppendToPath(root_path, "*");\r
261     handle = FindFirstFile(root_path, &filedata);\r
262     if (handle == INVALID_HANDLE_VALUE) {\r
263         switch (GetLastError()) {\r
264             case ERROR_FILE_NOT_FOUND:\r
265             case ERROR_PATH_NOT_FOUND:\r
266             case ERROR_NO_MORE_FILES:\r
267                 return NPT_SUCCESS;\r
268 \r
269             default:\r
270                 return NPT_FAILURE;\r
271         }\r
272     }\r
273 \r
274     // count and disregard system specific files\r
275     do {\r
276         if (strcmp(filedata.cFileName, ".") && strcmp(filedata.cFileName, "..")) \r
277             ++count;\r
278     } while (FindNextFile(handle, &filedata));\r
279 \r
280     if (GetLastError() != ERROR_NO_MORE_FILES) {\r
281         res = NPT_FAILURE;\r
282     }\r
283 \r
284     FindClose(handle);\r
285     return res;\r
286 }\r
287 \r
288 /*----------------------------------------------------------------------\r
289 |   NPT_Directory::Create\r
290 +---------------------------------------------------------------------*/\r
291 NPT_Result \r
292 NPT_Directory::Create(const char* path)\r
293 {\r
294     // check if path exists, if so no need to create it\r
295     NPT_DirectoryInfo info;\r
296     if (NPT_FAILED(NPT_Directory::GetInfo(path, info))) {\r
297         return CreateDirectory(path, NULL)?NPT_SUCCESS:NPT_FAILURE;\r
298     }\r
299 \r
300     return NPT_SUCCESS;\r
301 }\r
302 \r
303 /*----------------------------------------------------------------------\r
304 |   NPT_Directory::Remove\r
305 +---------------------------------------------------------------------*/\r
306 NPT_Result \r
307 NPT_Directory::Remove(const char* path)\r
308 {\r
309     NPT_Result             res;\r
310     NPT_DirectoryEntryInfo info;\r
311 \r
312     // make sure the path exists\r
313     res = NPT_DirectoryEntry::GetInfo(path, info);\r
314     if (NPT_SUCCEEDED(res)) {\r
315         // delete path \r
316         if (info.type == NPT_DIRECTORY_TYPE) {\r
317             res = RemoveDirectory(path)?NPT_SUCCESS:NPT_FAILURE;\r
318         } else {\r
319             res = DeleteFile(path)?NPT_SUCCESS:NPT_FAILURE;\r
320         }\r
321 \r
322         if (NPT_FAILED(res)) {\r
323             NPT_Debug("NPT_Directory::Remove - Win32 Error=%d, Dir = '%s'", \r
324                 GetLastError(), path);\r
325         }\r
326     }\r
327 \r
328     return res;\r
329 }\r
330 \r
331 /*----------------------------------------------------------------------\r
332 |   NPT_Directory::Move\r
333 +---------------------------------------------------------------------*/\r
334 NPT_Result \r
335 NPT_Directory::Move(const char* input, const char* output)\r
336 {\r
337     NPT_Result             res;\r
338     NPT_DirectoryEntryInfo info;\r
339 \r
340     // make sure the path exists\r
341     res = NPT_DirectoryEntry::GetInfo(input, info);\r
342     if (NPT_SUCCEEDED(res)) {\r
343         res = MoveFile(input, output)?NPT_SUCCESS:NPT_FAILURE;\r
344         if (NPT_FAILED(res)) {\r
345             int err = GetLastError();\r
346             NPT_Debug("NPT_Directory::Move - Win32 Error=%d, Input = '%s', Output = '%s'", \r
347                 err, input, output);\r
348         }\r
349     }\r
350 \r
351     return res;\r
352 }\r