Merge pull request #4775 from jmarshallnz/empty_episode_playcount
[vuplus_xbmc] / xbmc / win32 / dirent.h
1 /*
2  * dirent.h - dirent API for Microsoft Visual Studio
3  *
4  * Copyright (C) 2006-2012 Toni Ronkko
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * ``Software''), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  *
25  *
26  * Version 1.13, Dec 12 2012, Toni Ronkko
27  * Use traditional 8+3 file name if the name cannot be represented in the
28  * default ANSI code page.  Now compiles again with MSVC 6.0.  Thanks to
29  * Konstantin Khomoutov for testing.
30  *
31  * Version 1.12.1, Oct 1 2012, Toni Ronkko
32  * Bug fix: renamed wide-character DIR structure _wDIR to _WDIR (with
33  * capital W) in order to maintain compatibility with MingW.
34  *
35  * Version 1.12, Sep 30 2012, Toni Ronkko
36  * Define PATH_MAX and NAME_MAX.  Added wide-character variants _wDIR, 
37  * _wdirent, _wopendir(), _wreaddir(), _wclosedir() and _wrewinddir().
38  * Thanks to Edgar Buerkle and Jan Nijtmans for ideas and code.
39  *
40  * Do not include windows.h.  This allows dirent.h to be integrated more
41  * easily into programs using winsock.  Thanks to Fernando Azaldegui.
42  *
43  * Version 1.11, Mar 15, 2011, Toni Ronkko
44  * Defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0.
45  *
46  * Version 1.10, Aug 11, 2010, Toni Ronkko
47  * Added d_type and d_namlen fields to dirent structure.  The former is
48  * especially useful for determining whether directory entry represents a
49  * file or a directory.  For more information, see
50  * http://www.delorie.com/gnu/docs/glibc/libc_270.html
51  *
52  * Improved conformance to the standards.  For example, errno is now set
53  * properly on failure and assert() is never used.  Thanks to Peter Brockam
54  * for suggestions.
55  *
56  * Fixed a bug in rewinddir(): when using relative directory names, change
57  * of working directory no longer causes rewinddir() to fail.
58  *
59  * Version 1.9, Dec 15, 2009, John Cunningham
60  * Added rewinddir member function
61  *
62  * Version 1.8, Jan 18, 2008, Toni Ronkko
63  * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string
64  * between multi-byte and unicode representations.  This makes the
65  * code simpler and also allows the code to be compiled under MingW.  Thanks
66  * to Azriel Fasten for the suggestion.
67  *
68  * Mar 4, 2007, Toni Ronkko
69  * Bug fix: due to the strncpy_s() function this file only compiled in
70  * Visual Studio 2005.  Using the new string functions only when the
71  * compiler version allows.
72  *
73  * Nov  2, 2006, Toni Ronkko
74  * Major update: removed support for Watcom C, MS-DOS and Turbo C to
75  * simplify the file, updated the code to compile cleanly on Visual
76  * Studio 2005 with both unicode and multi-byte character strings,
77  * removed rewinddir() as it had a bug.
78  *
79  * Aug 20, 2006, Toni Ronkko
80  * Removed all remarks about MSVC 1.0, which is antiqued now.  Simplified
81  * comments by removing SGML tags.
82  *
83  * May 14 2002, Toni Ronkko
84  * Embedded the function definitions directly to the header so that no
85  * source modules need to be included in the Visual Studio project.  Removed
86  * all the dependencies to other projects so that this header file can be
87  * used independently.
88  *
89  * May 28 1998, Toni Ronkko
90  * First version.
91  *****************************************************************************/
92 #ifndef DIRENT_H
93 #define DIRENT_H
94
95 #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86)
96 #   define _X86_
97 #endif
98 #include <stdio.h>
99 #include <stdarg.h>
100 #include <windef.h>
101 #include <winbase.h>
102 #include <wchar.h>
103 #include <string.h>
104 #include <stdlib.h>
105 #include <malloc.h>
106 #include <sys/types.h>
107 #include <sys/stat.h>
108 #include <errno.h>
109
110 /* Indicates that d_type field is available in dirent structure */
111 #define _DIRENT_HAVE_D_TYPE
112
113 /* Indicates that d_namlen field is available in dirent structure */
114 #define _DIRENT_HAVE_D_NAMLEN
115
116 /* Entries missing from MSVC 6.0 */
117 #if !defined(FILE_ATTRIBUTE_DEVICE)
118 #   define FILE_ATTRIBUTE_DEVICE 0x40
119 #endif
120
121 /* File type and permission flags for stat() */
122 #if !defined(S_IFMT)
123 #   define S_IFMT   _S_IFMT                     /* File type mask */
124 #endif
125 #if !defined(S_IFDIR)
126 #   define S_IFDIR  _S_IFDIR                    /* Directory */
127 #endif
128 #if !defined(S_IFCHR)
129 #   define S_IFCHR  _S_IFCHR                    /* Character device */
130 #endif
131 #if !defined(S_IFFIFO)
132 #   define S_IFFIFO _S_IFFIFO                   /* Pipe */
133 #endif
134 #if !defined(S_IFREG)
135 #   define S_IFREG  _S_IFREG                    /* Regular file */
136 #endif
137 #if !defined(S_IREAD)
138 #   define S_IREAD  _S_IREAD                    /* Read permission */
139 #endif
140 #if !defined(S_IWRITE)
141 #   define S_IWRITE _S_IWRITE                   /* Write permission */
142 #endif
143 #if !defined(S_IEXEC)
144 #   define S_IEXEC  _S_IEXEC                    /* Execute permission */
145 #endif
146 #if !defined(S_IFIFO)
147 #   define S_IFIFO _S_IFIFO                     /* Pipe */
148 #endif
149 #if !defined(S_IFBLK)
150 #   define S_IFBLK   0                          /* Block device */
151 #endif
152 #if !defined(S_IFLNK)
153 #   define S_IFLNK   0                          /* Link */
154 #endif
155 #if !defined(S_IFSOCK)
156 #   define S_IFSOCK  0                          /* Socket */
157 #endif
158
159 #if defined(_MSC_VER)
160 #   define S_IRUSR  S_IREAD                     /* Read user */
161 #   define S_IWUSR  S_IWRITE                    /* Write user */
162 #   define S_IXUSR  0                           /* Execute user */
163 #   define S_IRGRP  0                           /* Read group */
164 #   define S_IWGRP  0                           /* Write group */
165 #   define S_IXGRP  0                           /* Execute group */
166 #   define S_IROTH  0                           /* Read others */
167 #   define S_IWOTH  0                           /* Write others */
168 #   define S_IXOTH  0                           /* Execute others */
169 #endif
170
171 /* Maximum length of file name */
172 #if !defined(PATH_MAX)
173 #   define PATH_MAX MAX_PATH
174 #endif
175 #if !defined(FILENAME_MAX)
176 #   define FILENAME_MAX MAX_PATH
177 #endif
178 #if !defined(NAME_MAX)
179 #   define NAME_MAX FILENAME_MAX
180 #endif
181
182 /* File type flags for d_type */
183 #define DT_UNKNOWN  0
184 #define DT_REG      S_IFREG
185 #define DT_DIR      S_IFDIR
186 #define DT_FIFO     S_IFIFO
187 #define DT_SOCK     S_IFSOCK
188 #define DT_CHR      S_IFCHR
189 #define DT_BLK      S_IFBLK
190
191 /* Macros for converting between st_mode and d_type */
192 #define IFTODT(mode) ((mode) & S_IFMT)
193 #define DTTOIF(type) (type)
194
195 /*
196  * File type macros.  Note that block devices, sockets and links cannot be
197  * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
198  * only defined for compatibility.  These macros should always return false
199  * on Windows.
200  */
201 #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
202 #define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
203 #define S_ISREG(mode)  (((mode) & S_IFMT) == S_IFREG)
204 #define S_ISLNK(mode)  (((mode) & S_IFMT) == S_IFLNK)
205 #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
206 #define S_ISCHR(mode)  (((mode) & S_IFMT) == S_IFCHR)
207 #define S_ISBLK(mode)  (((mode) & S_IFMT) == S_IFBLK)
208
209 /* Return the exact length of d_namlen without zero terminator */
210 #define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
211
212 /* Return number of bytes needed to store d_namlen */
213 #define _D_ALLOC_NAMLEN(p) (PATH_MAX + 1)
214
215
216 #ifdef __cplusplus
217 extern "C" {
218 #endif
219
220
221 /* Wide-character version */
222 struct _wdirent {
223     long d_ino;                                 /* Always zero */
224     unsigned short d_reclen;                    /* Structure size */
225     size_t d_namlen;                            /* Length of name without \0 */
226     int d_type;                                 /* File type */
227     wchar_t d_name[PATH_MAX + 1];               /* File name */
228 };
229 typedef struct _wdirent _wdirent;
230
231 struct _WDIR {
232     struct _wdirent ent;                        /* Current directory entry */
233     WIN32_FIND_DATAW data;                      /* Private file data */
234     int cached;                                 /* True if data is valid */
235     HANDLE handle;                              /* Win32 search handle */
236     wchar_t *patt;                              /* Initial directory name */
237 };
238 typedef struct _WDIR _WDIR;
239
240 static _WDIR *_wopendir (const wchar_t *dirname);
241 static struct _wdirent *_wreaddir (_WDIR *dirp);
242 static int _wclosedir (_WDIR *dirp);
243 static void _wrewinddir (_WDIR* dirp);
244
245
246 /* For compatibility with Symbian */
247 #define wdirent _wdirent
248 #define WDIR _WDIR
249 #define wopendir _wopendir
250 #define wreaddir _wreaddir
251 #define wclosedir _wclosedir
252 #define wrewinddir _wrewinddir
253
254
255 /* Multi-byte character versions */
256 struct dirent {
257     long d_ino;                                 /* Always zero */
258     unsigned short d_reclen;                    /* Structure size */
259     size_t d_namlen;                            /* Length of name without \0 */
260     int d_type;                                 /* File type */
261     char d_name[PATH_MAX + 1];                  /* File name */
262 };
263 typedef struct dirent dirent;
264
265 struct DIR {
266     struct dirent ent;
267     struct _WDIR *wdirp;
268 };
269 typedef struct DIR DIR;
270
271 static DIR *opendir (const char *dirname);
272 static struct dirent *readdir (DIR *dirp);
273 static int closedir (DIR *dirp);
274 static void rewinddir (DIR* dirp);
275
276
277 /* Internal utility functions */
278 static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
279 static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
280
281 static int dirent_mbstowcs_s(
282     size_t *pReturnValue,
283     wchar_t *wcstr,
284     size_t sizeInWords,
285     const char *mbstr,
286     size_t count);
287
288 static int dirent_wcstombs_s(
289     size_t *pReturnValue,
290     char *mbstr,
291     size_t sizeInBytes,
292     const wchar_t *wcstr,
293     size_t count);
294
295 static void dirent_set_errno (int error);
296
297 /*
298  * Open directory stream DIRNAME for read and return a pointer to the
299  * internal working area that is used to retrieve individual directory
300  * entries.
301  */
302 static _WDIR*
303 _wopendir(
304     const wchar_t *dirname)
305 {
306     _WDIR *dirp = NULL;
307     int error;
308
309     /* Must have directory name */
310     if (dirname == NULL  ||  dirname[0] == '\0') {
311         dirent_set_errno (ENOENT);
312         return NULL;
313     }
314
315     /* Allocate new _WDIR structure */
316     dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
317     if (dirp != NULL) {
318         DWORD n;
319
320         /* Reset _WDIR structure */
321         dirp->handle = INVALID_HANDLE_VALUE;
322         dirp->patt = NULL;
323         dirp->cached = 0;
324
325         /* Compute the length of full path plus zero terminator */
326         n = GetFullPathNameW (dirname, 0, NULL, NULL);
327
328         /* Allocate room for absolute directory name and search pattern */
329         dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
330         if (dirp->patt) {
331
332             /*
333              * Convert relative directory name to an absolute one.  This
334              * allows rewinddir() to function correctly even when current
335              * working directory is changed between opendir() and rewinddir().
336              */
337             n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
338             if (n > 0) {
339                 wchar_t *p;
340
341                 /* Append search pattern \* to the directory name */
342                 p = dirp->patt + n;
343                 if (dirp->patt < p) {
344                     switch (p[-1]) {
345                     case '\\':
346                     case '/':
347                     case ':':
348                         /* Directory ends in path separator, e.g. c:\temp\ */
349                         /*NOP*/;
350                         break;
351
352                     default:
353                         /* Directory name doesn't end in path separator */
354                         *p++ = '\\';
355                     }
356                 }
357                 *p++ = '*';
358                 *p = '\0';
359
360                 /* Open directory stream and retrieve the first entry */
361                 if (dirent_first (dirp)) {
362                     /* Directory stream opened successfully */
363                     error = 0;
364                 } else {
365                     /* Cannot retrieve first entry */
366                     error = 1;
367                     dirent_set_errno (ENOENT);
368                 }
369
370             } else {
371                 /* Cannot retrieve full path name */
372                 dirent_set_errno (ENOENT);
373                 error = 1;
374             }
375
376         } else {
377             /* Cannot allocate memory for search pattern */
378             error = 1;
379         }
380
381     } else {
382         /* Cannot allocate _WDIR structure */
383         error = 1;
384     }
385
386     /* Clean up in case of error */
387     if (error  &&  dirp) {
388         _wclosedir (dirp);
389         dirp = NULL;
390     }
391
392     return dirp;
393 }
394
395 /*
396  * Read next directory entry.  The directory entry is returned in dirent
397  * structure in the d_name field.  Individual directory entries returned by
398  * this function include regular files, sub-directories, pseudo-directories
399  * "." and ".." as well as volume labels, hidden files and system files.
400  */
401 static struct _wdirent*
402 _wreaddir(
403     _WDIR *dirp)
404 {
405     WIN32_FIND_DATAW *datap;
406     struct _wdirent *entp;
407
408     /* Read next directory entry */
409     datap = dirent_next (dirp);
410     if (datap) {
411         size_t n;
412         DWORD attr;
413         
414         /* Pointer to directory entry to return */
415         entp = &dirp->ent;
416
417         /* 
418          * Copy file name as wide-character string.  If the file name is too
419          * long to fit in to the destination buffer, then truncate file name
420          * to PATH_MAX characters and zero-terminate the buffer.
421          */
422         n = 0;
423         while (n < PATH_MAX  &&  datap->cFileName[n] != 0) {
424             entp->d_name[n] = datap->cFileName[n];
425             n++;
426         }
427         dirp->ent.d_name[n] = 0;
428
429         /* Length of file name excluding zero terminator */
430         entp->d_namlen = n;
431
432         /* File type */
433         attr = datap->dwFileAttributes;
434         if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
435             entp->d_type = DT_CHR;
436         } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
437             entp->d_type = DT_DIR;
438         } else {
439             entp->d_type = DT_REG;
440         }
441
442         /* Reset dummy fields */
443         entp->d_ino = 0;
444         entp->d_reclen = sizeof (struct _wdirent);
445
446     } else {
447
448         /* Last directory entry read */
449         entp = NULL;
450
451     }
452
453     return entp;
454 }
455
456 /*
457  * Close directory stream opened by opendir() function.  This invalidates the
458  * DIR structure as well as any directory entry read previously by
459  * _wreaddir().
460  */
461 static int
462 _wclosedir(
463     _WDIR *dirp)
464 {
465     int ok;
466     if (dirp) {
467
468         /* Release search handle */
469         if (dirp->handle != INVALID_HANDLE_VALUE) {
470             FindClose (dirp->handle);
471             dirp->handle = INVALID_HANDLE_VALUE;
472         }
473
474         /* Release search pattern */
475         if (dirp->patt) {
476             free (dirp->patt);
477             dirp->patt = NULL;
478         }
479
480         /* Release directory structure */
481         free (dirp);
482         ok = /*success*/0;
483
484     } else {
485         /* Invalid directory stream */
486         dirent_set_errno (EBADF);
487         ok = /*failure*/-1;
488     }
489     return ok;
490 }
491
492 /*
493  * Rewind directory stream such that _wreaddir() returns the very first
494  * file name again.
495  */
496 static void
497 _wrewinddir(
498     _WDIR* dirp)
499 {
500     if (dirp) {
501         /* Release existing search handle */
502         if (dirp->handle != INVALID_HANDLE_VALUE) {
503             FindClose (dirp->handle);
504         }
505
506         /* Open new search handle */
507         dirent_first (dirp);
508     }
509 }
510
511 /* Get first directory entry (internal) */
512 static WIN32_FIND_DATAW*
513 dirent_first(
514     _WDIR *dirp)
515 {
516     WIN32_FIND_DATAW *datap;
517
518     /* Open directory and retrieve the first entry */
519     dirp->handle = FindFirstFileW (dirp->patt, &dirp->data);
520     if (dirp->handle != INVALID_HANDLE_VALUE) {
521
522         /* a directory entry is now waiting in memory */
523         datap = &dirp->data;
524         dirp->cached = 1;
525
526     } else {
527
528         /* Failed to re-open directory: no directory entry in memory */
529         dirp->cached = 0;
530         datap = NULL;
531
532     }
533     return datap;
534 }
535
536 /* Get next directory entry (internal) */
537 static WIN32_FIND_DATAW*
538 dirent_next(
539     _WDIR *dirp)
540 {
541     WIN32_FIND_DATAW *p;
542
543     /* Get next directory entry */
544     if (dirp->cached != 0) {
545
546         /* A valid directory entry already in memory */
547         p = &dirp->data;
548         dirp->cached = 0;
549
550     } else if (dirp->handle != INVALID_HANDLE_VALUE) {
551
552         /* Get the next directory entry from stream */
553         if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
554             /* Got a file */
555             p = &dirp->data;
556         } else {
557             /* The very last entry has been processed or an error occured */
558             FindClose (dirp->handle);
559             dirp->handle = INVALID_HANDLE_VALUE;
560             p = NULL;
561         }
562
563     } else {
564
565         /* End of directory stream reached */
566         p = NULL;
567
568     }
569
570     return p;
571 }
572
573 /* 
574  * Open directory stream using plain old C-string.
575  */
576 static DIR*
577 opendir(
578     const char *dirname) 
579 {
580     struct DIR *dirp;
581     int error;
582
583     /* Must have directory name */
584     if (dirname == NULL  ||  dirname[0] == '\0') {
585         dirent_set_errno (ENOENT);
586         return NULL;
587     }
588
589     /* Allocate memory for DIR structure */
590     dirp = (DIR*) malloc (sizeof (struct DIR));
591     if (dirp) {
592         wchar_t wname[PATH_MAX + 1];
593         size_t n;
594
595         /* Convert directory name to wide-character string */
596         error = dirent_mbstowcs_s(
597             &n, wname, PATH_MAX + 1, dirname, PATH_MAX);
598         if (!error) {
599
600             /* Open directory stream using wide-character name */
601             dirp->wdirp = _wopendir (wname);
602             if (dirp->wdirp) {
603                 /* Directory stream opened */
604                 error = 0;
605             } else {
606                 /* Failed to open directory stream */
607                 error = 1;
608             }
609
610         } else {
611             /* 
612              * Cannot convert file name to wide-character string.  This
613              * occurs if the string contains invalid multi-byte sequences or
614              * the output buffer is too small to contain the resulting
615              * string.
616              */
617             error = 1;
618         }
619
620     } else {
621         /* Cannot allocate DIR structure */
622         error = 1;
623     }
624
625     /* Clean up in case of error */
626     if (error  &&  dirp) {
627         free (dirp);
628         dirp = NULL;
629     }
630
631     return dirp;
632 }
633
634 /*
635  * Read next directory entry.
636  *
637  * When working with text consoles, please note that file names returned by
638  * readdir() are represented in the default ANSI code page while any output to
639  * console is typically formatted on another code page.  Thus, non-ASCII
640  * characters in file names will not usually display correctly on console.  The
641  * problem can be fixed in two ways: (1) change the character set of console
642  * to 1252 using chcp utility and use Lucida Console font, or (2) use
643  * _cprintf function when writing to console.  The _cprinf() will re-encode
644  * ANSI strings to the console code page so many non-ASCII characters will
645  * display correcly.
646  */
647 static struct dirent*
648 readdir(
649     DIR *dirp) 
650 {
651     WIN32_FIND_DATAW *datap;
652     struct dirent *entp;
653
654     /* Read next directory entry */
655     datap = dirent_next (dirp->wdirp);
656     if (datap) {
657         size_t n;
658         int error;
659
660         /* Attempt to convert file name to multi-byte string */
661         error = dirent_wcstombs_s(
662             &n, dirp->ent.d_name, MAX_PATH + 1, datap->cFileName, MAX_PATH);
663
664         /* 
665          * If the file name cannot be represented by a multi-byte string,
666          * then attempt to use old 8+3 file name.  This allows traditional
667          * Unix-code to access some file names despite of unicode
668          * characters, although file names may seem unfamiliar to the user.
669          *
670          * Be ware that the code below cannot come up with a short file
671          * name unless the file system provides one.  At least
672          * VirtualBox shared folders fail to do this.
673          */
674         if (error  &&  datap->cAlternateFileName[0] != '\0') {
675             error = dirent_wcstombs_s(
676                 &n, dirp->ent.d_name, MAX_PATH + 1, datap->cAlternateFileName,
677                 sizeof (datap->cAlternateFileName) / 
678                     sizeof (datap->cAlternateFileName[0]));
679         }
680
681         if (!error) {
682             DWORD attr;
683
684             /* Initialize directory entry for return */
685             entp = &dirp->ent;
686
687             /* Length of file name excluding zero terminator */
688             entp->d_namlen = n - 1;
689
690             /* File attributes */
691             attr = datap->dwFileAttributes;
692             if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
693                 entp->d_type = DT_CHR;
694             } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
695                 entp->d_type = DT_DIR;
696             } else {
697                 entp->d_type = DT_REG;
698             }
699
700             /* Reset dummy fields */
701             entp->d_ino = 0;
702             entp->d_reclen = sizeof (struct dirent);
703
704         } else {
705             /* 
706              * Cannot convert file name to multi-byte string so construct
707              * an errornous directory entry and return that.  Note that
708              * we cannot return NULL as that would stop the processing
709              * of directory entries completely.
710              */
711             entp = &dirp->ent;
712             entp->d_name[0] = '?';
713             entp->d_name[1] = '\0';
714             entp->d_namlen = 1;
715             entp->d_type = DT_UNKNOWN;
716             entp->d_ino = 0;
717             entp->d_reclen = 0;
718         }
719
720     } else {
721         /* No more directory entries */
722         entp = NULL;
723     }
724
725     return entp;
726 }
727
728 /*
729  * Close directory stream.
730  */
731 static int
732 closedir(
733     DIR *dirp) 
734 {
735     int ok;
736     if (dirp) {
737
738         /* Close wide-character directory stream */
739         ok = _wclosedir (dirp->wdirp);
740         dirp->wdirp = NULL;
741
742         /* Release multi-byte character version */
743         free (dirp);
744
745     } else {
746
747         /* Invalid directory stream */
748         dirent_set_errno (EBADF);
749         ok = /*failure*/-1;
750
751     }
752     return ok;
753 }
754
755 /*
756  * Rewind directory stream to beginning.
757  */
758 static void
759 rewinddir(
760     DIR* dirp) 
761 {
762     /* Rewind wide-character string directory stream */
763     _wrewinddir (dirp->wdirp);
764 }
765
766 /* Convert multi-byte string to wide character string */
767 static int
768 dirent_mbstowcs_s(
769     size_t *pReturnValue,
770     wchar_t *wcstr,
771     size_t sizeInWords,
772     const char *mbstr,
773     size_t count)
774 {
775     int error;
776
777 #if defined(_MSC_VER)  &&  _MSC_VER >= 1400
778
779     /* Microsoft Visual Studio 2005 or later */
780     error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
781
782 #else
783
784     /* Older Visual Studio or non-Microsoft compiler */
785     size_t n;
786
787     /* Convert to wide-character string */
788     n = mbstowcs (wcstr, mbstr, count);
789     if (n < sizeInWords) {
790
791         /* Zero-terminate output buffer */
792         if (wcstr) {
793             wcstr[n] = 0;
794         }
795
796         /* Length of resuting multi-byte string WITH zero terminator */
797         if (pReturnValue) {
798             *pReturnValue = n + 1;
799         }
800
801         /* Success */
802         error = 0;
803
804     } else {
805
806         /* Could not convert string */
807         error = 1;
808
809     }
810
811 #endif
812
813     return error;
814 }
815
816 /* Convert wide-character string to multi-byte string */
817 static int
818 dirent_wcstombs_s(
819     size_t *pReturnValue,
820     char *mbstr,
821     size_t sizeInBytes,
822     const wchar_t *wcstr,
823     size_t count)
824 {
825     int error;
826
827 #if defined(_MSC_VER)  &&  _MSC_VER >= 1400
828
829     /* Microsoft Visual Studio 2005 or later */
830     error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
831
832 #else
833
834     /* Older Visual Studio or non-Microsoft compiler */
835     size_t n;
836
837     /* Convert to multi-byte string */
838     n = wcstombs (mbstr, wcstr, count);
839     if (n < sizeInBytes) {
840
841         /* Zero-terminate output buffer */
842         if (mbstr) {
843             mbstr[n] = '\0';
844         }
845
846         /* Lenght of resulting multi-bytes string WITH zero-terminator */
847         if (pReturnValue) {
848             *pReturnValue = n + 1;
849         }
850
851         /* Success */
852         error = 0;
853
854     } else {
855
856         /* Cannot convert string */
857         error = 1;
858
859     }
860
861 #endif
862
863     return error;
864 }
865
866 /* Set errno variable */
867 static void
868 dirent_set_errno(
869     int error)
870 {
871 #if defined(_MSC_VER)
872
873     /* Microsoft Visual Studio */
874     _set_errno (error);
875
876 #else
877
878     /* Non-Microsoft compiler */
879     errno = error;
880
881 #endif
882 }
883
884
885 #ifdef __cplusplus
886 }
887 #endif
888 #endif /*DIRENT_H*/
889