mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 06:05:58 -06:00
This might bring some incompatibilities in the code that expects wchar to be 16 bit, which escpecially involves dealing with Win32 (and to lesser extend MacOS) APIs, so if your application is doing that, please check all instances of WCHAR (UniChar on MacOS) or even wchar especially type casts. To support host APIs, char16 is introduced (but there is no 16-bit String varian). Use ToSystemCharsetW, FromSystemCharsetW to convert texts to Win32 API. - Support of drawing non-BMP characters in GUI - Vastly improved character font replacement code (when drawing characters missing with requested font, replacement font is used) - Last instances of Win32 ANSI calls (those ending with A) are removed - UTF handling routines are refactored and their's naming is unified - RTF is now being able to handle non-BMP characters (RTF is used as clipboard format for RichText) Other minor changes: - fixed TryRealloc issue - improved MemoryCheck - Removed MemoryAlloc48/MemoryFree48 - In theide Background parsing should less often cause delays in the main thread
1073 lines
22 KiB
C++
1073 lines
22 KiB
C++
#include "Core.h"
|
|
#include "Core.h"
|
|
//#BLITZ_APPROVE
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
#include <sys/types.h>
|
|
#include <utime.h>
|
|
#endif//PLATFORM_POSIX
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
|
|
#define Ptr Ptr_
|
|
#define byte byte_
|
|
#define CY win32_CY_
|
|
|
|
#include <winnls.h>
|
|
#include <winnetwk.h>
|
|
|
|
#include <wincon.h>
|
|
|
|
#ifdef COMPILER_MINGW
|
|
#undef CY
|
|
#endif
|
|
|
|
#include <shlobj.h>
|
|
|
|
#undef Ptr
|
|
#undef byte
|
|
#undef CY
|
|
|
|
#endif
|
|
|
|
namespace Upp {
|
|
|
|
static int sDirSep(int c) {
|
|
return c == '/' || c == '\\' ? c : 0;
|
|
}
|
|
|
|
static bool strecmp0(const char *p, const char *s) {
|
|
while(*p) {
|
|
if(*p == '*') {
|
|
while(*p == '*') p++;
|
|
do
|
|
if(ToUpper(*p) == ToUpper(*s) && strecmp0(p, s)) return true;
|
|
while(*s++);
|
|
return false;
|
|
}
|
|
if(*p == '?') {
|
|
if(*s == '\0') return false;
|
|
}
|
|
else
|
|
if(ToUpper(*p) != ToUpper(*s)) return false;
|
|
s++;
|
|
p++;
|
|
}
|
|
return *s == '\0';
|
|
}
|
|
|
|
bool PatternMatch(const char *p, const char *s) {
|
|
const char *q;
|
|
q = strchr(p, '.');
|
|
if(q) {
|
|
if(q[1] == '\0') {
|
|
if(strchr(s, '.')) return false;
|
|
String h(p, q);
|
|
return strecmp0(h, s);
|
|
}
|
|
else
|
|
if(q[1] == '*' && q[2] == '\0') {
|
|
String h(p, q);
|
|
return strecmp0(h, s) || strecmp0(p, s);
|
|
}
|
|
}
|
|
return strecmp0(p, s);
|
|
}
|
|
|
|
bool PatternMatchMulti(const char *p, const char *s) {
|
|
String pt;
|
|
while(*p) {
|
|
if(*p == ';' || *p == ',' || *p == ' ') {
|
|
if(PatternMatch(pt, s)) return true;
|
|
p++;
|
|
while(*p == ';' || *p == ',' || *p == ' ') p++;
|
|
pt.Clear();
|
|
}
|
|
else
|
|
pt.Cat(*p++);
|
|
}
|
|
return pt.IsEmpty() ? false : PatternMatch(pt, s);
|
|
}
|
|
|
|
const char *GetFileNamePos(const char *fileName) {
|
|
const char *s = fileName;
|
|
const char *fname = s;
|
|
char c;
|
|
while((c = *s++) != '\0')
|
|
#ifdef PLATFORM_WIN32
|
|
if(c == '\\' || c == ':' || c == '/')
|
|
#else
|
|
if(c == '/')
|
|
#endif
|
|
fname = s;
|
|
return fname;
|
|
}
|
|
|
|
const char *GetFileExtPos(const char *fileName) {
|
|
fileName = GetFileNamePos(fileName);
|
|
const char *ext = strrchr(fileName, '.');
|
|
return ext ? ext : fileName + strlen(fileName);
|
|
}
|
|
|
|
bool HasFileExt(const char *path) {
|
|
return *GetFileExtPos(path);
|
|
}
|
|
|
|
bool HasWildcards(const char *fileName) {
|
|
return strchr(fileName, '*') || strchr(fileName, '?');
|
|
}
|
|
|
|
bool IsFullPath(const char *r) {
|
|
#ifdef PLATFORM_WIN32
|
|
return *r && r[1] && (r[1] == ':' || r[0] == '\\' && r[1] == '\\' || r[0] == '/' && r[1] == '/');
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
return *r == '/';
|
|
#endif
|
|
}
|
|
|
|
String GetFileDirectory(const char *fileName) {
|
|
return String(fileName, (int)(GetFileNamePos(fileName) - fileName));
|
|
}
|
|
|
|
String GetFileFolder(const char *fileName) {
|
|
const char *s = GetFileNamePos(fileName);
|
|
#ifdef PLATFORM_WIN32
|
|
if(s - fileName == 3 && fileName[1] == ':')
|
|
return String(fileName, 3);
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
if(s - fileName == 1 && s[0] == '/')
|
|
return "/";
|
|
#endif
|
|
if(s > fileName)
|
|
return String(fileName, (int)(s - fileName) - 1);
|
|
return Null;
|
|
}
|
|
|
|
String GetFileTitle(const char *fileName) {
|
|
fileName = GetFileNamePos(fileName);
|
|
const char *ext = GetFileExtPos(fileName);
|
|
if(*ext)
|
|
return String(fileName, (int)(ext - fileName));
|
|
else
|
|
return fileName;
|
|
}
|
|
|
|
String GetFileExt(const char *fileName) {
|
|
return GetFileExtPos(fileName);
|
|
}
|
|
|
|
String GetFileName(const char *fileName) {
|
|
return GetFileNamePos(fileName);
|
|
}
|
|
|
|
String AppendFileName(const String& path, const char *fileName) {
|
|
String result = path;
|
|
if(result.GetLength() && *result.Last() != DIR_SEP && *fileName != DIR_SEP)
|
|
result += DIR_SEP;
|
|
result += fileName;
|
|
return result;
|
|
}
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
bool PathIsEqual(const char *p1, const char *p2)
|
|
{
|
|
return ToLower(NormalizePath(p1)) == ToLower(NormalizePath(p2));
|
|
}
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
bool PathIsEqual(const char *p1, const char *p2)
|
|
{
|
|
return NormalizePath(p1) == NormalizePath(p2);
|
|
}
|
|
#endif
|
|
|
|
#ifndef PLATFORM_WINCE
|
|
String GetCurrentDirectory() {
|
|
#if defined(PLATFORM_WIN32)
|
|
WCHAR h[MAX_PATH];
|
|
GetCurrentDirectoryW(MAX_PATH, h);
|
|
return FromSystemCharsetW(h);
|
|
#elif defined(PLATFORM_POSIX)
|
|
char h[1024];
|
|
return getcwd(h, 1024) ? FromSystemCharset(h) : String();
|
|
#else
|
|
#error GetCurrentDirectory not implemented for this platform, comment this line to get Null
|
|
return Null;
|
|
#endif//PLATFORM
|
|
}
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
bool SetCurrentDirectory(const char *path)
|
|
{
|
|
return chdir(path) == 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PLATFORM_WIN32) && !defined(PLATFORM_WINCE)
|
|
|
|
String GetTempPath()
|
|
{
|
|
WCHAR h[MAX_PATH];
|
|
GetTempPathW(MAX_PATH, h);
|
|
return FromSystemCharsetW(h);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
|
|
String GetTempPath()
|
|
{
|
|
return FromSystemCharset(P_tmpdir);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef PLATFORM_WINCE
|
|
String GetTempFileName(const char *prefix) {
|
|
Uuid id = Uuid::Create();
|
|
return AppendFileName(GetTempPath(), String(prefix) + Format(id) + ".tmp");
|
|
}
|
|
#endif
|
|
|
|
String FromUnixName(const char* fn, const char* stop = NULL) {
|
|
String s;
|
|
char c;
|
|
while(fn != stop && (c = *fn++))
|
|
s += (c == '/' ? '\\' : c);
|
|
return s;
|
|
}
|
|
|
|
String ToUnixName(const char* fn, const char* stop = NULL) {
|
|
String s;
|
|
char c;
|
|
while(fn != stop && (c = *fn++))
|
|
s += (c == '\\' ? '/' : c);
|
|
return s;
|
|
}
|
|
|
|
String GetFullPath(const char *file) {
|
|
#ifdef PLATFORM_WIN32
|
|
String ufn = FromUnixName(file);
|
|
WCHAR h[MAX_PATH];
|
|
GetFullPathNameW(ToSystemCharsetW(ufn), MAX_PATH, h, 0);
|
|
return FromSystemCharsetW(h);
|
|
#else
|
|
return NormalizePath(file);
|
|
#endif
|
|
}
|
|
|
|
String GetFileOnPath(const char* file, const char* paths, bool current, const char *curdir) {
|
|
String ufn = NativePath(file);
|
|
if(IsFullPath(ufn) && FileExists(ufn))
|
|
return ufn;
|
|
String fn;
|
|
String cd = curdir;
|
|
if(!curdir)
|
|
cd = GetCurrentDirectory();
|
|
if(current && FileExists(fn = NormalizePath(ufn, cd)))
|
|
;
|
|
else if(paths)
|
|
{
|
|
fn = Null;
|
|
while(*paths) {
|
|
const char* start = paths;
|
|
#ifdef PLATFORM_WIN32
|
|
while(*paths && *paths != ';')
|
|
paths++;
|
|
#else
|
|
while(*paths && *paths != ';' && *paths != ':')
|
|
paths++;
|
|
#endif
|
|
String dir(start, (int)(paths - start));
|
|
if(!dir.IsEmpty()) {
|
|
#ifdef PLATFORM_WINCE
|
|
dir = NormalizePath(AppendFileName(NativePath(dir), ufn));
|
|
#else
|
|
dir = NormalizePath(AppendFileName(NativePath(dir), ufn), cd);
|
|
#endif
|
|
if(FileExists(dir)) {
|
|
fn = dir;
|
|
break;
|
|
}
|
|
}
|
|
if(*paths)
|
|
paths++;
|
|
}
|
|
}
|
|
return fn;
|
|
}
|
|
|
|
String WinPath(const char *p) {
|
|
String r;
|
|
while(*p) {
|
|
r.Cat(*p == '/' ? '\\' : *p);
|
|
p++;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
String UnixPath(const char *p) {
|
|
String r;
|
|
while(*p) {
|
|
r.Cat(*p == '\\' ? '/' : *p);
|
|
p++;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
String AppendExt(const char* fn, const char* ext) {
|
|
String result = NativePath(fn);
|
|
if(!HasFileExt(fn))
|
|
result += ext;
|
|
return result;
|
|
}
|
|
|
|
String ForceExt(const char* fn, const char* ext) {
|
|
return NativePath(String(fn, GetFileExtPos(fn))) + ext;
|
|
}
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
|
|
FindFile::~FindFile()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
FindFile::FindFile()
|
|
{
|
|
handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
FindFile::FindFile(const char *name) {
|
|
handle = INVALID_HANDLE_VALUE;
|
|
Search(name);
|
|
}
|
|
|
|
bool FindFile::Search(const char *name) {
|
|
pattern = GetFileName(name);
|
|
path = NormalizePath(GetFileDirectory(name));
|
|
Close();
|
|
handle = FindFirstFileW(ToSystemCharsetW(name), data);
|
|
if(handle == INVALID_HANDLE_VALUE)
|
|
return false;
|
|
if(!PatternMatch(pattern, GetName()))
|
|
return Next();
|
|
return true;
|
|
}
|
|
|
|
static bool sGetSymLinkPath0(const char *linkpath, String *path)
|
|
{
|
|
bool ret = false;
|
|
HRESULT hres;
|
|
IShellLinkW* psl;
|
|
IPersistFile* ppf;
|
|
CoInitialize(NULL);
|
|
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
|
|
(PVOID *) &psl);
|
|
if(SUCCEEDED(hres)) {
|
|
hres = psl->QueryInterface(IID_IPersistFile, (PVOID *) &ppf);
|
|
if(SUCCEEDED(hres)) {
|
|
hres = ppf->Load(ToSystemCharsetW(linkpath), STGM_READ);
|
|
if(SUCCEEDED(hres)) {
|
|
if(path) {
|
|
WCHAR fileW[_MAX_PATH] = {0};
|
|
psl->GetPath(fileW, _MAX_PATH, NULL, 0);
|
|
*path = fileW;
|
|
}
|
|
else
|
|
ret = true;
|
|
}
|
|
ppf->Release();
|
|
}
|
|
psl->Release();
|
|
}
|
|
CoUninitialize();
|
|
return ret;
|
|
}
|
|
|
|
bool FindFile::IsSymLink() const
|
|
{
|
|
String name = GetName();
|
|
if(GetFileExt(name) != ".lnk")
|
|
return false;
|
|
return sGetSymLinkPath0(AppendFileName(path, name), NULL);
|
|
}
|
|
|
|
bool FindFile::IsExecutable() const
|
|
{
|
|
return !IsDirectory() && ToLower(GetName()).EndsWith(".exe");
|
|
}
|
|
|
|
void FindFile::Close() {
|
|
if(handle != INVALID_HANDLE_VALUE) FindClose(handle);
|
|
handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
bool FindFile::Next0() {
|
|
if(!FindNextFileW(handle, data)) {
|
|
Close();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool FindFile::Next()
|
|
{
|
|
for(;;) {
|
|
if(!Next0())
|
|
return false;
|
|
if(PatternMatch(pattern, GetName()))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
String FindFile::GetName() const
|
|
{
|
|
return FromSystemCharsetW(data->cFileName);
|
|
}
|
|
|
|
int64 FindFile::GetLength() const
|
|
{
|
|
return (int64)data->nFileSizeLow | ((int64)data->nFileSizeHigh << 32);
|
|
}
|
|
|
|
bool FindFile::IsFolder() const {
|
|
auto h = data->cFileName;
|
|
return IsDirectory() && !(h[0] == '.' && h[1] == 0) && !(h[0] == '.' && h[1] == '.' && h[2] == 0);
|
|
}
|
|
|
|
String NormalizePath(const char *path, const char *currdir)
|
|
{
|
|
String join_path;
|
|
if(!IsFullPath(path))
|
|
path = join_path = AppendFileName(currdir, path);
|
|
String out;
|
|
if(*path && path[1] == ':') {
|
|
out << path[0] << ":\\";
|
|
path += 3;
|
|
}
|
|
else
|
|
if(path[0] == '\\' && path[1] == '\\') {
|
|
out = "\\\\";
|
|
path += 2;
|
|
}
|
|
else
|
|
if(sDirSep(*path)) {
|
|
if(*currdir)
|
|
out << *currdir << ':';
|
|
out.Cat(DIR_SEP);
|
|
path++;
|
|
}
|
|
int outstart = out.GetLength();
|
|
while(*path) {
|
|
if(sDirSep(*path)) {
|
|
while(sDirSep(*path))
|
|
path++;
|
|
if(*path == '\0')
|
|
break;
|
|
if(out.IsEmpty() || *out.Last() != DIR_SEP)
|
|
out.Cat(DIR_SEP);
|
|
}
|
|
const char *b = path;
|
|
while(*path && !sDirSep(*path))
|
|
path++;
|
|
if(path - b == 1 && *b == '.')
|
|
; //no-op
|
|
else if(path - b == 2 && *b == '.' && b[1] == '.') {
|
|
const char *ob = ~out + outstart, *oe = out.End();
|
|
if(oe - 1 > ob && oe[-1] == DIR_SEP)
|
|
oe--;
|
|
while(oe > ob && oe[-1] != DIR_SEP)
|
|
oe--;
|
|
out.Trim((int)(oe - out.Begin()));
|
|
}
|
|
else
|
|
out.Cat(b, (int)(path - b));
|
|
}
|
|
return out;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
|
|
void FindFile::Close() {
|
|
if(dir) {
|
|
closedir(dir);
|
|
dir = NULL;
|
|
}
|
|
}
|
|
|
|
bool FindFile::IsFolder() const {
|
|
return IsDirectory()
|
|
&& !(name[0] == '.' && name[1] == '\0')
|
|
&& !(name[0] == '.' && name[1] == '.' && name[2] == '\0');
|
|
}
|
|
|
|
struct stat& FindFile::Stat() const {
|
|
if(!statis) {
|
|
statis = true;
|
|
if(file)
|
|
stat(ToSystemCharset(AppendFileName(path, name)), &statf);
|
|
}
|
|
return statf;
|
|
}
|
|
|
|
bool FindFile::CanMode(dword usr, dword grp, dword oth) const
|
|
{
|
|
const struct stat& s = Stat();
|
|
dword mode = GetMode();
|
|
static uid_t uid = getuid();
|
|
static gid_t gid = getgid();
|
|
return (mode & oth) ||
|
|
(mode & grp) && gid == s.st_gid ||
|
|
(mode & usr) && uid == s.st_uid;
|
|
}
|
|
|
|
bool FindFile::IsSymLink() const
|
|
{
|
|
if(file) {
|
|
struct stat stf;
|
|
lstat(AppendFileName(path, name), &stf);
|
|
return S_ISLNK(stf.st_mode);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool FindFile::IsExecutable() const
|
|
{
|
|
return !IsDirectory() && ((S_IXUSR|S_IXGRP|S_IXOTH) & GetMode());
|
|
}
|
|
|
|
bool FindFile::Next() {
|
|
file = false;
|
|
if(!dir) return false;
|
|
statis = false;
|
|
for(;;) {
|
|
struct dirent *e = readdir(dir);
|
|
if(!e) {
|
|
name.Clear();
|
|
file = false;
|
|
Close();
|
|
return false;
|
|
}
|
|
name = FromSystemCharset(e->d_name);
|
|
if(PatternMatch(pattern, name)) {
|
|
file = true;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FindFile::Search(const char *fn) {
|
|
Close();
|
|
path = NormalizePath(GetFileDirectory(fn));
|
|
statis = false;
|
|
file = false;
|
|
if(HasWildcards(fn)) {
|
|
pattern = GetFileName(fn);
|
|
dir = opendir(ToSystemCharset(path));
|
|
return Next();
|
|
}
|
|
else {
|
|
name = GetFileName(fn);
|
|
if(stat(ToSystemCharset(fn), &statf)) return false;
|
|
statis = true;
|
|
file = true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
FindFile::FindFile(const char *fn) {
|
|
dir = NULL;
|
|
Search(fn);
|
|
}
|
|
|
|
String NormalizePath(const char *path, const char *currdir) {
|
|
Vector<String> si = Split(path, sDirSep);
|
|
Vector<String> p;
|
|
int i = 0;
|
|
String out;
|
|
if(path[0] == '~') {
|
|
out = GetHomeDirectory();
|
|
i++;
|
|
}
|
|
else
|
|
if(sDirSep(path[0]))
|
|
out = (sDirSep(path[1]) ? "//" : "/");
|
|
else {
|
|
out = (sDirSep(currdir[0]) && sDirSep(currdir[1]) ? "//" : "/");
|
|
p = Split(currdir, sDirSep);
|
|
}
|
|
for(; i < si.GetCount(); i++) {
|
|
String s = si[i];
|
|
if(s != "." && !s.IsEmpty()) {
|
|
if(s[0] == '.' && s[1] == '.') {
|
|
if(!p.IsEmpty()) p.Drop();
|
|
}
|
|
else
|
|
p.Add(s);
|
|
}
|
|
}
|
|
out.Cat(Join(p, DIR_SEPS));
|
|
return out;
|
|
}
|
|
|
|
#endif//PLATFORM_POSIX
|
|
|
|
String FindFile::GetPath() const
|
|
{
|
|
return AppendFileName(path, GetName());
|
|
}
|
|
|
|
bool FileExists(const char *name) {
|
|
FindFile ff(name);
|
|
return ff && ff.IsFile();
|
|
}
|
|
|
|
int64 GetFileLength(const char *name) {
|
|
FindFile ff(name);
|
|
return ff ? ff.GetLength() : -1;
|
|
}
|
|
|
|
bool DirectoryExists(const char *name) {
|
|
FindFile ff(name + String("/*"));
|
|
return ff;
|
|
}
|
|
|
|
String NormalizePath(const char *path) {
|
|
#ifdef PLATFORM_WINCE
|
|
return NormalizePath(path, "");
|
|
#else
|
|
return NormalizePath(path, GetCurrentDirectory());
|
|
#endif
|
|
}
|
|
|
|
bool FileCopy(const char *oldname, const char *newname)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
return CopyFileW(ToSystemCharsetW(oldname), ToSystemCharsetW(newname), false);
|
|
#elif defined(PLATFORM_POSIX)
|
|
FileIn fi(oldname);
|
|
if(!fi.IsOpen())
|
|
return false;
|
|
FileOut fo(newname);
|
|
if(!fo.IsOpen())
|
|
return false;
|
|
CopyStream(fo, fi, fi.GetLeft());
|
|
fi.Close();
|
|
fo.Close();
|
|
if(fo.IsError())
|
|
{
|
|
unlink(newname);
|
|
return false;
|
|
}
|
|
SetFileTime(newname, GetFileTime(oldname));
|
|
return true;
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
}
|
|
|
|
bool FileMove(const char *oldname, const char *newname)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
return !!MoveFileW(ToSystemCharsetW(oldname), ToSystemCharsetW(newname));
|
|
#elif defined(PLATFORM_POSIX)
|
|
return !rename(ToSystemCharset(oldname), ToSystemCharset(newname));
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
}
|
|
|
|
bool FileDelete(const char *filename)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
return !!DeleteFileW(ToSystemCharsetW(filename));
|
|
#elif defined(PLATFORM_POSIX)
|
|
return !unlink(ToSystemCharset(filename));
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
return false;
|
|
}
|
|
|
|
bool DirectoryDelete(const char *dirname)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
return !!RemoveDirectoryW(ToSystemCharsetW(dirname));
|
|
#elif defined(PLATFORM_POSIX)
|
|
return !rmdir(ToSystemCharset(dirname));
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
return false;
|
|
}
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
int Compare_FileTime(const FileTime& fa, const FileTime& fb)
|
|
{
|
|
return CompareFileTime(&fa, &fb);
|
|
}
|
|
#endif
|
|
|
|
Time FileGetTime(const char *filename)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
HANDLE handle;
|
|
handle = CreateFileW(ToSystemCharsetW(filename), GENERIC_READ,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
if(handle == INVALID_HANDLE_VALUE)
|
|
return Null;
|
|
FileTime ft;
|
|
bool res = GetFileTime(handle, 0, 0, &ft);
|
|
CloseHandle(handle);
|
|
return res ? Time(ft) : Time(Null);
|
|
#elif defined(PLATFORM_POSIX)
|
|
struct stat st;
|
|
if(stat(ToSystemCharset(filename), &st))
|
|
return Null;
|
|
return Time(st.st_mtime);
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
}
|
|
|
|
FileTime GetFileTime(const char *filename)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
HANDLE handle;
|
|
handle = CreateFileW(ToSystemCharsetW(filename), GENERIC_READ,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
FileTime ft0;
|
|
memset(&ft0, 0, sizeof(ft0));
|
|
if(handle == INVALID_HANDLE_VALUE)
|
|
return ft0;
|
|
FileTime ft;
|
|
bool res = GetFileTime(handle, 0, 0, &ft);
|
|
CloseHandle(handle);
|
|
return res ? ft : ft0;
|
|
#elif defined(PLATFORM_POSIX)
|
|
struct stat st;
|
|
if(stat(ToSystemCharset(filename), &st))
|
|
return 0;
|
|
return st.st_mtime;
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
}
|
|
|
|
bool SetFileTime(const char *filename, FileTime ft)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
HANDLE handle;
|
|
handle = CreateFileW(ToSystemCharsetW(filename), GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
if(handle == INVALID_HANDLE_VALUE)
|
|
return false;
|
|
bool res = SetFileTime(handle, 0, 0, &ft);
|
|
CloseHandle(handle);
|
|
return res;
|
|
#elif defined(PLATFORM_POSIX)
|
|
struct utimbuf ub;
|
|
ub.actime = ub.modtime = ft;
|
|
return !utime(ToSystemCharset(filename), &ub);
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
}
|
|
|
|
bool FileSetTime(const char *filename, Time time)
|
|
{
|
|
return SetFileTime(filename, TimeToFileTime(time));
|
|
}
|
|
|
|
FileTime TimeToFileTime(Time time)
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
SYSTEMTIME tm;
|
|
Zero(tm);
|
|
tm.wYear = time.year;
|
|
tm.wMonth = time.month;
|
|
tm.wDay = time.day;
|
|
tm.wHour = time.hour;
|
|
tm.wMinute = time.minute;
|
|
tm.wSecond = time.second;
|
|
FileTime ftl, ftg;
|
|
SystemTimeToFileTime(&tm, &ftl);
|
|
LocalFileTimeToFileTime(&ftl, &ftg);
|
|
return ftg;
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
struct tm t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.tm_sec = time.second;
|
|
t.tm_min = time.minute;
|
|
t.tm_hour = time.hour;
|
|
t.tm_mday = time.day;
|
|
t.tm_mon = time.month - 1;
|
|
t.tm_year = time.year - 1900;
|
|
t.tm_isdst = -1;
|
|
return mktime(&t);
|
|
#endif
|
|
}
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
bool DirectoryCreate(const char *path, int mode)
|
|
{
|
|
return ::mkdir(ToSystemCharset(path), mode) == 0;
|
|
}
|
|
|
|
bool RealizePath(const String& file, int mode)
|
|
{
|
|
return RealizeDirectory(GetFileFolder(file), mode);
|
|
}
|
|
#else
|
|
bool DirectoryCreate(const char *path)
|
|
{
|
|
return !!CreateDirectoryW(ToSystemCharsetW(path), 0);
|
|
}
|
|
|
|
bool RealizePath(const String& file)
|
|
{
|
|
return RealizeDirectory(GetFileFolder(file));
|
|
}
|
|
#endif
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
#define DIR_MIN 3 //!! wrong! what about \a\b\c ?
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
#define DIR_MIN 1
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
bool RealizeDirectory(const String& d, int mode)
|
|
#else
|
|
bool RealizeDirectory(const String& d)
|
|
#endif
|
|
{
|
|
String dir = NormalizePath(d);
|
|
Vector<String> p;
|
|
while(dir.GetLength() > DIR_MIN && !DirectoryExists(dir)) {
|
|
p.Add(dir);
|
|
dir = GetFileFolder(dir);
|
|
}
|
|
for(int i = p.GetCount() - 1; i >= 0; i--)
|
|
#ifdef PLATFORM_POSIX
|
|
if(!DirectoryCreate(p[i], mode))
|
|
#else
|
|
if(!DirectoryCreate(p[i]))
|
|
#endif
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void SetWritePermission(const char *path)
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
SetFileAttributes(path, GetFileAttributes(path) & ~FILE_ATTRIBUTE_READONLY);
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
chmod(path, S_IRWXU);
|
|
#endif
|
|
}
|
|
|
|
bool DeleteFolderDeep(const char *dir, bool rdonly)
|
|
{
|
|
bool ok = true;
|
|
{
|
|
FindFile ff(AppendFileName(dir, "*.*"));
|
|
while(ff) {
|
|
String name = ff.GetName();
|
|
String p = AppendFileName(dir, name);
|
|
if(ff.IsFile() || ff.IsSymLink()) {
|
|
if(ff.IsReadOnly() && rdonly)
|
|
SetWritePermission(p);
|
|
ok = ok && FileDelete(p);
|
|
}
|
|
else
|
|
if(ff.IsFolder())
|
|
ok = ok && DeleteFolderDeep(p, rdonly);
|
|
ff.Next();
|
|
}
|
|
}
|
|
SetWritePermission(dir);
|
|
return ok && DirectoryDelete(dir);
|
|
}
|
|
|
|
String GetSymLinkPath(const char *linkpath)
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
String path;
|
|
sGetSymLinkPath0(linkpath, &path);
|
|
return path;
|
|
#else
|
|
char buff[_MAX_PATH + 1];
|
|
int len = readlink(linkpath, buff, _MAX_PATH);
|
|
if(len > 0 && len < _MAX_PATH)
|
|
return String(buff, len);
|
|
return Null;
|
|
#endif
|
|
}
|
|
|
|
FileSystemInfo::FileInfo::FileInfo()
|
|
: length(Null), read_only(false), is_directory(false)
|
|
, is_folder(false), is_file(false), is_symlink(false), is_archive(false)
|
|
, is_compressed(false), is_hidden(false), is_read_only(false), is_system(false)
|
|
, is_temporary(false), root_style(ROOT_NO_ROOT_DIR)
|
|
{}
|
|
|
|
FileSystemInfo& StdFileSystemInfo()
|
|
{
|
|
static FileSystemInfo h;
|
|
return h;
|
|
}
|
|
|
|
int FileSystemInfo::GetStyle() const
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
return STYLE_WIN32;
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
return STYLE_POSIX;
|
|
#endif
|
|
}
|
|
|
|
Array<FileSystemInfo::FileInfo> FileSystemInfo::Find(String mask, int max_count, bool unmounted) const
|
|
{
|
|
Array<FileInfo> fi;
|
|
if(IsNull(mask))
|
|
{ // root
|
|
#ifdef PLATFORM_WINCE
|
|
FileInfo& f = fi.Add();
|
|
f.filename = "\\";
|
|
f.root_style = ROOT_FIXED;
|
|
#elif defined(PLATFORM_WIN32)
|
|
WCHAR drive[4] = L"?:\\";
|
|
for(int c = 'A'; c <= 'Z'; c++) {
|
|
*drive = c;
|
|
int n = GetDriveTypeW(drive);
|
|
if(n == DRIVE_NO_ROOT_DIR)
|
|
continue;
|
|
FileInfo& f = fi.Add();
|
|
f.filename = drive;
|
|
WCHAR name[256], system[256];
|
|
DWORD d;
|
|
if(c != 'A' && c != 'B' && n != DRIVE_UNKNOWN) {
|
|
bool b = GetVolumeInformationW(drive, name, 256, &d, &d, &d, system, 256);
|
|
if(b) {
|
|
if(*name) f.root_desc << " " << FromSystemCharsetW(name);
|
|
}
|
|
else if(n == DRIVE_REMOVABLE || n == DRIVE_CDROM) {
|
|
if(unmounted) {
|
|
f.root_desc = t_("Empty drive");
|
|
} else {
|
|
fi.Drop();
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
switch(n)
|
|
{
|
|
default:
|
|
case DRIVE_UNKNOWN: f.root_style = ROOT_UNKNOWN; break;
|
|
case DRIVE_NO_ROOT_DIR: f.root_style = ROOT_NO_ROOT_DIR; break;
|
|
case DRIVE_REMOVABLE: f.root_style = ROOT_REMOVABLE; break;
|
|
case DRIVE_FIXED: f.root_style = ROOT_FIXED; break;
|
|
case DRIVE_REMOTE: f.root_style = ROOT_REMOTE; break;
|
|
case DRIVE_CDROM: f.root_style = ROOT_CDROM; break;
|
|
case DRIVE_RAMDISK: f.root_style = ROOT_RAMDISK; break;
|
|
}
|
|
}
|
|
|
|
#elif defined(PLATFORM_POSIX)
|
|
FileInfo& f = fi.Add();
|
|
f.filename = "/";
|
|
f.root_style = ROOT_FIXED;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
FindFile ff;
|
|
if(ff.Search(mask))
|
|
do
|
|
{
|
|
FileInfo& f = fi.Add();
|
|
f.filename = ff.GetName();
|
|
#ifndef PLATFORM_POSIX
|
|
f.is_archive = ff.IsArchive();
|
|
f.is_compressed = ff.IsCompressed();
|
|
f.is_hidden = ff.IsHidden();
|
|
f.is_system = ff.IsSystem();
|
|
f.is_temporary = ff.IsTemporary();
|
|
#endif
|
|
f.is_read_only = ff.IsReadOnly();
|
|
f.length = ff.GetLength();
|
|
#ifdef PLATFORM_POSIX
|
|
f.creation_time = ff.GetLastChangeTime();
|
|
f.unix_mode = ff.GetMode();
|
|
#endif
|
|
f.last_access_time = ff.GetLastAccessTime();
|
|
f.last_write_time = ff.GetLastWriteTime();
|
|
#ifdef PLATFORM_WIN32
|
|
f.creation_time = ff.GetCreationTime();
|
|
f.unix_mode = 0;
|
|
#endif
|
|
f.read_only = ff.IsReadOnly();
|
|
f.is_directory = ff.IsDirectory();
|
|
f.is_folder = ff.IsFolder();
|
|
f.is_file = ff.IsFile();
|
|
#ifdef PLATFORM_POSIX
|
|
f.is_symlink = ff.IsSymLink();
|
|
#endif
|
|
}
|
|
while(ff.Next() && fi.GetCount() < max_count);
|
|
}
|
|
return fi;
|
|
}
|
|
|
|
bool FileSystemInfo::CreateFolder(String path, String& error) const
|
|
{
|
|
if(UPP::DirectoryCreate(path))
|
|
return true;
|
|
error = GetErrorMessage(GetLastError());
|
|
return false;
|
|
}
|
|
|
|
bool FileSystemInfo::FolderExists(String path) const
|
|
{
|
|
if(IsNull(path))
|
|
return true;
|
|
if(path.Find('*') >= 0 || path.Find('?') >= 0)
|
|
return false;
|
|
Array<FileInfo> fi = Find(path, 1);
|
|
return !fi.IsEmpty() && fi[0].is_directory;
|
|
}
|
|
|
|
static void FindAllPaths_(Vector<String>& r, const String& dir, const char *patterns, dword opt)
|
|
{
|
|
for(FindFile ff(dir + "/*.*"); ff; ff++) {
|
|
String p = ff.GetPath();
|
|
if(PatternMatchMulti(patterns, ff.GetName()) &&
|
|
((opt & FINDALLFILES) && ff.IsFile() || (opt & FINDALLFOLDERS) && ff.IsFolder()))
|
|
r.Add(ff.GetPath());
|
|
if(ff.IsFolder())
|
|
FindAllPaths_(r, ff.GetPath(), patterns, opt);
|
|
}
|
|
}
|
|
|
|
Vector<String> FindAllPaths(const String& dir, const char *patterns, dword opt)
|
|
{
|
|
Vector<String> r;
|
|
FindAllPaths_(r, dir, patterns, opt);
|
|
return r;
|
|
}
|
|
|
|
}
|