17 #define IS_ALUNDER(ch) ((ch) == '_' || isalnum((ch)))
19 #if defined(ECERE_BOOTSTRAP)
26 #ifndef ECERE_BOOTSTRAP
27 #if defined(__GNUC__) || defined(__WATCOMC__) || defined(__WIN32__)
29 #include <sys/types.h>
34 #if defined(__unix__) || defined(__APPLE__)
38 #if defined(__WIN32__) || defined(__WATCOMC__)
44 #if defined(__WIN32__)
45 #define WIN32_LEAN_AND_MEAN
46 #define String String_
51 BOOL __declspec(dllimport) WINAPI GetVolumePathName(LPCTSTR lpszFileName,LPTSTR lpszVolumePathName,DWORD cchBufferLength);
53 // Missing function...
55 #ifndef WNetGetResourceInformation
56 DWORD APIENTRY WNetGetResourceInformationA(LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD lpcbBuffer, LPTSTR* lplpSystem);
58 #define WNetGetResourceInformation WNetGetResourceInformationW
60 #define WNetGetResourceInformation WNetGetResourceInformationA
72 #endif //#ifndef ECERE_BOOTSTRAP
82 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET) && !defined(ECERE_BOOTSTRAP)
88 // IMPLEMENTATION OF THESE IS IN _File.c
92 FILE *eC_stdout(void);
94 uint FILE_GetSize(FILE * input);
95 bool FILE_Lock(FILE * input, FILE * output, FileLock type, uint64 start, uint64 length, bool wait);
96 void FILE_set_buffered(FILE * input, FILE * output, bool value);
97 FileAttribs FILE_FileExists(const char * fileName);
98 bool FILE_FileGetSize(const char * fileName, FileSize * size);
99 bool FILE_FileGetStats(const char * fileName, FileStats stats);
100 void FILE_FileFixCase(char * file);
101 void FILE_FileOpen(const char * fileName, FileOpenMode mode, FILE ** input, FILE **output);
105 FileSystem httpFileSystem;
107 public class FileSize : uint
109 // defaultAlignment = Right;
111 void OnDisplay(Surface surface, int x, int y, int width, void * fieldData, int alignment, DataDisplayFlags displayFlags)
115 eUtils_PrintSize(string, *size, 2);
116 len = strlen(string);
117 surface.WriteTextDots(alignment, x, y, width, string, len);
120 int OnCompare(FileSize data2)
127 else if(this < data2)
133 const char * OnGetString(char * string, void * fieldData, bool * needClass)
135 PrintSize(string, this, 2);
139 bool OnGetDataFromString(const char * string)
142 double value = strtod(string, &end);
144 if(strstr(end, "GB") || strstr(end, "gb")) multiplier = (uint)1024 * 1024 * 1024;
145 else if(strstr(end, "MB") || strstr(end, "mb")) multiplier = (uint)1024 * 1024;
146 else if(strstr(end, "KB") || strstr(end, "kb")) multiplier = 1024;
148 this = (uint)(multiplier * value);
153 public class FileSize64 : uint64
155 int OnCompare(FileSize64 data2)
162 else if(this < data2)
168 const char * OnGetString(char * string, void * fieldData, bool * needClass)
170 PrintBigSize(string, this, 2);
174 bool OnGetDataFromString(const char * string)
177 double value = strtod(string, &end);
178 uint64 multiplier = 1;
179 if(strstr(end, "PB") || strstr(end, "pb")) multiplier = (uint64)1024 * 1024 * 1024 * 1024;
180 else if(strstr(end, "TB") || strstr(end, "tb")) multiplier = (uint64)1024 * 1024 * 1024 * 1024;
181 else if(strstr(end, "GB") || strstr(end, "gb")) multiplier = (uint64)1024 * 1024 * 1024;
182 else if(strstr(end, "MB") || strstr(end, "mb")) multiplier = (uint64)1024 * 1024;
183 else if(strstr(end, "KB") || strstr(end, "kb")) multiplier = 1024;
185 this = (uint64)(multiplier * value);
192 virtual File ::Open(const char * archive, const char * name, FileOpenMode mode);
195 virtual FileAttribs ::Exists(const char * archive, const char * fileName);
196 virtual bool ::GetSize(const char * archive, const char * fileName, FileSize * size);
197 virtual bool ::Stats(const char * archive, const char * fileName, FileStats stats);
198 virtual void ::FixCase(const char * archive, char * fileName);
201 virtual bool ::Find(FileDesc file, const char * archive, const char * name);
202 virtual bool ::FindNext(FileDesc file);
203 virtual void ::CloseDir(FileDesc file);
205 // Archive manipulation
206 virtual Archive ::OpenArchive(const char * fileName, ArchiveOpenFlags create);
207 virtual bool ::QuerySize(const char * fileName, FileSize * size);
210 public enum FileOpenMode { read = 1, write, append, readWrite, writeRead, appendRead };
211 public enum FileSeekMode { start, current, end };
213 #if !defined(ECERE_BOOTSTRAP)
214 static FileDialog fileDialog { text = $"Select File" };
219 unlocked = 0, // LOCK_UN _SH_DENYNO
220 shared = 1, // LOCK_SH _SH_DENYWR
221 exclusive = 2 // LOCK_EX _SH_DENYRW
224 public class File : IOChannel
226 FILE * input, * output;
228 uint ReadData(byte * bytes, uint numBytes)
230 return Read(bytes, 1, numBytes);
233 uint WriteData(const byte * bytes, uint numBytes)
235 return Write(bytes, 1, numBytes);
240 if(output && output != input)
254 bool OnGetDataFromString(const char * string)
263 File f = FileOpen(string, read);
270 uint read = f.Read(buffer, 1, sizeof(buffer));
271 Write(buffer, 1, read);
280 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
284 PrintSize(tempString, GetSize(), 2);
290 #ifndef ECERE_BOOTSTRAP
291 Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
293 Window editData = class::OnEdit(dataBox, obsolete, x + 24, y, w - 48, h, userData);
296 dataBox, inactive = true, text = $"Import"."Imp", hotKey = f2,
297 position = { Max(x + 24, x + w - 24), y }, size = { 24, h };
299 bool DataBox::NotifyClicked(Button button, int x, int y, Modifiers mods)
301 fileDialog.master = rootWindow;
302 fileDialog.filePath = "";
303 fileDialog.type = open;
305 if(fileDialog.Modal() == ok)
307 const char * filePath = fileDialog.filePath;
309 if(output.OnGetDataFromString(filePath))
311 SetData(output, false);
320 dataBox, inactive = true, text = $"Export"."Exp", hotKey = f2,
321 position = { Max(x + 24, x + w - 48), y }, size = { 24, h };
323 bool DataBox::NotifyClicked(Button button, int x, int y, Modifiers mods)
325 fileDialog.master = rootWindow;
326 fileDialog.type = save;
327 fileDialog.filePath = "";
328 if(fileDialog.Modal() == ok)
330 const char * filePath = fileDialog.filePath;
331 File f = FileOpen(filePath, write);
334 File input = *(void **)data;
335 input.Seek(0, start);
339 uint read = input.Read(buffer, 1, sizeof(buffer));
340 f.Write(buffer, 1, read);
352 #endif //#ifndef ECERE_BOOTSTRAP
354 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOARCHIVE) && !defined(ECERE_BOOTSTRAP)
355 void OnSerialize(IOChannel channel)
357 uint size = this ? GetSize() : MAXDWORD;
360 byte * uncompressed = new byte[size];
362 if(uncompressed || !size)
364 uint count = Read(uncompressed, 1, size);
367 uLongf cSize = size + size / 1000 + 12;
368 byte * compressed = new byte[cSize];
371 compress2(compressed, &cSize, uncompressed, size, 9);
373 size.OnSerialize(channel);
374 cSize.OnSerialize(channel);
375 channel.WriteData(compressed, (uint)cSize);
384 size.OnSerialize(channel);
389 size.OnSerialize(channel);
391 // Will add position...
395 for(c = 0; c<size; c += sizeof(data))
397 uint count = Read(data, 1, sizeof(data));
398 buffer.WriteData(data, count);
404 void OnUnserialize(IOChannel channel)
411 size.OnUnserialize(channel);
415 cSize.OnUnserialize(channel);
417 compressed = new byte[cSize];
420 if(channel.ReadData(compressed, cSize) == cSize)
422 byte * uncompressed = new byte[size];
423 if(uncompressed || !size)
427 uncompress(uncompressed, &size, compressed, cSize);
428 Write(uncompressed, 1, (uint)size);
442 size.OnUnserialize(channel);
446 for(c = 0; c<size; c += sizeof(data))
448 uint count = Min(size - c, sizeof(data));
449 channel.ReadData(data, count);
450 Write(data, 1, count);
463 virtual bool Seek(int pos, FileSeekMode mode)
465 uint fmode = SEEK_SET;
468 case start: fmode = SEEK_SET; break;
469 case end: fmode = SEEK_END; break;
470 case current: fmode = SEEK_CUR; break;
472 return fseek(input ? input : output, pos, fmode) != EOF;
475 virtual uint Tell(void)
477 return (uint)(input ? ftell(input) : ftell(output));
480 virtual int Read(void * buffer, uint size, uint count)
482 return input ? (int)fread(buffer, size, count, input) : 0;
485 virtual int Write(const void * buffer, uint size, uint count)
487 return output ? (int)fwrite(buffer, size, count, output) : 0;
491 virtual bool Getc(char * ch)
493 int ich = fgetc(input);
496 if(ch) *ch = (char)ich;
502 virtual bool Putc(char ch)
504 return (fputc((int)ch, output) == EOF) ? false : true;
507 virtual bool Puts(const char * string)
512 result = (fputs(string, output) == EOF) ? false : true;
513 // TODO: Check if any repercusions of commenting out fflush here
514 // This is what broke the debugger in 0.44d2 , it is required for outputting things to the DualPipe
515 // Added an explicit flush call in DualPipe::Puts
521 virtual bool Eof(void)
523 return input ? feof(input) != 0 : true;
526 virtual bool Truncate(FileSize size)
528 #ifdef ECERE_BOOTSTRAP
529 fprintf(stderr, "WARNING: File::Truncate unimplemented in ecereBootstrap.\n");
532 #if defined(__WIN32__)
533 return output ? (_chsize(fileno(output), size) == 0) : false;
535 return output ? (ftruncate(fileno(output), size) == 0) : false;
540 virtual uint GetSize(void)
542 return FILE_GetSize(input);
545 virtual void CloseInput(void)
556 virtual void CloseOutput(void)
567 virtual bool Lock(FileLock type, uint64 start, uint64 length, bool wait)
569 return FILE_Lock(input, output, type, start, length, wait);
572 virtual bool Unlock(uint64 start, uint64 length, bool wait)
574 return Lock(unlocked, start, length, wait);
578 int Printf(const char * format, ...)
583 char text[MAX_F_STRING];
585 va_start(args, format);
586 vsnprintf(text, sizeof(text), format, args);
587 text[sizeof(text)-1] = 0;
589 result = strlen(text);
595 public void PrintLn(typed_object object, ...)
599 va_start(args, object);
600 PrintStdArgsToBuffer(buffer, sizeof(buffer), object, args);
606 public void Print(typed_object object, ...)
610 va_start(args, object);
611 PrintStdArgsToBuffer(buffer, sizeof(buffer), object, args);
622 bool GetLine(char *s, int max)
638 if(/*!Peek() || */ !Getc(&ch))
650 return result || c > 1;
653 // Strings and numbers separated by spaces, commas, tabs, or CR/LF, handling quotes
654 bool GetString(char * string, int max)
669 if( (ch!='\n') && (ch!='\r') && (ch!=' ') && (ch!=',') && (ch!='\t'))
675 for(c=0; c<max-1; c++)
677 if(!quoted && ((ch=='\n')||(ch=='\r')||(ch==' ')||(ch==',')||(ch=='\t')))
705 GetString(string,sizeof(string));
709 unsigned int GetHexValue(void)
712 GetString(string, sizeof(string));
713 return (uint)strtoul(string, null, 16);
719 GetString(string, sizeof(string));
720 return (float)FloatFromString(string);
723 double GetDouble(void)
726 GetString(string, sizeof(string));
727 return FloatFromString(string);
730 property void * input { set { input = value; } get { return input; } }
731 property void * output { set { output = value; } get { return output; } }
732 property bool buffered
736 FILE_set_buffered(input, output, value);
739 property bool eof { get { return Eof(); } }
741 int GetLineEx(char *s, int max, bool *hasNewLineChar)
751 if(/*!Peek() || */ !Getc(&ch))
759 *hasNewLineChar = (ch == '\n');
765 bool CopyTo(const char * outputFileName)
768 File f = FileOpen(outputFileName, write);
777 uint count = Read(buffer, 1, sizeof(buffer));
778 if(count && !f.Write(buffer, 1, count))
791 virtual bool Open(const char * fileName, FileOpenMode mode)
796 FILE_FileOpen(fileName, mode, &input, &output);
799 if(!input && !output);
804 // TESTING ENABLING FILE BUFFERING BY DEFAULT... DOCUMENT ANY ISSUE
807 setvbuf(file.input, null, _IONBF, 0);
809 setvbuf(file.output, null, _IONBF, 0);
815 LogErrorCode((mode == Read || mode == ReadWrite) ?
816 ERR_FILE_NOT_FOUND : ERR_FILE_WRITE_FAILED, fileName);
831 #if defined(__WIN32__)
832 default extern intptr_t stdinHandle;
833 default extern intptr_t stdoutHandle;
836 public class ConsoleFile : File
839 output = eC_stdout();
841 #if defined(__WIN32__)
844 CloseHandle((HANDLE)stdinHandle);
849 CloseHandle((HANDLE)stdoutHandle);
860 public class FileAttribs : bool
863 bool isFile:1, isArchive:1, isHidden:1, isReadOnly:1, isSystem:1, isTemporary:1, isDirectory:1;
864 bool isDrive:1, isCDROM:1, isRemote:1, isRemovable:1, isServer:1, isShare:1;
865 // property bool { };
868 #ifdef ECERE_BOOTSTRAP
869 public class SecSince1970 : int64;
872 public struct FileStats
876 SecSince1970 accessed;
877 SecSince1970 modified;
878 SecSince1970 created;
881 #if defined(__WIN32__)
883 // --- FileName functions ---
885 default TimeStamp Win32FileTimeToTimeStamp(FILETIME * fileTime)
887 // TIME_ZONE_INFORMATION tz = { 0 };
891 FileTimeToSystemTime(fileTime, <);
894 GetTimeZoneInformation(&tz);
896 _TzSpecificLocalTimeToSystemTime(&tz, <, &st);
901 t.month = (Month)(st.wMonth - 1);
904 t.minute = st.wMinute;
905 t.second = st.wSecond;
909 default void TimeStampToWin32FileTime(TimeStamp t, FILETIME * fileTime)
911 // TIME_ZONE_INFORMATION tz = { 0 };
917 st.wYear = (short)tm.year;
918 st.wMonth = (short)(tm.month + 1);
919 st.wDay = (short)tm.day;
920 st.wHour = (short)tm.hour;
921 st.wMinute = (short)tm.minute;
922 st.wSecond = (short)tm.second;
923 st.wMilliseconds = 0;
927 GetTimeZoneInformation(&tz);
929 SystemTimeToTzSpecificLocalTime(&tz, &st, <);
933 SystemTimeToFileTime(<, fileTime);
936 default TimeStamp Win32FileTimeToTimeStamp(FILETIME * fileTime);
937 default void TimeStampToWin32FileTime(TimeStamp t, FILETIME * fileTime);
939 default bool WinReviveNetworkResource(uint16 * _wfileName);
943 public FileAttribs FileExists(const char * fileName)
945 #if !defined(ECERE_BOOTSTRAP)
946 char archiveName[MAX_LOCATION];
947 const char * archiveFile;
948 if(SplitArchivePath(fileName, archiveName, &archiveFile))
950 return EARFileSystem::Exists(archiveName, archiveFile);
952 else if(strstr(fileName, "http://") == fileName)
954 return FileAttribs { isFile = true };
958 return FILE_FileExists(fileName);
961 static int openCount;
963 public File FileOpen(const char * fileName, FileOpenMode mode)
968 #if !defined(ECERE_BOOTSTRAP)
969 char archiveName[MAX_LOCATION];
970 const char * archiveFile;
971 if(SplitArchivePath(fileName, archiveName, &archiveFile))
973 result = EARFileSystem::Open(archiveName, archiveFile, mode);
975 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
976 else if(strstr(fileName, "http://") == fileName || strstr(fileName, "https://"))
978 result = FileOpenURL(fileName);
983 if(strstr(fileName, "File://") == fileName)
985 result = (File)(uintptr)strtoull(fileName+7, null, 16);
988 if(result._class && eClass_IsDerived(result._class, class(File)))
990 if(!result._refCount) incref result;
992 result.Seek(0, start);
1000 File file = File {};
1003 FILE_FileOpen(fileName, mode, &file.input, &file.output);
1006 if(!file.input && !file.output);
1011 // TESTING ENABLING FILE BUFFERING BY DEFAULT... DOCUMENT ANY ISSUE
1014 setvbuf(file.input, null, _IONBF, 0);
1016 setvbuf(file.output, null, _IONBF, 0);
1023 LogErrorCode((mode == Read || mode == ReadWrite) ?
1024 ERR_FILE_NOT_FOUND : ERR_FILE_WRITE_FAILED, fileName);
1033 public void FileFixCase(char * file)
1035 FILE_FileFixCase(file);
1038 #if !defined(ECERE_BOOTSTRAP)
1039 public bool FileTruncate(const char * fileName, FileSize size)
1041 #if defined(__WIN32__)
1042 uint16 * _wfileName = UTF8toUTF16(fileName, null);
1043 int f = _wopen(_wfileName, _O_RDWR|_O_CREAT, _S_IREAD|_S_IWRITE);
1044 bool result = false;
1047 if(!_chsize(f, size))
1054 return truncate(fileName, size) == 0;
1059 public bool FileGetSize(const char * fileName, FileSize * size)
1061 bool result = false;
1067 #if !defined(ECERE_BOOTSTRAP)
1068 char archiveName[MAX_LOCATION];
1069 const char * archiveFile;
1070 if(SplitArchivePath(fileName, archiveName, &archiveFile))
1071 return EARFileSystem::GetSize(archiveName, archiveFile, size);
1074 result = FILE_FileGetSize(fileName, size);
1080 public bool FileGetStats(const char * fileName, FileStats stats)
1082 bool result = false;
1083 if(stats && fileName)
1085 #if !defined(ECERE_BOOTSTRAP)
1086 char archiveName[MAX_LOCATION];
1087 const char * archiveFile;
1088 if(SplitArchivePath(fileName, archiveName, &archiveFile))
1089 result = EARFileSystem::Stats(archiveName, archiveFile, stats);
1092 return FILE_FileGetStats(fileName, stats);
1097 #ifndef ECERE_BOOTSTRAP
1099 public bool FileSetAttribs(const char * fileName, FileAttribs attribs)
1102 uint winAttribs = 0;
1103 uint16 * _wfileName = UTF8toUTF16(fileName, null);
1105 if(attribs.isHidden) winAttribs |= FILE_ATTRIBUTE_HIDDEN;
1106 if(attribs.isReadOnly) winAttribs |= FILE_ATTRIBUTE_READONLY;
1108 SetFileAttributes(_wfileName, winAttribs);
1114 public bool FileSetTime(const char * fileName, TimeStamp created, TimeStamp accessed, TimeStamp modified)
1116 bool result = false;
1117 TimeStamp currentTime = time(null);
1118 if(!created) created = currentTime;
1119 if(!accessed) accessed = currentTime;
1120 if(!modified) modified = currentTime;
1124 uint16 * _wfileName = UTF8toUTF16(fileName, null);
1125 HANDLE hFile = CreateFile(_wfileName, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, null,
1126 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, null);
1128 if(hFile != INVALID_HANDLE_VALUE)
1132 TimeStampToWin32FileTime(created, &c);
1133 TimeStampToWin32FileTime(accessed, &a);
1134 TimeStampToWin32FileTime(modified, &m);
1140 cc = Win32FileTimeToTimeStamp(&c);
1141 aa = Win32FileTimeToTimeStamp(&a);
1142 mm = Win32FileTimeToTimeStamp(&m);
1146 if(SetFileTime(hFile, &c, &a, &m))
1152 struct utimbuf t = { (int)accessed, (int)modified };
1153 if(!utime(fileName, &t))
1160 /****************************************************************************
1162 ****************************************************************************/
1163 // Directory Description for file listing
1164 private class Dir : struct
1166 #if defined(__WIN32__)
1170 NETRESOURCE * resources;
1174 NETRESOURCE * workGroups;
1179 char name[MAX_LOCATION];
1182 static FileDesc FileFind(const char * path, const char * extensions)
1184 FileDesc result = null;
1187 if((file = FileDesc {}))
1189 char archiveName[MAX_LOCATION];
1190 const char * archiveFile;
1191 if(SplitArchivePath(path, archiveName, &archiveFile))
1193 if(EARFileSystem::Find(file, archiveName, archiveFile))
1195 file.system = class(EARFileSystem);
1203 if((d = file.dir = Dir {}))
1205 #if defined(__WIN32__)
1206 if(!strcmp(path, "/"))
1209 uint drives = 0xFFFFFFFF;
1210 d.fHandle = (HANDLE)(uintptr)drives; //GetLogicalDrives();
1211 for(c = 0; c<26; c++)
1212 if(((uint)(uintptr)d.fHandle) & (1<<c))
1214 char volume[MAX_FILENAME] = "";
1215 uint16 _wvolume[MAX_FILENAME];
1217 uint16 _wfilePath[4];
1219 strcpy(d.name, path);
1220 file.stats.attribs = FileAttribs { isDirectory = true, isDrive = true };
1221 _wfilePath[0] = file.path[0] = (char)('A' + c);
1222 _wfilePath[1] = file.path[1] = ':';
1223 _wfilePath[2] = file.path[2] = '\\';
1224 _wfilePath[3] = file.path[3] = '\0';
1225 file.stats.size = 0;
1226 file.stats.accessed = file.stats.created = file.stats.modified = 0;
1227 driveType = GetDriveType(_wfilePath);
1230 case DRIVE_REMOVABLE: file.stats.attribs.isRemovable = true; break;
1231 case DRIVE_REMOTE: file.stats.attribs.isRemote = true; break;
1232 case DRIVE_CDROM: file.stats.attribs.isCDROM = true; break;
1235 if(driveType == DRIVE_NO_ROOT_DIR) continue;
1237 if(driveType != DRIVE_REMOVABLE && driveType != DRIVE_REMOTE &&
1238 GetVolumeInformation(_wfilePath, _wvolume, MAX_FILENAME - 1, null, null, null, null, 0))
1240 file.path[2] = '\0';
1241 UTF16toUTF8Buffer(_wvolume, volume, MAX_FILENAME);
1242 sprintf(file.name, "%s [%s]", file.path, volume);
1246 file.path[2] = '\0';
1247 strcpy(file.name, file.path);
1252 d.fHandle = (HANDLE)(uintptr) drives;
1255 else if(path[0] != '\\' || path[1] != '\\' || strstr(path+2, "\\"))
1257 WIN32_FIND_DATA winFile;
1258 uint16 dir[MAX_PATH];
1260 UTF8toUTF16Buffer(path, dir, MAX_LOCATION);
1261 if(path[0]) wcscat(dir, L"\\");
1262 wcscat(dir, L"*.*");
1264 d.fHandle = FindFirstFile(dir, &winFile);
1265 if(d.fHandle == INVALID_HANDLE_VALUE && WinReviveNetworkResource(dir))
1266 d.fHandle = FindFirstFile(dir, &winFile);
1267 if(d.fHandle != INVALID_HANDLE_VALUE)
1269 UTF16toUTF8Buffer(winFile.cFileName, file.name, MAX_FILENAME);
1270 strcpy(file.path, path);
1271 PathCat(file.path, file.name);
1273 strcat(file.path, DIR_SEPS);
1274 strcat(file.path, file.name);*/
1275 // file.sizeHigh = winFile.nFileSizeHigh;
1276 file.stats.size = winFile.nFileSizeLow;
1278 file.stats.attribs = FileAttribs { };
1279 file.stats.attribs.isArchive = (winFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? true : false;
1280 file.stats.attribs.isHidden = (winFile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? true : false;
1281 file.stats.attribs.isReadOnly = (winFile.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? true : false;
1282 file.stats.attribs.isSystem = (winFile.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? true : false;
1283 file.stats.attribs.isTemporary = (winFile.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) ? true : false;
1284 file.stats.attribs.isDirectory = (winFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false;
1285 file.stats.attribs.isFile = !(winFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1286 strcpy(d.name, path);
1288 file.stats.accessed = Win32FileTimeToTimeStamp(&winFile.ftLastAccessTime);
1289 file.stats.modified = Win32FileTimeToTimeStamp(&winFile.ftLastWriteTime);
1290 file.stats.created = Win32FileTimeToTimeStamp(&winFile.ftCreationTime);
1297 DWORD count = 0xFFFFFFFF;
1298 DWORD size = 512 * sizeof(NETRESOURCE);
1299 NETRESOURCE * buffer = (NETRESOURCE *)new0 byte[size];
1300 NETRESOURCE nr = {0};
1303 nr.dwScope = RESOURCE_GLOBALNET;
1304 nr.dwType = RESOURCETYPE_DISK;
1305 nr.lpProvider = (uint16 *)L"Microsoft Windows Network";
1307 strcpy(d.name, path);
1310 nr.lpRemoteName = UTF8toUTF16(path, null);
1313 WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &nr, &handle);
1316 WinReviveNetworkResource(nr.lpRemoteName);
1317 WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &nr, &handle);
1324 int returnCode = WNetEnumResource(handle, &count, buffer, &size);
1325 if(returnCode != ERROR_MORE_DATA)
1328 buffer = (NETRESOURCE *)renew0 buffer byte[size];
1330 WNetCloseEnum(handle);
1333 delete nr.lpRemoteName;
1336 file.stats.attribs = FileAttribs { isDirectory = true, isShare = true };
1337 file.stats.size = 0;
1338 file.stats.accessed = file.stats.created = file.stats.modified = 0;
1340 UTF16toUTF8Buffer(buffer->lpRemoteName, file.path, MAX_LOCATION);
1341 GetLastDirectory(file.path, file.name);
1344 d.resources = buffer;
1345 d.numResources = count;
1354 nr.lpProvider = (uint16 *)L"Microsoft Windows Network";
1357 WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &nr, &handle);
1360 int returnCode = WNetEnumResource(handle, &count, buffer, &size);
1361 if(returnCode != ERROR_MORE_DATA)
1364 buffer = (NETRESOURCE *)renew0 buffer byte[size];
1366 WNetCloseEnum(handle);
1368 for(c = 0; c<count; c++)
1370 NETRESOURCE * resources;
1371 DWORD countInGroup = 0xFFFFFFFF;
1373 size = 512 * sizeof(NETRESOURCE);
1374 resources = (NETRESOURCE *)new0 byte[size];
1377 WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &buffer[c], &handle);
1380 int returnCode = WNetEnumResource(handle, &countInGroup, resources, &size);
1381 if(returnCode != ERROR_MORE_DATA)
1383 countInGroup = 0xFFFFFFFF;
1384 resources = (NETRESOURCE *)renew0 resources byte[size];
1386 WNetCloseEnum(handle);
1390 file.stats.attribs = FileAttribs { isDirectory = true, isServer = true };
1391 file.stats.size = 0;
1392 file.stats.accessed = file.stats.created = file.stats.modified = 0;
1394 UTF16toUTF8Buffer(resources->lpRemoteName, file.path, MAX_LOCATION);
1396 file.path[2] = (char)toupper(file.path[2]);
1397 GetLastDirectory(file.path, file.name);
1401 d.resources = resources;
1402 d.numResources = countInGroup;
1405 d.workGroups = buffer;
1406 d.numWorkGroups = count;
1413 if(c >= count && buffer) delete buffer;
1420 d.d = opendir((path && path[0]) ? path : ".");
1421 if(d.d && (de = readdir(d.d)))
1425 strcpy(file.path, path);
1427 strcat(file.path, DIR_SEPS);
1429 strcpy(file.name,de->d_name);
1430 strcat(file.path, file.name);
1431 if(!stat(file.path, &s))
1433 file.stats.attribs = (s.st_mode&S_IFDIR) ? FileAttribs { isDirectory = true } : FileAttribs { isFile = true };
1434 file.stats.size = (FileSize)s.st_size;
1435 file.stats.accessed = s.st_atime;
1436 file.stats.modified = s.st_mtime;
1437 file.stats.created = s.st_ctime;
1439 strcpy(d.name, path);
1454 while(result && !result.Validate(extensions))
1455 result = result.FindNext(extensions);
1460 private class FileDesc : struct
1463 char name[MAX_FILENAME];
1464 char path[MAX_LOCATION];
1466 subclass(FileSystem) system;
1469 bool Validate(const char * extensions)
1471 if(strcmp(name, "..") && strcmp(name, ".") && strcmp(name, ""))
1473 if(extensions && !stats.attribs.isDirectory)
1475 char extension[MAX_EXTENSION], compared[MAX_EXTENSION];
1478 GetExtension(name, extension);
1479 for(c = 0; extensions[c];)
1483 for(;(ch = extensions[c]) && !IS_ALUNDER(ch); c++);
1484 for(;(ch = extensions[c]) && IS_ALUNDER(ch); c++)
1485 compared[len++] = ch;
1486 compared[len] = '\0';
1488 if(!strcmpi(extension, compared))
1498 FileDesc FindNext(const char * extensions)
1500 FileDesc result = null;
1506 while(!Validate(extensions))
1512 if(system.FindNext(this))
1519 #if defined(__WIN32__)
1520 if(!strcmp(d.name, "/"))
1523 uint drives = (uint)(uintptr)d.fHandle;
1524 for(c = 0; c<26; c++)
1528 char volume[MAX_FILENAME] = "";
1531 uint16 _wvolume[MAX_FILENAME];
1533 stats.attribs = FileAttribs { isDirectory = true, isDrive = true };
1535 stats.accessed = stats.created = stats.modified = 0;
1536 _wpath[0] = path[0] = (char)('A' + c);
1537 _wpath[1] = path[1] = ':';
1538 _wpath[2] = path[2] = '\\';
1539 _wpath[3] = path[3] = 0;
1540 driveType = GetDriveType(_wpath);
1545 case DRIVE_REMOVABLE: stats.attribs.isRemovable = true; break;
1546 case DRIVE_REMOTE: stats.attribs.isRemote = true; break;
1547 case DRIVE_CDROM: stats.attribs.isCDROM = true; break;
1549 if(driveType == DRIVE_NO_ROOT_DIR)
1551 uint16 remoteName[1024];
1556 status = WNetGetConnection(_wpath, remoteName, &size);
1557 if(status != ERROR_CONNECTION_UNAVAIL)
1564 if(driveType != DRIVE_REMOVABLE && driveType != DRIVE_REMOTE &&
1565 GetVolumeInformation(_wpath, _wvolume, MAX_FILENAME - 1, null, null, null, null, 0))
1567 UTF16toUTF8Buffer(_wvolume, volume, MAX_FILENAME);
1569 sprintf(name, "%s [%s]", path, volume);
1580 d.fHandle = (HANDLE)(uintptr) drives;
1583 else if(d.name[0] != '\\' || d.name[1] != '\\' || strstr(d.name+2, "\\"))
1585 WIN32_FIND_DATA winFile;
1586 if(FindNextFile(d.fHandle, &winFile))
1588 UTF16toUTF8Buffer(winFile.cFileName, name, MAX_FILENAME);
1589 stats.attribs = FileAttribs { };
1590 stats.attribs.isArchive = (winFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? true : false;
1591 stats.attribs.isHidden = (winFile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? true : false;
1592 stats.attribs.isReadOnly = (winFile.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? true : false;
1593 stats.attribs.isSystem = (winFile.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? true : false;
1594 stats.attribs.isTemporary = (winFile.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) ? true : false;
1595 stats.attribs.isDirectory = (winFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false;
1596 stats.attribs.isFile = !(winFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1597 stats.size = winFile.nFileSizeLow;
1599 stats.accessed = Win32FileTimeToTimeStamp(&winFile.ftLastAccessTime);
1600 stats.modified = Win32FileTimeToTimeStamp(&winFile.ftLastWriteTime);
1601 stats.created = Win32FileTimeToTimeStamp(&winFile.ftCreationTime);
1603 strcpy(path, d.name);
1604 PathCat(path, name);
1606 strcat(path, DIR_SEPS);
1607 strcat(path, name);*/
1617 if(d.resource < d.numResources)
1619 stats.attribs = FileAttribs { isDirectory = true, isShare = true };
1621 stats.accessed = stats.created = stats.modified = 0;
1623 UTF16toUTF8Buffer(d.resources[d.resource].lpRemoteName, path, MAX_LOCATION);
1624 GetLastDirectory(path, name);
1639 for(c = d.workGroup; c<d.numWorkGroups; c++)
1641 if(c != d.workGroup)
1643 DWORD countInGroup = 0xFFFFFFFF;
1645 NETRESOURCE * resources;
1646 DWORD size = 512 * sizeof(NETRESOURCE);
1648 resources = (NETRESOURCE *)new0 byte[size];
1650 WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &d.workGroups[c], &handle);
1653 int returnCode = WNetEnumResource(handle, &countInGroup, resources, &size);
1654 if(returnCode != ERROR_MORE_DATA)
1656 countInGroup = 0xFFFFFFFF;
1657 resources = (NETRESOURCE *)renew0 resources byte[size];
1660 WNetCloseEnum(handle);
1661 d.numResources = countInGroup;
1662 d.resources = resources;
1666 if(d.resource < d.numResources)
1668 stats.attribs = FileAttribs { isDirectory = true, isServer = true };
1670 stats.accessed = stats.created = stats.modified = 0;
1672 UTF16toUTF8Buffer(d.resources[d.resource].lpRemoteName, path, MAX_LOCATION);
1674 path[2] = (char)toupper(path[2]);
1675 GetLastDirectory(path, name);
1689 if(d.workGroup == d.numWorkGroups && d.resource == d.numResources)
1691 delete d.workGroups;
1703 strcpy(name,de->d_name);
1704 strcpy(path, d.name);
1705 if(d.name[0] && d.name[1])
1706 strcat(path, DIR_SEPS);
1710 stats.attribs = FileAttribs { };
1711 stats.attribs = (s.st_mode&S_IFDIR) ? FileAttribs { isDirectory = true } : FileAttribs { isFile = true };
1712 stats.size = (FileSize)s.st_size;
1713 stats.accessed = s.st_atime;
1714 stats.modified = s.st_mtime;
1715 stats.created = s.st_ctime;
1732 system.CloseDir(this);
1738 #if defined(__WIN32__)
1739 if(d.fHandle && strcmp(d.name, "/"))
1740 FindClose(d.fHandle);
1751 public struct FileListing
1754 const char * directory;
1755 const char * extensions;
1760 desc = desc.FindNext(extensions);
1762 desc = FileFind(directory, extensions);
1775 property const char * name { get { return desc ? desc.name : null; } };
1776 property const char * path { get { return desc ? desc.path : null; } };
1777 property FileStats stats { get { value = desc ? desc.stats : FileStats { }; } };
1784 public File CreateTemporaryFile(char * tempFileName, const char * template)
1786 #ifndef ECERE_BOOTSTRAP // quick fix for now
1788 #if defined(__unix__) || defined(__APPLE__)
1789 char buffer[MAX_FILENAME];
1791 strcpy(buffer, "/tmp/");
1792 strcat(buffer, template);
1793 //strcpy(buffer, template);
1794 strcat(buffer, "XXXXXX");
1796 fd = mkstemp(buffer);
1797 strcpy(tempFileName, buffer);
1799 f.output = f.input = fdopen(fd, "r+");
1801 char tempPath[MAX_LOCATION];
1802 GetTempPathA(MAX_LOCATION, tempPath); // TODO: Patch this whole thing to support Unicode temp path
1803 GetTempFileNameA(tempPath, template, 0, tempFileName);
1804 f = FileOpen(tempFileName, readWrite);
1814 public void CreateTemporaryDir(char * tempFileName, const char * template)
1816 #ifndef ECERE_BOOTSTRAP // quick fix for now
1817 #if defined(__unix__) || defined(__APPLE__)
1818 char buffer[MAX_FILENAME];
1819 strcpy(buffer, "/tmp/");
1820 strcat(buffer, template);
1821 //strcpy(buffer, template);
1822 strcat(buffer, "XXXXXX");
1825 strcpy(tempFileName, buffer);
1827 char tempPath[MAX_LOCATION];
1828 GetTempPathA(MAX_LOCATION, tempPath); // TODO: Patch this whole thing to support Unicode temp path
1829 GetTempFileNameA(tempPath, template, 0, tempFileName);
1830 DeleteFile(tempFileName);
1831 MakeDir(tempFileName);
1836 public void MakeSlashPath(char * p)
1839 if(__runtimePlatform == win32)
1840 ChangeCh(p, '\\', '/');
1843 public void MakeSystemPath(char * p)
1848 public char * CopySystemPath(const char * p)
1850 char * d = CopyString(p);
1856 public char * CopyUnixPath(const char * p)
1858 char * d = CopyString(p);
1864 public char * GetSystemPathBuffer(char * d, const char * p)
1867 strcpy(d, p ? p : "");
1872 public char * GetSlashPathBuffer(char * d, const char * p)
1875 strcpy(d, p ? p : "");