• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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