compiler: Added (u)intsize to map to size_t; Updated C prototypes to use it; Fixed...
[sdk] / ecere / src / sys / File.c
1 #undef __BLOCKS__
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdarg.h>
5 #include <ctype.h>
6
7 #if defined(__GNUC__) || defined(__WATCOMC__) || defined(__WIN32__)
8 #include <time.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #endif
13
14 #if defined(__unix__) || defined(__APPLE__)
15 #include <utime.h>
16 #endif
17
18 #if defined(__WIN32__)
19 #define WIN32_LEAN_AND_MEAN
20 #define UNICODE
21 #include <windows.h>
22 #include <io.h>
23
24 #else
25 #include <unistd.h>
26 #endif
27
28 typedef int bool;
29 typedef unsigned char byte;
30 typedef unsigned short uint16;
31 typedef unsigned int uint;
32 typedef unsigned int FileSize;
33 typedef long long int64;
34 typedef unsigned long long uint64;
35
36 #define false 0
37 #define true 1
38
39 #define null ((void *)0)
40
41 #define MAX_LOCATION 797
42 #define MAX_FILENAME 274
43
44 void __ecereNameSpace__ecere__com__eSystem_Delete(void * memory);
45 void * __ecereNameSpace__ecere__com__eSystem_New0(unsigned int size);
46 void * __ecereNameSpace__ecere__com__eSystem_Renew(void * memory, unsigned int size);
47 void * __ecereNameSpace__ecere__com__eSystem_Renew0(void * memory, unsigned int size);
48 unsigned short * __ecereNameSpace__ecere__sys__UTF8toUTF16(char * source, int * wordCount);
49 unsigned short * __ecereNameSpace__ecere__sys__UTF8toUTF16Buffer(char * source, uint16 * dest, int max);
50 char * __ecereNameSpace__ecere__sys__UTF16toUTF8(uint16 * source);
51
52 #if defined(__WIN32__) || defined(__WATCOMC__)
53 #include <direct.h>
54 __declspec(dllimport) BOOL WINAPI GetVolumePathName(LPCTSTR lpszFileName,LPTSTR lpszVolumePathName,DWORD cchBufferLength);
55 #else
56 #include <dirent.h>
57 #endif
58
59 typedef unsigned int FileAttribs;
60 typedef int64 SecSince1970;
61 typedef SecSince1970 TimeStamp;
62
63 typedef enum
64 {
65    FOM_read = 1,
66    FOM_write,
67    FOM_append,
68    FOM_readWrite,
69    FOM_writeRead,
70    FOM_appendRead
71 } FileOpenMode;
72
73 typedef enum
74 {
75    unlocked = 0,     // LOCK_UN  _SH_DENYNO
76    shared = 1,       // LOCK_SH  _SH_DENYWR
77    exclusive = 2     // LOCK_EX  _SH_DENYRW
78 } FileLock;
79
80 #define isFile       0x0001
81 #define isArchive    0x0002
82 #define isHidden     0x0004
83 #define isReadOnly   0x0008
84 #define isSystem     0x0010
85 #define isTemporary  0x0020
86 #define isDirectory  0x0040
87 #define isDrive      0x0080
88 #define isCDROM      0x0100
89 #define isRemote     0x0200
90 #define isRemovable  0x0400
91 #define isServer     0x0800
92 #define isShare      0x1000
93
94 typedef struct
95 {
96    FileAttribs attribs;
97    FileSize size;
98    SecSince1970 accessed;
99    SecSince1970 modified;
100    SecSince1970 created;
101 } FileStats;
102
103 char * __ecereNameSpace__ecere__sys__GetLastDirectory(char * string, char * output);
104 bool __ecereNameSpace__ecere__sys__SplitArchivePath(char * fileName, char * archiveName, char ** archiveFile);
105
106 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
107 void __ecereMethod___ecereNameSpace__ecere__sys__EARFileSystem_FixCase(char * archive, char * name);
108
109 static BOOL CALLBACK EnumThreadWindowsProc(HWND hwnd, LPARAM lParam)
110 {
111    DWORD pid;
112    if(IsWindowVisible(hwnd) && GetWindowThreadProcessId(hwnd, &pid) && pid == GetCurrentProcessId())
113    {      
114       *(void **)lParam = hwnd;
115       return FALSE;
116    }
117    return TRUE;   
118 }
119 bool WinReviveNetworkResource(uint16 * _wfileName)
120 {
121    bool result = false;
122    HWND windowHandle = null;
123    NETRESOURCE nr = { 0 };
124    nr.dwType = RESOURCETYPE_DISK;
125    nr.lpRemoteName = _wfileName;
126    if(_wfileName[0] != '\\' || _wfileName[1] == '\\')
127    {
128       uint16 volumePathName[MAX_LOCATION];
129       if(GetVolumePathName(_wfileName, volumePathName, MAX_LOCATION))
130       {
131          uint16 remoteName[MAX_LOCATION];
132          DWORD size = MAX_LOCATION;
133          volumePathName[wcslen(volumePathName)-1] = 0;
134          if(WNetGetConnection(volumePathName, remoteName, &size) == ERROR_CONNECTION_UNAVAIL)
135          {
136             nr.lpRemoteName = remoteName;
137             nr.lpLocalName = volumePathName;
138          }
139          else
140             return false;
141       }
142       else
143          return false;
144    }
145    EnumThreadWindows(GetCurrentThreadId(), EnumThreadWindowsProc, (LPARAM)&windowHandle);
146    if(!windowHandle)
147    {
148       EnumWindows(EnumThreadWindowsProc, (LPARAM)&windowHandle);
149       
150    }
151    if(WNetAddConnection3(windowHandle, &nr, null, null, CONNECT_INTERACTIVE|CONNECT_PROMPT) == NO_ERROR)
152       result = true;
153    return result;
154 }
155
156 TimeStamp Win32FileTimeToTimeStamp(FILETIME * fileTime);
157 void TimeStampToWin32FileTime(TimeStamp t, FILETIME * fileTime);
158
159 #endif
160
161 uint FILE_GetSize(FILE * input)
162 {
163    if(input)
164    {
165       struct stat s;
166       int fd = fileno(input);
167       if(!fstat(fd, &s))
168          return s.st_size;
169    }
170    return 0;
171 }
172
173 bool FILE_Lock(FILE * input, FILE * output, FileLock type, uint64 start, uint64 length, bool wait)
174 {
175    if(!output && !input)
176       return true;
177    else
178    {
179 #if defined(__WIN32__)
180       int handle = fileno(output ? output : input);
181       HANDLE hFile = (HANDLE)_get_osfhandle(handle);
182       OVERLAPPED overlapped = { 0 };
183       overlapped.Offset = (uint)(start & 0xFFFFFFFF);
184       overlapped.OffsetHigh = (uint)((start & 0xFFFFFFFF00000000LL) >> 32);
185       if(type ==  unlocked)
186          return UnlockFileEx(hFile, 0,
187             (uint)(length ? (length & 0xFFFFFFFF) : 0xFFFFFFFF),
188             (uint)(length ? ((length & 0xFFFFFFFF00000000LL) >> 32) : 0xFFFFFFFF),
189             &overlapped) != 0;
190       else
191          return LockFileEx(hFile, ((type == exclusive) ? LOCKFILE_EXCLUSIVE_LOCK : 0) | (wait ? 0 : LOCKFILE_FAIL_IMMEDIATELY), 0, 
192             (uint)(length ? (length & 0xFFFFFFFF) : 0xFFFFFFFF),
193             (uint)(length ? ((length & 0xFFFFFFFF00000000LL) >> 32) : 0xFFFFFFFF),
194             &overlapped) != 0;
195 #else
196       struct flock fl;
197       int fd;
198
199       fl.l_type   = (type == unlocked) ? F_UNLCK : ((type == exclusive) ? F_WRLCK : F_RDLCK);
200       fl.l_whence = SEEK_SET;
201       fl.l_start  = start;
202       fl.l_len    = length;
203       fl.l_pid    = getpid();
204
205       fd = fileno(output ? output : input);
206       return fcntl(fd, wait ? F_SETLKW : F_SETLK, &fl) != -1;
207 #endif      
208    }
209 }
210
211 void FILE_set_buffered(FILE * input, FILE * output, bool value)
212 {
213 #if !defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
214    if(input)
215       setvbuf(input, null, value ? _IOFBF : _IONBF, 0);
216    if(output && output != input)
217       setvbuf(output, null, value ? _IOFBF : _IONBF, 0);
218 #endif
219 }
220
221 FileAttribs FILE_FileExists(char * fileName)
222 {
223 #ifdef __WIN32__
224    FileAttribs result = 0;
225    uint attribute = 0;  // Initialization isn't actually required here but GCC complains about it.
226    uint16 * _wfileName = __ecereNameSpace__ecere__sys__UTF8toUTF16(fileName, null);
227    if(!strcmp(fileName, "/") || !strcmp(fileName, "\\\\"))
228    {
229       result = (FileAttribs)(isDirectory);
230    }
231    else
232       attribute = GetFileAttributes(_wfileName);
233 #if !defined(ECERE_BOOTSTRAP)
234    if(!result && attribute == 0xFFFFFFFF)
235    {
236       if(WinReviveNetworkResource(_wfileName))
237          attribute = GetFileAttributes(_wfileName);
238       if(attribute == 0xFFFFFFFF)
239       {
240          if(fileName[0] == '\\' && fileName[1] == '\\')
241          {
242             NETRESOURCE nr = { 0 };
243             NETRESOURCE * buffer = null;
244             unsigned int size = sizeof(NETRESOURCE);
245             uint16 * dir;
246
247             nr.dwScope       = RESOURCE_GLOBALNET;
248             nr.dwType        = RESOURCETYPE_DISK;
249             nr.lpRemoteName  = _wfileName;
250             nr.lpProvider = L"Microsoft Windows Network";
251
252             buffer = (NETRESOURCE *)__ecereNameSpace__ecere__com__eSystem_New0(size);
253             while(true)
254             {
255                int returnCode = WNetGetResourceInformationW(&nr, buffer, (DWORD *)&size, &dir);
256                if(returnCode == WN_MORE_DATA)
257                   buffer = (NETRESOURCE *)__ecereNameSpace__ecere__com__eSystem_Renew0(buffer, size);
258                else
259                {
260                   if(returnCode == WN_SUCCESS)
261                   {
262                      if(!_wcsicmp(buffer->lpRemoteName, _wfileName))
263                         result = (FileAttribs)( isDirectory | isServer );
264                   }
265                   break;
266                }
267             }
268             __ecereNameSpace__ecere__com__eSystem_Delete(buffer);
269          }
270       }
271    }
272 #endif
273    if(!result && attribute != 0xFFFFFFFF)
274    {
275       if(attribute & FILE_ATTRIBUTE_DIRECTORY)
276          result = (FileAttribs)( isDirectory );
277       else
278          result = (FileAttribs)(isFile);
279    }
280    __ecereNameSpace__ecere__com__eSystem_Delete(_wfileName);
281    return result;
282 #else
283    if(!access(fileName, F_OK))
284    {
285       struct stat s;
286       stat(fileName, &s);
287       return S_ISDIR(s.st_mode) ? (FileAttribs) ( isDirectory ) : (FileAttribs) ( isFile );
288    }
289    else
290    {
291       // TODO: Check this
292       return (FileAttribs) 0;
293    }
294 #endif
295 }
296
297 bool FILE_FileGetSize(char * fileName, FileSize * size)
298 {
299    bool result = false;
300 #if defined(__WIN32__)
301    struct _stat s;
302    uint16 * _wfileName = __ecereNameSpace__ecere__sys__UTF8toUTF16(fileName, null);
303    if(!_wstat(_wfileName, &s))
304 #else
305    struct stat s;
306    if(!stat(fileName, &s))
307 #endif
308    {
309       *size = s.st_size;
310       result = true;
311    }
312 #if defined(__WIN32__)
313    __ecereNameSpace__ecere__com__eSystem_Delete(_wfileName);
314 #endif
315    return result;
316 }
317
318 bool FILE_FileGetStats(char * fileName, FileStats * stats)
319 {
320    bool result = false;
321 #if defined(__WIN32__)
322    uint16 * _wfileName = __ecereNameSpace__ecere__sys__UTF8toUTF16(fileName, null);
323    struct _stat s;
324    if(!_wstat(_wfileName, &s))
325 #else
326    struct stat s;
327    if(!stat(fileName, &s))
328 #endif
329    {
330       stats->size = s.st_size;
331       stats->attribs = (s.st_mode & S_IFDIR) ? ((FileAttribs) (isDirectory)): ((FileAttribs) 0);
332
333 #if defined(__WIN32__)
334       {
335          HANDLE hFile = CreateFile(_wfileName, 0, FILE_SHARE_READ, null,
336             OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, null);
337          if(hFile != INVALID_HANDLE_VALUE)
338          {
339 #if defined(ECERE_BOOTSTRAP)
340             stats->created  = 0;
341             stats->accessed = 0;
342             stats->modified = 0;
343 #else
344             FILETIME c, a, m;
345             GetFileTime(hFile, &c, &a, &m);
346             stats->created  = Win32FileTimeToTimeStamp(&c);
347             stats->accessed = Win32FileTimeToTimeStamp(&a);
348             stats->modified = Win32FileTimeToTimeStamp(&m);
349 #endif
350             
351             CloseHandle(hFile);
352          }
353       }
354 #else
355       stats->accessed = s.st_atime;
356       stats->created = s.st_ctime;
357       stats->modified = s.st_mtime;
358 #endif
359 /*
360       stats->attribs.isArchive   = (winFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)   ? true : false;
361       stats->attribs.isHidden    = (winFile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)    ? true : false;
362       stats->attribs.isReadOnly  = (winFile.dwFileAttributes & FILE_ATTRIBUTE_READONLY)  ? true : false;
363       stats->attribs.isSystem    = (winFile.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)    ? true : false;
364       stats->attribs.isTemporary = (winFile.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) ? true : false;
365       stats->attribs.isDirectory = (winFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false;
366 */
367       result = true;
368    }
369 #if defined(__WIN32__)
370    __ecereNameSpace__ecere__com__eSystem_Delete(_wfileName);
371 #endif
372    return result;
373 }
374
375 void FILE_FileFixCase(char * file)
376 {
377 #if defined(__WIN32__)
378 #ifndef ECERE_BOOTSTRAP
379    char archive[MAX_LOCATION], * name;
380    if(__ecereNameSpace__ecere__sys__SplitArchivePath(file, archive, &name))
381    {
382       char fileName[MAX_LOCATION];
383       strcpy(fileName, name);
384       __ecereMethod___ecereNameSpace__ecere__sys__EARFileSystem_FixCase(archive, fileName);
385       FILE_FileFixCase(archive);
386       sprintf(file, "<%s>%s", archive, fileName);
387    }
388    else
389 #endif
390    {
391       int c = 0;
392       char parent[MAX_LOCATION] = "";
393
394       // Skip network protocols
395       if(strstr(file, "http://") == file) return;
396
397       // Copy drive letter to new path
398       if(file[0] && file[1] == ':')
399       {
400          parent[0] = (char)toupper(file[0]);
401          parent[1] = ':';
402          parent[2] = '\0';
403          c = 2;
404       }
405       // Copy Microsoft Network string to new path
406       else if(file[0] == '\\' && file[1] == '\\')
407       {
408          parent[0] = parent[1] = '\\';
409          parent[2] = '\0';
410          c = 2;
411       }
412       // Copy Entire Computer to new path
413       else if(file[0] == '/'  && !file[1])
414    
415       {
416          parent[0] = '/';
417          parent[1] = '\0';
418          c = 1;
419       }
420
421       while(file[c])
422       {
423          // Get next directory
424          char directory[MAX_FILENAME];
425          int len = 0;
426          char ch;
427          for(;(ch = file[c]) && (ch == '/' || ch == '\\'); c++);
428          for(;(ch = file[c]) && (ch != '/' && ch != '\\'); c++)
429          {
430             if(len < MAX_FILENAME)
431                directory[len++] = ch;  
432          }
433          directory[len] = '\0';
434
435          // Normal file
436          if(parent[0] != '\\' || parent[1] != '\\' || strstr(parent+2, "\\"))
437          {
438             if(strcmp(directory, "..") && strcmp(directory, "."))
439             {
440                WIN32_FIND_DATA winFile;
441                uint16 dir[MAX_PATH];
442                HANDLE handle;
443
444                __ecereNameSpace__ecere__sys__UTF8toUTF16Buffer(parent, dir, MAX_PATH);
445                if(dir[0]) wcscat(dir, L"\\");
446                {
447                   uint16 * _wdirectory = __ecereNameSpace__ecere__sys__UTF8toUTF16(directory, null);
448                   wcscat(dir, _wdirectory);
449                   __ecereNameSpace__ecere__com__eSystem_Delete(_wdirectory);
450                }
451
452                handle = FindFirstFile(dir, &winFile);
453                if(parent[0] || (file[0] == '\\' || file[0] == '/'))
454                   strcat(parent, "\\");
455                if(handle != INVALID_HANDLE_VALUE)
456                {
457                   char * utf8 = __ecereNameSpace__ecere__sys__UTF16toUTF8(winFile.cFileName);
458                   strcat(parent, utf8);
459                   __ecereNameSpace__ecere__com__eSystem_Delete(utf8);
460                   FindClose(handle);
461                }
462                else
463                   strcat(parent, directory);
464             }
465             else
466             {
467                if(parent[0] || (file[0] == '\\' || file[0] == '/'))
468                   strcat(parent, "\\");
469
470                strcat(parent, directory);
471             }
472          }
473 #ifndef ECERE_BOOTSTRAP
474          else
475          {
476             // Network server
477             if(parent[2])
478             {
479                HANDLE handle = 0;
480                DWORD count = 0xFFFFFFFF;
481                DWORD size = 512 * sizeof(NETRESOURCE);
482                NETRESOURCE * buffer = (NETRESOURCE *)__ecereNameSpace__ecere__com__eSystem_New0(size);
483                NETRESOURCE nr = {0};
484                int c;
485
486                nr.dwScope = RESOURCE_GLOBALNET;
487                nr.dwType = RESOURCETYPE_DISK;
488                // UNICODE FIX
489                nr.lpRemoteName = __ecereNameSpace__ecere__sys__UTF8toUTF16(parent, null);
490                nr.lpProvider = L"Microsoft Windows Network";
491
492                // Server
493                WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &nr, &handle);
494                if(handle)
495                {
496                   while(true)
497                   {
498                      int returnCode = WNetEnumResource(handle, &count, buffer, &size);
499                      if(returnCode != ERROR_MORE_DATA)
500                         break;
501                      count = 0xFFFFFFFF;
502                      buffer = (NETRESOURCE *)__ecereNameSpace__ecere__com__eSystem_Renew0(buffer, size);
503                   }
504                   WNetCloseEnum(handle);
505                }
506                else
507                   count = 0;
508
509                for(c = 0; c<count; c++)
510                {
511                   char shareName[MAX_FILENAME];
512                   char * remoteName = __ecereNameSpace__ecere__sys__UTF16toUTF8(buffer[c].lpRemoteName);
513                   __ecereNameSpace__ecere__sys__GetLastDirectory(remoteName, shareName);
514                   __ecereNameSpace__ecere__com__eSystem_Delete(remoteName);
515                   if(!strcmpi(directory, shareName))
516                   {
517                      strcpy(directory, shareName);
518                      break;
519                   }
520                }
521                if(c == count)
522                   strlwr(directory);
523
524                __ecereNameSpace__ecere__com__eSystem_Delete(nr.lpRemoteName);
525                __ecereNameSpace__ecere__com__eSystem_Delete(buffer);
526
527                strcat(parent, "\\");
528                strcat(parent, directory);
529             }
530             // Network share
531             else
532             {
533                strlwr(directory);
534                directory[0] = (char)toupper(directory[0]);
535                strcat(parent, directory);
536             }
537          }
538 #endif
539       }
540       strcpy(file, parent);
541    }
542 #endif
543 }
544
545 void FILE_FileOpen(char * fileName, FileOpenMode mode, FILE ** input, FILE **output)
546 {
547 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
548    uint16 * _wfileName = __ecereNameSpace__ecere__sys__UTF8toUTF16(fileName, null);
549    /*
550    file.handle = CreateFile(_wfileName,
551       ((mode == FOM_read || mode == FOM_readWrite || mode == FOM_writeRead || mode == FOM_appendRead) ? GENERIC_READ : 0) |
552       ((mode == FOM_write || mode == FOM_append || mode == FOM_readWrite || mode == FOM_writeRead || mode == FOM_appendRead) ? GENERIC_WRITE: 0),
553       FILE_SHARE_READ|FILE_SHARE_WRITE,
554       null,
555       (mode == write || mode == writeRead) ? TRUNCATE_EXISTING : ((mode == read || mode == readWrite) ? OPEN_EXISTING : OPEN_ALWAYS), 0, null);
556    if(file.handle)
557    {
558       int flags;
559       int handle;
560       switch(mode)
561       {
562          case FOM_read:       handle = _open_osfhandle((int)file.handle, _O_RDONLY); break;
563          case FOM_write:      handle = _open_osfhandle((int)file.handle, _O_WRONLY | _O_CREAT | _O_TRUNC); break;
564          case FOM_append:     handle = _open_osfhandle((int)file.handle, _O_WRONLY | _O_CREAT | _O_APPEND); break;
565          case FOM_readWrite:  handle = _open_osfhandle((int)file.handle, _O_RDWR); break;
566          case FOM_writeRead:  handle = _open_osfhandle((int)file.handle, _O_RDWR | _O_CREAT | _O_TRUNC); break;
567          case FOM_appendRead: handle = _open_osfhandle((int)file.handle, _O_RDWR | _O_APPEND | _O_CREAT); break;
568       }
569       if(handle)
570       {
571          switch(mode)
572          {
573             case FOM_read:       *input = _fdopen(handle, "rb"); break;
574             case FOM_write:      *output = _fdopen(handle, "wb"); break;
575             case FOM_append:     *output = _fdopen(handle, "ab"); break;
576             case FOM_readWrite:  *input = *output = _fdopen(handle, "r+b"); break;
577             case FOM_writeRead:  *input = *output = _fdopen(handle, "w+b"); break;
578             case FOM_appendRead: *input = *output = _fdopen(handle, "a+b"); break;
579          }
580       }
581    }
582    */
583    switch(mode)
584    {
585       case FOM_read:       *input = _wfopen(_wfileName, L"rb"); break;
586       case FOM_write:      *output = _wfopen(_wfileName, L"wb"); break;
587       case FOM_append:     *output = _wfopen(_wfileName, L"ab"); break;
588       case FOM_readWrite:  *input = *output = _wfopen(_wfileName, L"r+b"); break;
589       case FOM_writeRead:  *input = *output = _wfopen(_wfileName, L"w+b"); break;
590       case FOM_appendRead: *input = *output = _wfopen(_wfileName, L"a+b"); break;
591    }
592    if(!mode && WinReviveNetworkResource(_wfileName))
593    {
594       switch(mode)
595       {
596          case FOM_read:       *input = _wfopen(_wfileName, L"rb"); break;
597          case FOM_write:      *output = _wfopen(_wfileName, L"wb"); break;
598          case FOM_append:     *output = _wfopen(_wfileName, L"ab"); break;
599          case FOM_readWrite:  *input = *output = _wfopen(_wfileName, L"r+b"); break;
600          case FOM_writeRead:  *input = *output = _wfopen(_wfileName, L"w+b"); break;
601          case FOM_appendRead: *input = *output = _wfopen(_wfileName, L"a+b"); break;
602       }
603    }
604    __ecereNameSpace__ecere__com__eSystem_Delete(_wfileName);
605 #else
606    switch(mode)
607    {
608       case FOM_read:       *input = fopen(fileName, "rb"); break;
609       case FOM_write:      *output = fopen(fileName, "wb"); break;
610       case FOM_append:     *output = fopen(fileName, "ab"); break;
611       case FOM_readWrite:  *input = *output = fopen(fileName, "r+b"); break;
612       case FOM_writeRead:  *input = *output = fopen(fileName, "w+b"); break;
613       case FOM_appendRead: *input = *output = fopen(fileName, "a+b"); break;
614    }
615 #endif
616 }