1 /* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18 /*! \file oscl_file_io.cpp
19 \brief This file contains file io APIs
20 */
21
22 #include "oscl_file_find.h"
23 #include "oscl_utf8conv.h"
24 #include "oscl_stdstring.h"
25 #ifndef OSCL_STRING_CONTAINERS_H_INCLUDED
26 #include "oscl_string_containers.h"
27 #endif
28
Oscl_FileFind()29 OSCL_EXPORT_REF Oscl_FileFind::Oscl_FileFind()
30 {
31 lastError = Oscl_FileFind::E_OK;
32 #if ! OSCL_HAS_GLOB
33 #define OSCL_FILEFIND_NUMBER_OF_FILES_ENTRY 256
34 int err = 0;
35 OSCL_TRY(err,
36 iDirEntVec.reserve(OSCL_FILEFIND_NUMBER_OF_FILES_ENTRY);
37 );
38 if (err)
39 {
40 iDirEntVec.clear();
41 OSCL_LEAVE(err);
42 lastError = Oscl_FileFind::E_OTHER;
43 }
44 #endif
45 delimeter = OSCL_FILE_CHAR_PATH_DELIMITER;
46 nullchar = _STRLIT_CHAR("\0");
47 count = 0;
48 foundfirst = false;
49 appendPathDelimiter = false;
50 pathname = NULL;
51 type = Oscl_FileFind::INVALID_TYPE;
52 }
53
~Oscl_FileFind()54 OSCL_EXPORT_REF Oscl_FileFind::~Oscl_FileFind()
55 {
56 Close();
57 }
58
59 static bool oscl_strglob(const char *str, const char *p);
FindFirst(const char * directory,const char * pattern,char * buf,uint32 buflen)60 OSCL_EXPORT_REF const char *Oscl_FileFind::FindFirst(const char *directory, const char *pattern, char *buf, uint32 buflen)
61 {
62 const char *def_pattern = "*";
63 lastError = Oscl_FileFind::E_OK;
64 type = Oscl_FileFind::INVALID_TYPE;
65 if (directory == NULL || buf == NULL || buflen <= 0)
66 {
67 lastError = Oscl_FileFind::E_INVALID_ARG;
68 return NULL;
69 }
70 if (pattern == NULL) pattern = def_pattern;
71 if (foundfirst)
72 {
73 lastError = Oscl_FileFind::E_INVALID_STATE;
74 return NULL;
75 }
76 #if (OSCL_HAS_GLOB)
77 if (!setpathanddelimiter(directory))
78 return NULL;
79 int retval;
80 OSCL_HeapString<OsclMemAllocator> path(pathname);
81 path += pattern;
82
83 if ((retval = glob(path.get_cstr(), GLOB_ERR | GLOB_NOSORT , NULL, &hFind)) == 0)
84 {
85 foundfirst = true;
86 if (hFind.gl_pathc > 0)
87 {
88 if (strlen(hFind.gl_pathv[count]) > buflen)
89 {
90 lastError = Oscl_FileFind::E_BUFFER_TOO_SMALL;
91 return NULL;
92 }
93 oscl_strncpy(buf, hFind.gl_pathv[count++], buflen);
94 struct stat statbuf;
95 if (stat(buf, &statbuf) == 0)
96 {
97 type = (S_ISDIR(statbuf.st_mode)) ? DIR_TYPE : FILE_TYPE;
98 }
99 else
100 {
101 type = FILE_TYPE;
102 }
103 return buf;
104 }
105 else
106 {
107 Close();
108 }
109 }
110 else
111 {
112 if (GLOB_NOMATCH == retval)
113 {
114 lastError = Oscl_FileFind::E_NO_MATCH;
115 }
116 else if (GLOB_ABORTED)
117 {
118 lastError = Oscl_FileFind::E_PATH_NOT_FOUND;
119 }
120 else
121 {
122 lastError = Oscl_FileFind::E_OTHER;
123 }
124 }
125 #else
126 // support linux having no glob.h support in glob pattern matching
127 if (!setpathanddelimiter(directory))
128 return NULL;
129 DIR* pDir;
130 struct dirent* pEnt;
131 uint32 itr = 0;
132 struct stat statbuf;
133 if (oscl_strlen(directory) > 0)
134 {
135 pDir = opendir(directory);
136 }
137 else
138 {
139 // empty directory, replaced with searching current dir
140 // make the behavior consistent with the glob-based implementation
141 OSCL_HeapString<OsclMemAllocator> curpath(".");
142 curpath += OSCL_FILE_CHAR_PATH_DELIMITER;
143 pDir = opendir(curpath.get_cstr());
144 }
145 if (pDir == NULL)
146 {
147 lastError = Oscl_FileFind::E_PATH_NOT_FOUND;
148 return NULL;
149 }
150 // parsing thru dirent structure
151 while ((pEnt = readdir(pDir)) != NULL)
152 {
153 if (oscl_strglob(pEnt->d_name, pattern) &&
154 oscl_strcmp(pEnt->d_name, ".") &&
155 oscl_strcmp(pEnt->d_name, "..")) // excluded out '.' and '..' from readdir
156 { // pattern matched
157 buf[0] = *nullchar;
158 oscl_strcat(buf, pathname);
159 oscl_strcat(buf, pEnt->d_name);
160 iDirEntVec.push_back(buf);
161 // d_type is not all available on all lunix system, using stat() instead
162 if (itr == 0)
163 { // first find filetype
164 if (stat(pEnt->d_name, &statbuf) == 0)
165 {
166 type = (S_ISDIR(statbuf.st_mode)) ? DIR_TYPE : FILE_TYPE;
167 }
168 else
169 {
170 type = FILE_TYPE;
171 }
172 }
173 itr++;
174 }
175 }
176 closedir(pDir);
177 if (iDirEntVec.size())
178 {
179 if (strlen(iDirEntVec[0].get_cstr()) > buflen)
180 {
181 lastError = Oscl_FileFind::E_BUFFER_TOO_SMALL;
182 return NULL;
183 }
184 // copy and return the first found element
185 buf[0] = *nullchar;
186 oscl_strcat(buf, iDirEntVec[0].get_cstr());
187 foundfirst = true;
188 count = 1; // advance to next element, used for findnext()
189 return buf;
190 }
191 lastError = Oscl_FileFind::E_NO_MATCH;
192 #endif
193 return NULL;
194 }
195
FindFirst(const oscl_wchar * directory,const oscl_wchar * pattern,oscl_wchar * buf,uint32 buflen)196 OSCL_EXPORT_REF const oscl_wchar *Oscl_FileFind::FindFirst(const oscl_wchar *directory, const oscl_wchar *pattern, oscl_wchar *buf, uint32 buflen)
197 {
198 const oscl_wchar *def_pattern = _STRLIT_WCHAR("*");
199 lastError = Oscl_FileFind::E_OK;
200 type = Oscl_FileFind::INVALID_TYPE;
201 if (directory == NULL || buf == NULL || buflen <= 0)
202 {
203 lastError = Oscl_FileFind::E_INVALID_ARG;
204 return NULL;
205 }
206 if (pattern == NULL) pattern = def_pattern;
207 if (foundfirst)
208 {
209 lastError = Oscl_FileFind::E_INVALID_STATE;
210 return NULL;
211 }
212 // non-symbain OSs are converted to char type FindFirst()
213 char* convpattern = (char*) OSCL_MALLOC(oscl_strlen(pattern) + 1);
214 char* convdir = (char*) OSCL_MALLOC(oscl_strlen(directory) + 1);
215 char* utf8buf = (char*) OSCL_MALLOC(buflen / sizeof(chartype));
216 if (!(convpattern && convdir && utf8buf))
217 {
218 lastError = Oscl_FileFind::E_MEMORY_ERROR;
219 OSCL_FREE(convdir);
220 OSCL_FREE(convpattern);
221 OSCL_FREE(utf8buf);
222 return NULL;
223 }
224 if ((0 == oscl_UnicodeToUTF8(directory, oscl_strlen(directory), convdir, oscl_strlen(directory) + 1)
225 && oscl_strlen(directory))
226 || (0 == oscl_UnicodeToUTF8(pattern, oscl_strlen(pattern), convpattern, oscl_strlen(pattern) + 1)
227 && oscl_strlen(pattern)))
228 {
229 lastError = Oscl_FileFind::E_PATH_TOO_LONG;
230 OSCL_FREE(convdir);
231 OSCL_FREE(convpattern);
232 OSCL_FREE(utf8buf);
233 return NULL;
234 }
235 const char* retval = FindFirst(convdir, convpattern, utf8buf, (buflen / sizeof(chartype)));
236 OSCL_FREE(convdir);
237 OSCL_FREE(convpattern);
238 if (retval != NULL)
239 {
240 int32 err = oscl_UTF8ToUnicode(retval, oscl_strlen(retval), buf, buflen);
241 OSCL_FREE(utf8buf);
242 if (!err && oscl_strlen(retval))
243 {
244 lastError = Oscl_FileFind::E_BUFFER_TOO_SMALL;
245 return NULL;
246 }
247 return buf;
248 }
249 OSCL_FREE(utf8buf);
250 return NULL;
251 }
252
FindNext(char * buf,uint32 buflen)253 OSCL_EXPORT_REF char *Oscl_FileFind::FindNext(char *buf, uint32 buflen)
254 {
255 lastError = Oscl_FileFind::E_OK;
256 type = Oscl_FileFind::INVALID_TYPE;
257 if (!buf || buflen <= 0)
258 {
259 lastError = Oscl_FileFind::E_INVALID_ARG;
260 return NULL;
261 }
262 if (!foundfirst)
263 {
264 lastError = Oscl_FileFind::E_INVALID_STATE;
265 return NULL;
266 }
267 #if (OSCL_HAS_GLOB)
268 if (count >= hFind.gl_pathc)
269 {
270 lastError = Oscl_FileFind::E_NO_MATCH;
271 return NULL;
272 }
273 if (oscl_strlen(hFind.gl_pathv[count]) > buflen)
274 {
275 lastError = Oscl_FileFind::E_BUFFER_TOO_SMALL;
276 }
277 else
278 {
279 oscl_strncpy(buf, hFind.gl_pathv[count++], buflen);
280 struct stat statbuf;
281 if (stat(buf, &statbuf) == 0)
282 {
283 type = (S_ISDIR(statbuf.st_mode)) ? DIR_TYPE : FILE_TYPE;
284 }
285 else
286 {
287 type = FILE_TYPE;
288 }
289 return buf;
290 }
291 #else
292 if (count >= iDirEntVec.size())
293 {
294 lastError = Oscl_FileFind::E_NO_MATCH;
295 return NULL;
296 }
297 if (oscl_strlen(iDirEntVec[count].get_cstr()) > buflen)
298 {
299 lastError = Oscl_FileFind::E_BUFFER_TOO_SMALL;
300 }
301 else
302 {
303 buf[0] = *nullchar;
304 oscl_strcat(buf, iDirEntVec[count++].get_cstr());
305 struct stat statbuf;
306 if (stat(buf, &statbuf) == 0)
307 {
308 type = (S_ISDIR(statbuf.st_mode)) ? DIR_TYPE : FILE_TYPE;
309 }
310 else
311 {
312 type = FILE_TYPE;
313 }
314 return buf;
315 }
316 #endif
317 return NULL;
318 }
319
FindNext(oscl_wchar * buf,uint32 buflen)320 OSCL_EXPORT_REF oscl_wchar *Oscl_FileFind::FindNext(oscl_wchar *buf, uint32 buflen)
321 {
322 lastError = Oscl_FileFind::E_OK;
323 type = Oscl_FileFind::INVALID_TYPE;
324 if (!buf || buflen <= 0)
325 {
326 lastError = Oscl_FileFind::E_INVALID_ARG;
327 return NULL;
328 }
329 if (!foundfirst)
330 {
331 lastError = Oscl_FileFind::E_INVALID_STATE;
332 return NULL;
333 }
334 char* utf8buf = (char*) OSCL_MALLOC(buflen * sizeof(chartype));
335 if (!utf8buf)
336 {
337 lastError = Oscl_FileFind::E_MEMORY_ERROR;
338 return NULL;
339 }
340 const char* retval = FindNext(utf8buf, buflen * sizeof(chartype));
341 if (retval != NULL)
342 {
343 int32 err = oscl_UTF8ToUnicode(retval, oscl_strlen(retval), buf, buflen);
344 OSCL_FREE(utf8buf);
345 if (!err && oscl_strlen(retval))
346 {
347 lastError = Oscl_FileFind::E_BUFFER_TOO_SMALL;
348 return NULL;
349 }
350 return buf;
351 }
352 lastError = Oscl_FileFind::E_NO_MATCH;
353 OSCL_FREE(utf8buf);
354 return NULL;
355 }
356
Close()357 OSCL_EXPORT_REF void Oscl_FileFind::Close()
358 {
359 #if (OSCL_HAS_GLOB)
360 if (foundfirst)
361 globfree(&hFind);
362 #else
363 iDirEntVec.clear();
364 #endif
365 foundfirst = false;
366 lastError = Oscl_FileFind::E_OK;
367 count = 0;
368 appendPathDelimiter = false;
369 if (pathname)
370 {
371 OSCL_FREE(pathname);
372 pathname = NULL;
373 }
374 }
375
GetElementType()376 OSCL_EXPORT_REF Oscl_FileFind::element_type Oscl_FileFind::GetElementType()
377 {
378 return type;
379 }
380
GetLastError()381 OSCL_EXPORT_REF Oscl_FileFind::error_type Oscl_FileFind::GetLastError()
382 {
383 return lastError;
384 }
385
setpathanddelimiter(const chartype * directory)386 bool Oscl_FileFind::setpathanddelimiter(const chartype* directory)
387 {
388 if (pathname)
389 {
390 lastError = Oscl_FileFind::E_INVALID_STATE;
391 return false;
392 }
393 if (directory[oscl_strlen(directory)-1] != *delimeter && oscl_strlen(directory))
394 appendPathDelimiter = true;
395 if (appendPathDelimiter)
396 pathname = (chartype*) OSCL_MALLOC((oscl_strlen(directory) + 2) * sizeof(chartype));
397 else
398 pathname = (chartype*) OSCL_MALLOC((oscl_strlen(directory) + 1) * sizeof(chartype));
399 if (!pathname)
400 {
401 lastError = E_MEMORY_ERROR;
402 return false;
403 }
404 pathname[0] = *nullchar;
405 oscl_strcat(pathname, directory);
406 if (appendPathDelimiter)
407 oscl_strcat(pathname, delimeter);
408 return true;
409 }
410 // globmatch matches pattern strings p from str, follows linux glob.c man spec.
oscl_strglob(const char * str,const char * p)411 static bool oscl_strglob(const char *str, const char *p)
412 {
413 #define NEGATE '^' /* std cset negation char */
414 int negate;
415 int match;
416 int c;
417
418 while (*p)
419 {
420 if (!*str && *p != '*')
421 return false;
422
423 switch (c = *p++)
424 {
425
426 case '*':
427 while (*p == '*')
428 p++;
429
430 if (!*p)
431 return true;
432
433 if (*p != '?' && *p != '[' && *p != '\\')
434 while (*str && *p != *str)
435 str++;
436
437 while (*str)
438 {
439 if (oscl_strglob(str, p))
440 return true;
441 str++;
442 }
443 return false;
444
445 case '?':
446 if (*str)
447 break;
448 return false;
449 /*
450 * set specification is inclusive, that is [a-z] is a, z and
451 * everything in between. this means [z-a] may be interpreted
452 * as a set that contains z, a and nothing in between.
453 */
454 case '[':
455 if (*p != NEGATE)
456 negate = false;
457 else
458 {
459 negate = true;
460 p++;
461 }
462
463 match = false;
464
465 while (!match && (c = *p++))
466 {
467 if (!*p)
468 return false;
469 if (*p == '-') /* c-c */
470 {
471 if (!*++p)
472 return false;
473 if (*p != ']')
474 {
475 if (*str == c || *str == *p ||
476 (*str > c && *str < *p))
477 match = true;
478 }
479 else /* c-] */
480 {
481 if (*str >= c)
482 match = true;
483 break;
484 }
485 }
486 else /* cc or c] */
487 {
488 if (c == *str)
489 match = true;
490 if (*p != ']')
491 {
492 if (*p == *str)
493 match = true;
494 }
495 else
496 break;
497 }
498 }
499
500 if (negate == match)
501 return false;
502 /*
503 * if there is a match, skip past the cset and continue on
504 */
505 while (*p && *p != ']')
506 p++;
507 if (!*p++)
508 return false;
509 break;
510
511 case '\\':
512 if (*p)
513 c = *p++;
514 default:
515 if (c != *str)
516 return false;
517 break;
518
519 }
520 str++;
521 }
522
523 return !*str;
524 }
525
526