15 #define IS_ALUNDER(ch) ((ch) == '_' || isalnum((ch)))
17 #if defined(ECERE_BOOTSTRAP)
24 #ifndef ECERE_BOOTSTRAP
25 #if defined(__GNUC__) || defined(__WATCOMC__) || defined(__WIN32__)
27 #include <sys/types.h>
32 #if defined(__unix__) || defined(__APPLE__)
36 #if defined(__WIN32__) || defined(__WATCOMC__)
42 #if defined(__WIN32__)
43 #define WIN32_LEAN_AND_MEAN
44 #define String String_
49 BOOL __declspec(dllimport) WINAPI GetVolumePathName(LPCTSTR lpszFileName,LPTSTR lpszVolumePathName,DWORD cchBufferLength);
51 // Missing function...
53 #ifndef WNetGetResourceInformation
54 DWORD APIENTRY WNetGetResourceInformationA(LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD lpcbBuffer, LPTSTR* lplpSystem);
56 #define WNetGetResourceInformation WNetGetResourceInformationW
58 #define WNetGetResourceInformation WNetGetResourceInformationA
70 #endif //#ifndef ECERE_BOOTSTRAP
80 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET) && !defined(ECERE_BOOTSTRAP)
86 // IMPLEMENTATION OF THESE IS IN _File.c
90 FILE *eC_stdout(void);
92 uint FILE_GetSize(FILE * input);
93 bool FILE_Lock(FILE * input, FILE * output, FileLock type, uint64 start, uint64 length, bool wait);
94 void FILE_set_buffered(FILE * input, FILE * output, bool value);
95 FileAttribs FILE_FileExists(const char * fileName);
96 bool FILE_FileGetSize(const char * fileName, FileSize * size);
97 bool FILE_FileGetStats(const char * fileName, FileStats stats);
98 void FILE_FileFixCase(char * file);
99 void FILE_FileOpen(const char * fileName, FileOpenMode mode, FILE ** input, FILE **output);
103 FileSystem httpFileSystem;
105 public class FileSize : uint
107 // defaultAlignment = Right;
109 void OnDisplay(Surface surface, int x, int y, int width, void * fieldData, int alignment, DataDisplayFlags displayFlags)
113 eUtils_PrintSize(string, *size, 2);
114 len = strlen(string);
115 surface.WriteTextDots(alignment, x, y, width, string, len);
118 int OnCompare(FileSize data2)
125 else if(this < data2)
131 const char * OnGetString(char * string, void * fieldData, bool * needClass)
133 PrintSize(string, this, 2);
137 bool OnGetDataFromString(const char * string)
140 double value = strtod(string, &end);
142 if(strstr(end, "GB") || strstr(end, "gb")) multiplier = (uint)1024 * 1024 * 1024;
143 else if(strstr(end, "MB") || strstr(end, "mb")) multiplier = (uint)1024 * 1024;
144 else if(strstr(end, "KB") || strstr(end, "kb")) multiplier = 1024;
146 this = (uint)(multiplier * value);
151 public class FileSize64 : uint64
153 int OnCompare(FileSize64 data2)
160 else if(this < data2)
166 const char * OnGetString(char * string, void * fieldData, bool * needClass)
168 PrintBigSize(string, this, 2);
172 bool OnGetDataFromString(const char * string)
175 double value = strtod(string, &end);
176 uint64 multiplier = 1;
177 if(strstr(end, "PB") || strstr(end, "pb")) multiplier = (uint64)1024 * 1024 * 1024 * 1024;
178 else if(strstr(end, "TB") || strstr(end, "tb")) multiplier = (uint64)1024 * 1024 * 1024 * 1024;
179 else if(strstr(end, "GB") || strstr(end, "gb")) multiplier = (uint64)1024 * 1024 * 1024;
180 else if(strstr(end, "MB") || strstr(end, "mb")) multiplier = (uint64)1024 * 1024;
181 else if(strstr(end, "KB") || strstr(end, "kb")) multiplier = 1024;
183 this = (uint64)(multiplier * value);
190 virtual File ::Open(const char * archive, const char * name, FileOpenMode mode);
193 virtual FileAttribs ::Exists(const char * archive, const char * fileName);
194 virtual bool ::GetSize(const char * archive, const char * fileName, FileSize * size);
195 virtual bool ::Stats(const char * archive, const char * fileName, FileStats stats);
196 virtual void ::FixCase(const char * archive, char * fileName);
199 virtual bool ::Find(FileDesc file, const char * archive, const char * name);
200 virtual bool ::FindNext(FileDesc file);
201 virtual void ::CloseDir(FileDesc file);
203 // Archive manipulation
204 virtual Archive ::OpenArchive(const char * fileName, ArchiveOpenFlags create);
205 virtual bool ::QuerySize(const char * fileName, FileSize * size);
208 public enum FileOpenMode { read = 1, write, append, readWrite, writeRead, appendRead };
209 public enum FileSeekMode { start, current, end };
211 #if !defined(ECERE_BOOTSTRAP)
212 static FileDialog fileDialog { text = $"Select File" };
217 unlocked = 0, // LOCK_UN _SH_DENYNO
218 shared = 1, // LOCK_SH _SH_DENYWR
219 exclusive = 2 // LOCK_EX _SH_DENYRW
222 public class File : IOChannel
224 FILE * input, * output;
226 uint ReadData(byte * bytes, uint numBytes)
228 return Read(bytes, 1, numBytes);
231 uint WriteData(const byte * bytes, uint numBytes)
233 return Write(bytes, 1, numBytes);
238 if(output && output != input)
252 bool OnGetDataFromString(const char * string)
261 File f = FileOpen(string, read);
268 uint read = f.Read(buffer, 1, sizeof(buffer));
269 Write(buffer, 1, read);
278 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
282 PrintSize(tempString, GetSize(), 2);
288 #ifndef ECERE_BOOTSTRAP
289 Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
291 Window editData = class::OnEdit(dataBox, obsolete, x + 24, y, w - 48, h, userData);
294 dataBox, inactive = true, text = $"Import"."Imp", hotKey = f2,
295 position = { Max(x + 24, x + w - 24), y }, size = { 24, h };
297 bool DataBox::NotifyClicked(Button button, int x, int y, Modifiers mods)
299 fileDialog.master = rootWindow;
300 fileDialog.filePath = "";
301 fileDialog.type = open;
303 if(fileDialog.Modal() == ok)
305 const char * filePath = fileDialog.filePath;
307 if(output.OnGetDataFromString(filePath))
309 SetData(output, false);
318 dataBox, inactive = true, text = $"Export"."Exp", hotKey = f2,
319 position = { Max(x + 24, x + w - 48), y }, size = { 24, h };
321 bool DataBox::NotifyClicked(Button button, int x, int y, Modifiers mods)
323 fileDialog.master = rootWindow;
324 fileDialog.type = save;
325 fileDialog.filePath = "";
326 if(fileDialog.Modal() == ok)
328 const char * filePath = fileDialog.filePath;
329 File f = FileOpen(filePath, write);
332 File input = *(void **)data;
333 input.Seek(0, start);
337 uint read = input.Read(buffer, 1, sizeof(buffer));
338 f.Write(buffer, 1, read);
350 #endif //#ifndef ECERE_BOOTSTRAP
352 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOARCHIVE) && !defined(ECERE_BOOTSTRAP)
353 void OnSerialize(IOChannel channel)
355 uint size = this ? GetSize() : MAXDWORD;
358 byte * uncompressed = new byte[size];
360 if(uncompressed || !size)
362 uint count = Read(uncompressed, 1, size);
365 uLongf cSize = size + size / 1000 + 12;
366 byte * compressed = new byte[cSize];
369 compress2(compressed, &cSize, uncompressed, size, 9);
371 size.OnSerialize(channel);
372 cSize.OnSerialize(channel);
373 channel.WriteData(compressed, (uint)cSize);
382 size.OnSerialize(channel);
387 size.OnSerialize(channel);
389 // Will add position...
393 for(c = 0; c<size; c += sizeof(data))
395 uint count = Read(data, 1, sizeof(data));
396 buffer.WriteData(data, count);
402 void OnUnserialize(IOChannel channel)
409 size.OnUnserialize(channel);
413 cSize.OnUnserialize(channel);
415 compressed = new byte[cSize];
418 if(channel.ReadData(compressed, cSize) == cSize)
420 byte * uncompressed = new byte[size];
421 if(uncompressed || !size)
424 uncompress(uncompressed, &size, compressed, cSize);
425 Write(uncompressed, 1, (uint)size);
439 size.OnUnserialize(channel);
443 for(c = 0; c<size; c += sizeof(data))
445 uint count = Min(size - c, sizeof(data));
446 channel.ReadData(data, count);
447 Write(data, 1, count);
460 virtual bool Seek(int pos, FileSeekMode mode)
462 uint fmode = SEEK_SET;
465 case start: fmode = SEEK_SET; break;
466 case end: fmode = SEEK_END; break;
467 case current: fmode = SEEK_CUR; break;
469 return fseek(input ? input : output, pos, fmode) != EOF;
472 virtual uint Tell(void)
474 return (uint)(input ? ftell(input) : ftell(output));
477 virtual int Read(void * buffer, uint size, uint count)
479 return input ? (int)fread(buffer, size, count, input) : 0;
482 virtual int Write(const void * buffer, uint size, uint count)
484 return output ? (int)fwrite(buffer, size, count, output) : 0;
488 virtual bool Getc(char * ch)
490 int ich = fgetc(input);
493 if(ch) *ch = (char)ich;
499 virtual bool Putc(char ch)
501 return (fputc((int)ch, output) == EOF) ? false : true;
504 virtual bool Puts(const char * string)
509 result = (fputs(string, output) == EOF) ? false : true;
510 // TODO: Check if any repercusions of commenting out fflush here
511 // This is what broke the debugger in 0.44d2 , it is required for outputting things to the DualPipe
512 // Added an explicit flush call in DualPipe::Puts
518 virtual bool Eof(void)
520 return input ? feof(input) != 0 : true;
523 virtual bool Truncate(FileSize size)
525 #ifdef ECERE_BOOTSTRAP
526 fprintf(stderr, "WARNING: File::Truncate unimplemented in ecereBootstrap.\n");
529 #if defined(__WIN32__)
530 return output ? (_chsize(fileno(output), size) == 0) : false;
532 return output ? (ftruncate(fileno(output), size) == 0) : false;
537 virtual uint GetSize(void)
539 return FILE_GetSize(input);
542 virtual void CloseInput(void)
553 virtual void CloseOutput(void)
564 virtual bool Lock(FileLock type, uint64 start, uint64 length, bool wait)
566 return FILE_Lock(input, output, type, start, length, wait);
569 virtual bool Unlock(uint64 start, uint64 length, bool wait)
571 return Lock(unlocked, start, length, wait);
575 int Printf(const char * format, ...)
580 char text[MAX_F_STRING];
582 va_start(args, format);
583 vsnprintf(text, sizeof(text), format, args);
584 text[sizeof(text)-1] = 0;
586 result = strlen(text);
592 public void PrintLn(typed_object object, ...)
596 va_start(args, object);
597 PrintStdArgsToBuffer(buffer, sizeof(buffer), object, args);
603 public void Print(typed_object object, ...)
607 va_start(args, object);
608 PrintStdArgsToBuffer(buffer, sizeof(buffer), object, args);
619 bool GetLine(char *s, int max)
635 if(/*!Peek() || */ !Getc(&ch))
647 return result || c > 1;
650 // Strings and numbers separated by spaces, commas, tabs, or CR/LF, handling quotes
651 bool GetString(char * string, int max)
663 if( (ch!='\n') && (ch!='\r') && (ch!=' ') && (ch!=',') && (ch!='\t'))
669 for(c=0; c<max-1; c++)
671 if(!quoted && ((ch=='\n')||(ch=='\r')||(ch==' ')||(ch==',')||(ch=='\t')))
699 GetString(string,sizeof(string));
703 unsigned int GetHexValue(void)
706 GetString(string, sizeof(string));
707 return (uint)strtoul(string, null, 16);
713 GetString(string, sizeof(string));
714 return (float)FloatFromString(string);
717 double GetDouble(void)
720 GetString(string, sizeof(string));
721 return FloatFromString(string);
724 property void * input { set { input = value; } get { return input; } }
725 property void * output { set { output = value; } get { return output; } }
726 property bool buffered
730 FILE_set_buffered(input, output, value);
733 property bool eof { get { return Eof(); } }
735 int GetLineEx(char *s, int max, bool *hasNewLineChar)
745 if(/*!Peek() || */ !Getc(&ch))
753 *hasNewLineChar = (ch == '\n');
759 bool CopyTo(const char * outputFileName)
762 File f = FileOpen(outputFileName, write);
771 uint count = Read(buffer, 1, sizeof(buffer));
772 if(count && !f.Write(buffer, 1, count))
785 virtual bool Open(const char * fileName, FileOpenMode mode)
790 FILE_FileOpen(fileName, mode, &input, &output);
793 if(!input && !output);
798 // TESTING ENABLING FILE BUFFERING BY DEFAULT... DOCUMENT ANY ISSUE
801 setvbuf(file.input, null, _IONBF, 0);
803 setvbuf(file.output, null, _IONBF, 0);
809 LogErrorCode((mode == Read || mode == ReadWrite) ?
810 ERR_FILE_NOT_FOUND : ERR_FILE_WRITE_FAILED, fileName);
825 #if defined(__WIN32__)
826 default extern intptr_t stdinHandle;
827 default extern intptr_t stdoutHandle;
830 public class ConsoleFile : File
833 output = eC_stdout();
835 #if defined(__WIN32__)
838 CloseHandle((HANDLE)stdinHandle);
843 CloseHandle((HANDLE)stdoutHandle);
854 public class FileAttribs : bool
857 bool isFile:1, isArchive:1, isHidden:1, isReadOnly:1, isSystem:1, isTemporary:1, isDirectory:1;
858 bool isDrive:1, isCDROM:1, isRemote:1, isRemovable:1, isServer:1, isShare:1;
859 // property bool { };
862 #ifdef ECERE_BOOTSTRAP
863 public class SecSince1970 : int64;
866 public struct FileStats
870 SecSince1970 accessed;
871 SecSince1970 modified;
872 SecSince1970 created;
875 #if defined(__WIN32__)
877 // --- FileName functions ---
879 default TimeStamp Win32FileTimeToTimeStamp(FILETIME * fileTime)
881 // TIME_ZONE_INFORMATION tz = { 0 };
885 FileTimeToSystemTime(fileTime, <);
888 GetTimeZoneInformation(&tz);
890 _TzSpecificLocalTimeToSystemTime(&tz, <, &st);
895 t.month = (Month)(st.wMonth - 1);
898 t.minute = st.wMinute;
899 t.second = st.wSecond;
903 default void TimeStampToWin32FileTime(TimeStamp t, FILETIME * fileTime)
905 // TIME_ZONE_INFORMATION tz = { 0 };
911 st.wYear = (short)tm.year;
912 st.wMonth = (short)tm.month + 1;
913 st.wDay = (short)tm.day;
914 st.wHour = (short)tm.hour;
915 st.wMinute = (short)tm.minute;
916 st.wSecond = (short)tm.second;
917 st.wMilliseconds = 0;
921 GetTimeZoneInformation(&tz);
923 SystemTimeToTzSpecificLocalTime(&tz, &st, <);
927 SystemTimeToFileTime(<, fileTime);
930 default TimeStamp Win32FileTimeToTimeStamp(FILETIME * fileTime);
931 default void TimeStampToWin32FileTime(TimeStamp t, FILETIME * fileTime);
933 default bool WinReviveNetworkResource(uint16 * _wfileName);
937 public FileAttribs FileExists(const char * fileName)
939 #if !defined(ECERE_BOOTSTRAP)
940 char archiveName[MAX_LOCATION];
941 const char * archiveFile;
942 if(SplitArchivePath(fileName, archiveName, &archiveFile))
944 return EARFileSystem::Exists(archiveName, archiveFile);
946 else if(strstr(fileName, "http://") == fileName)
948 return FileAttribs { isFile = true };
952 return FILE_FileExists(fileName);
955 static int openCount;
957 public File FileOpen(const char * fileName, FileOpenMode mode)
962 #if !defined(ECERE_BOOTSTRAP)
963 char archiveName[MAX_LOCATION];
964 const char * archiveFile;
965 if(SplitArchivePath(fileName, archiveName, &archiveFile))
967 result = EARFileSystem::Open(archiveName, archiveFile, mode);
969 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
970 else if(strstr(fileName, "http://") == fileName || strstr(fileName, "https://"))
972 result = FileOpenURL(fileName);
977 if(strstr(fileName, "File://") == fileName)
979 result = (File)(uintptr)strtoull(fileName+7, null, 16);
982 if(result._class && eClass_IsDerived(result._class, class(File)))
984 if(!result._refCount) incref result;
986 result.Seek(0, start);
997 FILE_FileOpen(fileName, mode, &file.input, &file.output);
1000 if(!file.input && !file.output);
1005 // TESTING ENABLING FILE BUFFERING BY DEFAULT... DOCUMENT ANY ISSUE
1008 setvbuf(file.input, null, _IONBF, 0);
1010 setvbuf(file.output, null, _IONBF, 0);
1017 LogErrorCode((mode == Read || mode == ReadWrite) ?
1018 ERR_FILE_NOT_FOUND : ERR_FILE_WRITE_FAILED, fileName);
1027 public void FileFixCase(char * file)
1029 FILE_FileFixCase(file);
1032 #if !defined(ECERE_BOOTSTRAP)
1033 public bool FileTruncate(const char * fileName, FileSize size)
1035 #if defined(__WIN32__)
1036 uint16 * _wfileName = UTF8toUTF16(fileName, null);
1037 int f = _wopen(_wfileName, _O_RDWR|_O_CREAT, _S_IREAD|_S_IWRITE);
1038 bool result = false;
1041 if(!_chsize(f, size))
1048 return truncate(fileName, size) == 0;
1053 public bool FileGetSize(const char * fileName, FileSize * size)
1055 bool result = false;
1061 #if !defined(ECERE_BOOTSTRAP)
1062 char archiveName[MAX_LOCATION];
1063 const char * archiveFile;
1064 if(SplitArchivePath(fileName, archiveName, &archiveFile))
1065 return EARFileSystem::GetSize(archiveName, archiveFile, size);
1068 result = FILE_FileGetSize(fileName, size);
1074 public bool FileGetStats(const char * fileName, FileStats stats)
1076 bool result = false;
1077 if(stats && fileName)
1079 #if !defined(ECERE_BOOTSTRAP)
1080 char archiveName[MAX_LOCATION];
1081 const char * archiveFile;
1082 if(SplitArchivePath(fileName, archiveName, &archiveFile))
1083 result = EARFileSystem::Stats(archiveName, archiveFile, stats);
1086 return FILE_FileGetStats(fileName, stats);
1091 #ifndef ECERE_BOOTSTRAP
1093 public bool FileSetAttribs(const char * fileName, FileAttribs attribs)
1096 uint winAttribs = 0;
1097 uint16 * _wfileName = UTF8toUTF16(fileName, null);
1099 if(attribs.isHidden) winAttribs |= FILE_ATTRIBUTE_HIDDEN;
1100 if(attribs.isReadOnly) winAttribs |= FILE_ATTRIBUTE_READONLY;
1102 SetFileAttributes(_wfileName, winAttribs);
1108 public bool FileSetTime(const char * fileName, TimeStamp created, TimeStamp accessed, TimeStamp modified)
1110 bool result = false;
1111 TimeStamp currentTime = time(null);
1112 if(!created) created = currentTime;
1113 if(!accessed) accessed = currentTime;
1114 if(!modified) modified = currentTime;
1118 uint16 * _wfileName = UTF8toUTF16(fileName, null);
1119 HANDLE hFile = CreateFile(_wfileName, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, null,
1120 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, null);
1122 if(hFile != INVALID_HANDLE_VALUE)
1126 TimeStampToWin32FileTime(created, &c);
1127 TimeStampToWin32FileTime(accessed, &a);
1128 TimeStampToWin32FileTime(modified, &m);
1134 cc = Win32FileTimeToTimeStamp(&c);
1135 aa = Win32FileTimeToTimeStamp(&a);
1136 mm = Win32FileTimeToTimeStamp(&m);
1140 if(SetFileTime(hFile, &c, &a, &m))
1146 struct utimbuf t = { (int)accessed, (int)modified };
1147 if(!utime(fileName, &t))
1154 /****************************************************************************
1156 ****************************************************************************/
1157 // Directory Description for file listing
1158 private class Dir : struct
1160 #if defined(__WIN32__)
1164 NETRESOURCE * resources;
1168 NETRESOURCE * workGroups;
1173 char name[MAX_LOCATION];
1176 static FileDesc FileFind(const char * path, const char * extensions)
1178 FileDesc result = null;
1181 if((file = FileDesc {}))
1183 char archiveName[MAX_LOCATION];
1184 const char * archiveFile;
1185 if(SplitArchivePath(path, archiveName, &archiveFile))
1187 if(EARFileSystem::Find(file, archiveName, archiveFile))
1189 file.system = class(EARFileSystem);
1197 if((d = file.dir = Dir {}))
1199 #if defined(__WIN32__)
1200 if(!strcmp(path, "/"))
1203 uint drives = 0xFFFFFFFF;
1204 d.fHandle = (HANDLE)(uintptr)drives; //GetLogicalDrives();
1205 for(c = 0; c<26; c++)
1206 if(((uint)(uintptr)d.fHandle) & (1<<c))
1208 char volume[MAX_FILENAME] = "";
1209 uint16 _wvolume[MAX_FILENAME];
1211 uint16 _wfilePath[4];
1213 strcpy(d.name, path);
1214 file.stats.attribs = FileAttribs { isDirectory = true, isDrive = true };
1215 _wfilePath[0] = file.path[0] = (char)('A' + c);
1216 _wfilePath[1] = file.path[1] = ':';
1217 _wfilePath[2] = file.path[2] = '\\';
1218 _wfilePath[3] = file.path[3] = '\0';
1219 file.stats.size = 0;
1220 file.stats.accessed = file.stats.created = file.stats.modified = 0;
1221 driveType = GetDriveType(_wfilePath);
1224 case DRIVE_REMOVABLE: file.stats.attribs.isRemovable = true; break;
1225 case DRIVE_REMOTE: file.stats.attribs.isRemote = true; break;
1226 case DRIVE_CDROM: file.stats.attribs.isCDROM = true; break;
1229 if(driveType == DRIVE_NO_ROOT_DIR) continue;
1231 if(driveType != DRIVE_REMOVABLE && driveType != DRIVE_REMOTE &&
1232 GetVolumeInformation(_wfilePath, _wvolume, MAX_FILENAME - 1, null, null, null, null, 0))
1234 file.path[2] = '\0';
1235 UTF16toUTF8Buffer(_wvolume, volume, MAX_FILENAME);
1236 sprintf(file.name, "%s [%s]", file.path, volume);
1240 file.path[2] = '\0';
1241 strcpy(file.name, file.path);
1246 d.fHandle = (HANDLE)(uintptr) drives;
1249 else if(path[0] != '\\' || path[1] != '\\' || strstr(path+2, "\\"))
1251 WIN32_FIND_DATA winFile;
1252 uint16 dir[MAX_PATH];
1254 UTF8toUTF16Buffer(path, dir, MAX_LOCATION);
1255 if(path[0]) wcscat(dir, L"\\");
1256 wcscat(dir, L"*.*");
1258 d.fHandle = FindFirstFile(dir, &winFile);
1259 if(d.fHandle == INVALID_HANDLE_VALUE && WinReviveNetworkResource(dir))
1260 d.fHandle = FindFirstFile(dir, &winFile);
1261 if(d.fHandle != INVALID_HANDLE_VALUE)
1263 UTF16toUTF8Buffer(winFile.cFileName, file.name, MAX_FILENAME);
1264 strcpy(file.path, path);
1265 PathCat(file.path, file.name);
1267 strcat(file.path, DIR_SEPS);
1268 strcat(file.path, file.name);*/
1269 // file.sizeHigh = winFile.nFileSizeHigh;
1270 file.stats.size = winFile.nFileSizeLow;
1272 file.stats.attribs = FileAttribs { };
1273 file.stats.attribs.isArchive = (winFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? true : false;
1274 file.stats.attribs.isHidden = (winFile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? true : false;
1275 file.stats.attribs.isReadOnly = (winFile.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? true : false;
1276 file.stats.attribs.isSystem = (winFile.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? true : false;
1277 file.stats.attribs.isTemporary = (winFile.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) ? true : false;
1278 file.stats.attribs.isDirectory = (winFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false;
1279 file.stats.attribs.isFile = !(winFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1280 strcpy(d.name, path);
1282 file.stats.accessed = Win32FileTimeToTimeStamp(&winFile.ftLastAccessTime);
1283 file.stats.modified = Win32FileTimeToTimeStamp(&winFile.ftLastWriteTime);
1284 file.stats.created = Win32FileTimeToTimeStamp(&winFile.ftCreationTime);
1291 DWORD count = 0xFFFFFFFF;
1292 DWORD size = 512 * sizeof(NETRESOURCE);
1293 NETRESOURCE * buffer = (NETRESOURCE *)new0 byte[size];
1294 NETRESOURCE nr = {0};
1297 nr.dwScope = RESOURCE_GLOBALNET;
1298 nr.dwType = RESOURCETYPE_DISK;
1299 nr.lpProvider = (uint16 *)L"Microsoft Windows Network";
1301 strcpy(d.name, path);
1304 nr.lpRemoteName = UTF8toUTF16(path, null);
1307 WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &nr, &handle);
1310 WinReviveNetworkResource(nr.lpRemoteName);
1311 WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &nr, &handle);
1318 int returnCode = WNetEnumResource(handle, &count, buffer, &size);
1319 if(returnCode != ERROR_MORE_DATA)
1322 buffer = (NETRESOURCE *)renew0 buffer byte[size];
1324 WNetCloseEnum(handle);
1327 delete nr.lpRemoteName;
1330 file.stats.attribs = FileAttribs { isDirectory = true, isShare = true };
1331 file.stats.size = 0;
1332 file.stats.accessed = file.stats.created = file.stats.modified = 0;
1334 UTF16toUTF8Buffer(buffer->lpRemoteName, file.path, MAX_LOCATION);
1335 GetLastDirectory(file.path, file.name);
1338 d.resources = buffer;
1339 d.numResources = count;
1348 nr.lpProvider = (uint16 *)L"Microsoft Windows Network";
1351 WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &nr, &handle);
1354 int returnCode = WNetEnumResource(handle, &count, buffer, &size);
1355 if(returnCode != ERROR_MORE_DATA)
1358 buffer = (NETRESOURCE *)renew0 buffer byte[size];
1360 WNetCloseEnum(handle);
1362 for(c = 0; c<count; c++)
1364 NETRESOURCE * resources;
1365 DWORD countInGroup = 0xFFFFFFFF;
1367 size = 512 * sizeof(NETRESOURCE);
1368 resources = (NETRESOURCE *)new0 byte[size];
1371 WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &buffer[c], &handle);
1374 int returnCode = WNetEnumResource(handle, &countInGroup, resources, &size);
1375 if(returnCode != ERROR_MORE_DATA)
1377 countInGroup = 0xFFFFFFFF;
1378 resources = (NETRESOURCE *)renew0 resources byte[size];
1380 WNetCloseEnum(handle);
1384 file.stats.attribs = FileAttribs { isDirectory = true, isServer = true };
1385 file.stats.size = 0;
1386 file.stats.accessed = file.stats.created = file.stats.modified = 0;
1388 UTF16toUTF8Buffer(resources->lpRemoteName, file.path, MAX_LOCATION);
1390 file.path[2] = (char)toupper(file.path[2]);
1391 GetLastDirectory(file.path, file.name);
1395 d.resources = resources;
1396 d.numResources = countInGroup;
1399 d.workGroups = buffer;
1400 d.numWorkGroups = count;
1407 if(c >= count && buffer) delete buffer;
1414 d.d = opendir((path && path[0]) ? path : ".");
1415 if(d.d && (de = readdir(d.d)))
1419 strcpy(file.path, path);
1421 strcat(file.path, DIR_SEPS);
1423 strcpy(file.name,de->d_name);
1424 strcat(file.path, file.name);
1425 if(!stat(file.path, &s))
1427 file.stats.attribs = (s.st_mode&S_IFDIR) ? FileAttribs { isDirectory = true } : FileAttribs { isFile = true };
1428 file.stats.size = (FileSize)s.st_size;
1429 file.stats.accessed = s.st_atime;
1430 file.stats.modified = s.st_mtime;
1431 file.stats.created = s.st_ctime;
1433 strcpy(d.name, path);
1448 while(result && !result.Validate(extensions))
1449 result = result.FindNext(extensions);
1454 private class FileDesc : struct
1457 char name[MAX_FILENAME];
1458 char path[MAX_LOCATION];
1460 subclass(FileSystem) system;
1463 bool Validate(const char * extensions)
1465 if(strcmp(name, "..") && strcmp(name, ".") && strcmp(name, ""))
1467 if(extensions && !stats.attribs.isDirectory)
1469 char extension[MAX_EXTENSION], compared[MAX_EXTENSION];
1472 GetExtension(name, extension);
1473 for(c = 0; extensions[c];)
1477 for(;(ch = extensions[c]) && !IS_ALUNDER(ch); c++);
1478 for(;(ch = extensions[c]) && IS_ALUNDER(ch); c++)
1479 compared[len++] = ch;
1480 compared[len] = '\0';
1482 if(!strcmpi(extension, compared))
1492 FileDesc FindNext(const char * extensions)
1494 FileDesc result = null;
1500 while(!Validate(extensions))
1506 if(system.FindNext(this))
1513 #if defined(__WIN32__)
1514 if(!strcmp(d.name, "/"))
1517 uint drives = (uint)(uintptr)d.fHandle;
1518 for(c = 0; c<26; c++)
1522 char volume[MAX_FILENAME] = "";
1525 uint16 _wvolume[MAX_FILENAME];
1527 stats.attribs = FileAttribs { isDirectory = true, isDrive = true };
1529 stats.accessed = stats.created = stats.modified = 0;
1530 _wpath[0] = path[0] = (char)('A' + c);
1531 _wpath[1] = path[1] = ':';
1532 _wpath[2] = path[2] = '\\';
1533 _wpath[3] = path[3] = 0;
1534 driveType = GetDriveType(_wpath);
1539 case DRIVE_REMOVABLE: stats.attribs.isRemovable = true; break;
1540 case DRIVE_REMOTE: stats.attribs.isRemote = true; break;
1541 case DRIVE_CDROM: stats.attribs.isCDROM = true; break;
1543 if(driveType == DRIVE_NO_ROOT_DIR)
1545 uint16 remoteName[1024];
1550 status = WNetGetConnection(_wpath, remoteName, &size);
1551 if(status != ERROR_CONNECTION_UNAVAIL)
1558 if(driveType != DRIVE_REMOVABLE && driveType != DRIVE_REMOTE &&
1559 GetVolumeInformation(_wpath, _wvolume, MAX_FILENAME - 1, null, null, null, null, 0))
1561 UTF16toUTF8Buffer(_wvolume, volume, MAX_FILENAME);
1563 sprintf(name, "%s [%s]", path, volume);
1574 d.fHandle = (HANDLE)(uintptr) drives;
1577 else if(d.name[0] != '\\' || d.name[1] != '\\' || strstr(d.name+2, "\\"))
1579 WIN32_FIND_DATA winFile;
1580 if(FindNextFile(d.fHandle, &winFile))
1582 UTF16toUTF8Buffer(winFile.cFileName, name, MAX_FILENAME);
1583 stats.attribs = FileAttribs { };
1584 stats.attribs.isArchive = (winFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? true : false;
1585 stats.attribs.isHidden = (winFile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? true : false;
1586 stats.attribs.isReadOnly = (winFile.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? true : false;
1587 stats.attribs.isSystem = (winFile.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? true : false;
1588 stats.attribs.isTemporary = (winFile.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) ? true : false;
1589 stats.attribs.isDirectory = (winFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false;
1590 stats.attribs.isFile = !(winFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1591 stats.size = winFile.nFileSizeLow;
1593 stats.accessed = Win32FileTimeToTimeStamp(&winFile.ftLastAccessTime);
1594 stats.modified = Win32FileTimeToTimeStamp(&winFile.ftLastWriteTime);
1595 stats.created = Win32FileTimeToTimeStamp(&winFile.ftCreationTime);
1597 strcpy(path, d.name);
1598 PathCat(path, name);
1600 strcat(path, DIR_SEPS);
1601 strcat(path, name);*/
1611 if(d.resource < d.numResources)
1613 stats.attribs = FileAttribs { isDirectory = true, isShare = true };
1615 stats.accessed = stats.created = stats.modified = 0;
1617 UTF16toUTF8Buffer(d.resources[d.resource].lpRemoteName, path, MAX_LOCATION);
1618 GetLastDirectory(path, name);
1633 for(c = d.workGroup; c<d.numWorkGroups; c++)
1635 if(c != d.workGroup)
1637 DWORD countInGroup = 0xFFFFFFFF;
1639 NETRESOURCE * resources;
1640 DWORD size = 512 * sizeof(NETRESOURCE);
1642 resources = (NETRESOURCE *)new0 byte[size];
1644 WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &d.workGroups[c], &handle);
1647 int returnCode = WNetEnumResource(handle, &countInGroup, resources, &size);
1648 if(returnCode != ERROR_MORE_DATA)
1650 countInGroup = 0xFFFFFFFF;
1651 resources = (NETRESOURCE *)renew0 resources byte[size];
1654 WNetCloseEnum(handle);
1655 d.numResources = countInGroup;
1656 d.resources = resources;
1660 if(d.resource < d.numResources)
1662 stats.attribs = FileAttribs { isDirectory = true, isServer = true };
1664 stats.accessed = stats.created = stats.modified = 0;
1666 UTF16toUTF8Buffer(d.resources[d.resource].lpRemoteName, path, MAX_LOCATION);
1668 path[2] = (char)toupper(path[2]);
1669 GetLastDirectory(path, name);
1683 if(d.workGroup == d.numWorkGroups && d.resource == d.numResources)
1685 delete d.workGroups;
1697 strcpy(name,de->d_name);
1698 strcpy(path, d.name);
1699 if(d.name[0] && d.name[1])
1700 strcat(path, DIR_SEPS);
1704 stats.attribs = FileAttribs { };
1705 stats.attribs = (s.st_mode&S_IFDIR) ? FileAttribs { isDirectory = true } : FileAttribs { isFile = true };
1706 stats.size = (FileSize)s.st_size;
1707 stats.accessed = s.st_atime;
1708 stats.modified = s.st_mtime;
1709 stats.created = s.st_ctime;
1726 system.CloseDir(this);
1732 #if defined(__WIN32__)
1733 if(d.fHandle && strcmp(d.name, "/"))
1734 FindClose(d.fHandle);
1745 public struct FileListing
1748 const char * directory;
1749 const char * extensions;
1754 desc = desc.FindNext(extensions);
1756 desc = FileFind(directory, extensions);
1769 property const char * name { get { return desc ? desc.name : null; } };
1770 property const char * path { get { return desc ? desc.path : null; } };
1771 property FileStats stats { get { value = desc ? desc.stats : FileStats { }; } };
1778 public File CreateTemporaryFile(char * tempFileName, const char * template)
1780 #ifndef ECERE_BOOTSTRAP // quick fix for now
1782 #if defined(__unix__) || defined(__APPLE__)
1783 char buffer[MAX_FILENAME];
1785 strcpy(buffer, "/tmp/");
1786 strcat(buffer, template);
1787 //strcpy(buffer, template);
1788 strcat(buffer, "XXXXXX");
1790 fd = mkstemp(buffer);
1791 strcpy(tempFileName, buffer);
1793 f.output = f.input = fdopen(fd, "r+");
1795 char tempPath[MAX_LOCATION];
1796 GetTempPathA(MAX_LOCATION, tempPath); // TODO: Patch this whole thing to support Unicode temp path
1797 GetTempFileNameA(tempPath, template, 0, tempFileName);
1798 f = FileOpen(tempFileName, readWrite);
1808 public void CreateTemporaryDir(char * tempFileName, const char * template)
1810 #ifndef ECERE_BOOTSTRAP // quick fix for now
1811 #if defined(__unix__) || defined(__APPLE__)
1812 char buffer[MAX_FILENAME];
1813 strcpy(buffer, "/tmp/");
1814 strcat(buffer, template);
1815 //strcpy(buffer, template);
1816 strcat(buffer, "XXXXXX");
1819 strcpy(tempFileName, buffer);
1821 char tempPath[MAX_LOCATION];
1822 GetTempPathA(MAX_LOCATION, tempPath); // TODO: Patch this whole thing to support Unicode temp path
1823 GetTempFileNameA(tempPath, template, 0, tempFileName);
1824 DeleteFile(tempFileName);
1825 MakeDir(tempFileName);
1830 public void MakeSlashPath(char * p)
1834 ChangeCh(p, '\\', '/');
1838 public void MakeSystemPath(char * p)
1843 public char * CopySystemPath(const char * p)
1845 char * d = CopyString(p);
1851 public char * CopyUnixPath(const char * p)
1853 char * d = CopyString(p);
1859 public char * GetSystemPathBuffer(char * d, const char * p)
1862 strcpy(d, p ? p : "");
1867 public char * GetSlashPathBuffer(char * d, const char * p)
1870 strcpy(d, p ? p : "");