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