ultimatepp/bazaar/Functions4U/Functions4U.cpp
koldo 39c2bc0a7b Functions4U: GetDesktopManagerNew and Trash doc. moved from SysInfo
git-svn-id: svn://ultimatepp.org/upp/trunk@1870 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2010-01-06 16:57:41 +00:00

1378 lines
34 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <Core/Core.h>
#if defined(PLATFORM_WIN32)
#include <shellapi.h>
#endif
#include "Functions4U.h"
/////////////////////////////////////////////////////////////////////
// LaunchFile
#if defined(PLATFORM_WIN32)
bool LaunchFileCreateProcess(const String file) {
STARTUPINFOW startInfo;
PROCESS_INFORMATION procInfo;
ZeroMemory(&startInfo, sizeof(startInfo));
startInfo.cb = sizeof(startInfo);
ZeroMemory(&procInfo, sizeof(procInfo));
WString wexec;
wexec = Format("\"%s\" \"%s\"", GetExtExecutable(GetFileExt(file)), file).ToWString();
WStringBuffer wsbexec(wexec);
if(!CreateProcessW(NULL, wsbexec, NULL, NULL, FALSE, 0, NULL, NULL, &startInfo, &procInfo))
return false;
WaitForSingleObject(procInfo.hProcess, 0);
CloseHandle(procInfo.hProcess);
CloseHandle(procInfo.hThread);
return true;
}
bool LaunchFileShellExecute(const String file) {
HINSTANCE ret;
WString fileName(file);
ret = ShellExecuteW(NULL, L"open", fileName, NULL, L".", SW_SHOWNORMAL);
return (int)ret > 32;
}
bool LaunchFile(const String file) {
if (!LaunchFileShellExecute(file)) // First try
return LaunchFileCreateProcess(file); // Second try
return true;
}
#endif
#ifdef PLATFORM_POSIX
String GetDesktopManagerNew() {
if(GetEnv("GNOME_DESKTOP_SESSION_ID").GetCount() || GetEnv("GNOME_KEYRING_SOCKET").GetCount())
return "gnome";
else if(GetEnv("KDE_FULL_SESSION").GetCount() || GetEnv("KDEDIR").GetCount() || GetEnv("KDE_MULTIHEAD").GetCount())
return "kde";
else {
StringParse desktopStr;
if (Sys("xprop -root _DT_SAVE_MODE").Find("xfce") >= 0)
return "xfce";
else if ((desktopStr = Sys("xprop -root")).Find("ENLIGHTENMENT") >= 0)
return "enlightenment";
else
return GetEnv("DESKTOP_SESSION");
}
}
bool LaunchFile(const String file) {
int ret;
if (GetDesktopManagerNew() == "gnome")
ret = system("gnome-open \"" + file + "\"");
else if (GetDesktopManagerNew() == "kde")
ret = system("kfmclient exec \"" + file + "\" &");
else if (GetDesktopManagerNew() == "enlightenment") {
String mime = GetExtExecutable(GetFileExt(file));
String program = mime.Left(mime.Find(".")); // Left side of mime executable is the program to run
ret = system(program + " \"" + file + "\" &");
} else
ret = system("xdg-open \"" + file + "\"");
return (ret >= 0);
}
#endif
/////////////////////////////////////////////////////////////////////
// General utilities
bool FileCat(const char *file, const char *appendFile) {
if (!FileExists(file))
return FileCopy(appendFile, file);
FileAppend f(file);
if(!f.IsOpen())
return false;
FileIn fi(appendFile);
if(!fi.IsOpen())
return false;
CopyStream(f, fi, fi.GetLeft());
fi.Close();
f.Close();
if(f.IsError())
return false;
return true;
}
bool FileStrAppend(const char *file, const char *str) {
FileAppend f(file);
if(!f.IsOpen())
return false;
f << str;
f.Close();
if(f.IsError())
return false;
return true;
}
String FormatLong(long a) {
return Sprintf("%ld", a);
}
String Replace(String str, String find, String replace) {
String ret;
int lenStr = str.GetCount();
int lenFind = find.GetCount();
int i = 0, j;
while ((j = str.Find(find, i)) >= i) {
ret += str.Mid(i, j-i) + replace;
i = j + lenFind;
if (i >= lenStr)
break;
}
ret += str.Mid(i);
return ret;
}
bool FileSetReadOnly(String fileName, bool readOnly)
{
#if defined(PLATFORM_WIN32)
WString wfile = fileName.ToWString();
DWORD attr = GetFileAttributesW(wfile);
if (attr == INVALID_FILE_ATTRIBUTES)
return false;
DWORD newattr;
if (readOnly)
newattr = attr | FILE_ATTRIBUTE_READONLY;
else
newattr = attr & ~FILE_ATTRIBUTE_READONLY;
if (attr != newattr)
return SetFileAttributesW(wfile, newattr);
else
return true;
#else
struct stat buffer;
int status;
if(0 != stat(fileName, &buffer))
return false;
mode_t newmode;
if (readOnly) {
newmode = buffer.st_mode | S_IRUSR | S_IRGRP | S_IROTH;
newmode = newmode & ~S_IWUSR & ~S_IWGRP & ~S_IWOTH;
} else {
newmode = buffer.st_mode | S_IRUSR | S_IRGRP | S_IROTH;
newmode = newmode | S_IWUSR | S_IWGRP | S_IWOTH;
}
if (newmode != buffer.st_mode)
return 0 == chmod(fileName, newmode);
else
return true;
#endif
}
#ifdef PLATFORM_POSIX
String GetTrashBinDirectory()
{
return AppendFileName(GetHomeDirectory(), ".local/share/Trash/files");
}
bool FileToTrashBin(const char *path)
{
String newPath = AppendFileName(GetTrashBinDirectory(), GetFileName(path));
return FileMove(path, newPath);
}
int64 TrashBinGetCount()
{
int64 ret = 0;
FindFile ff;
if(ff.Search(AppendFileName(GetTrashBinDirectory(), "*"))) {
do {
String name = ff.GetName();
if (name != "." && name != "..")
ret++;
} while(ff.Next());
}
return ret;
}
bool TrashBinClear()
{
FindFile ff;
String trashBinDirectory = GetTrashBinDirectory();
if(ff.Search(AppendFileName(trashBinDirectory, "*"))) {
do {
String name = ff.GetName();
if (name != "." && name != "..") {
String path = AppendFileName(trashBinDirectory, name);
if (ff.IsFile())
FileDelete(path);
else if (ff.IsDirectory())
DeleteFolderDeep(path);
}
} while(ff.Next());
}
return true;
}
#endif
#if defined(PLATFORM_WIN32)
bool FileToTrashBin(const char *path)
{
if (!FileExists(path) && !DirectoryExists(path))
return false;
WString ws(path);
ws.Cat() << L'\0'; // This string must be double-null terminated.
SHFILEOPSTRUCTW fileOp;
fileOp.hwnd = NULL;
fileOp.wFunc = FO_DELETE;
fileOp.pFrom = ~ws;
fileOp.pTo = NULL;
fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT;
int ret = SHFileOperationW(&fileOp);
if (0 != ret)
return false;
return true;
}
int64 TrashBinGetCount()
{
SHQUERYRBINFO shqbi;
shqbi.cbSize = sizeof(SHQUERYRBINFO);
if (S_OK != SHQueryRecycleBin(0, &shqbi))
return -1;
return shqbi.i64NumItems;
}
bool TrashBinClear()
{
if (S_OK != SHEmptyRecycleBin(0, 0, SHERB_NOCONFIRMATION | SHERB_NOPROGRESSUI | SHERB_NOSOUND))
return false;
return true;
}
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// This system files are like pipes: it is not possible to get the length to size the buffer
String LoadFile_Safe(String fileName)
{
#ifdef PLATFORM_POSIX
int fid = open(fileName, O_RDONLY);
#else
int fid = _wopen(fileName.ToWString(), O_RDONLY|O_BINARY);
#endif
if (fid < 0)
return String("");
const int size = 1024;
int nsize;
StringBuffer s;
char buf[size];
while((nsize = read(fid, buf, size)) == size)
s.Cat(buf, size);
if (nsize > 1)
s.Cat(buf, nsize-1);
close(fid);
return s;
}
String GetExtExecutable(String ext)
{
String exeFile = "";
if (ext[0] != '.')
ext = String(".") + ext;
#if defined(PLATFORM_WIN32)
String file = AppendFileName(GetHomeDirectory(), String("dummy") + ext); // Required by FindExecutableW
SaveFile(file, " ");
if (!FileExists(file))
return "";
HINSTANCE ret;
WString fileW(file);
WCHAR exe[1024];
ret = FindExecutableW(fileW, NULL, exe);
if ((long)ret > 32)
exeFile = WString(exe).ToString();
DeleteFile(file);
#endif
#ifdef PLATFORM_POSIX
StringParse mime;
//if (LaunchCommand(String("xdg-mime query filetype ") + file, mime) >= 0) // xdg-mime query filetype does not work properly in Enlightenment
mime = LoadFile_Safe("/etc/mime.types"); // Search in /etc/mime.types the mime type for the extension
if ((mime.GoAfter_Init(String(" ") + ext.Right(ext.GetCount()-1))) || (mime.GoAfter_Init(String("\t") + ext.Right(ext.GetCount()-1)))) {
mime.GoBeginLine();
mime = mime.GetText();
exeFile = TrimRight(Sys(String("xdg-mime query default ") + mime));
}
#endif
return exeFile;
}
#if defined(PLATFORM_WIN32)
Array<String> GetDriveList() {
char drvStr[26*4+1]; // A, B, C, ...
Array<String> ret;
int lenDrvStrs = ::GetLogicalDriveStrings(sizeof(drvStr), drvStr);
// To get the error call GetLastError()
if (lenDrvStrs == 0)
return ret;
ret.Add(drvStr);
for (int i = 0; i < lenDrvStrs-1; ++i) {
if (drvStr[i] == '\0')
ret.Add(drvStr + i + 1);
}
return ret;
}
#endif
#if defined(PLATFORM_POSIX)
Array<String> GetDriveList() {
Array<String> ret;
// Search for mountable file systems
String mountableFS;
StringParse sfileSystems(LoadFile_Safe("/proc/filesystems"));
String str;
while (true) {
str = sfileSystems.GetText();
if (str == "")
break;
else if (str != "nodev")
mountableFS << str << ".";
else
str = sfileSystems.GetText();
}
// Get mounted drives
StringParse smounts(LoadFile_Safe("/proc/mounts"));
StringParse smountLine(smounts.GetText("\r\n"));
do {
String devPath = smountLine.GetText();
String mountPath = smountLine.GetText();
String fs = smountLine.GetText();
if ((mountableFS.Find(fs) >= 0) && (mountPath.Find("/dev") < 0) && (mountPath.Find("/rofs") < 0)) // Is mountable
ret.Add(mountPath);
smountLine = smounts.GetText("\r\n");
} while (smountLine != "");
return ret;
}
#endif
String GetFirefoxDownloadFolder()
{
String profilesPath = "mozilla/firefox";
#ifdef PLATFORM_POSIX // Is hidden
profilesPath = String(".") + profilesPath;
#endif
StringParse profiles = LoadFile(AppendFileName(GetAppDataFolder(), AppendFileName(profilesPath, "profiles.ini")));
if (!profiles.GoAfter("Path")) return "";
if (!profiles.GoAfter("=")) return "";
String path = profiles.GetText();
String pathPrefs = AppendFileName(AppendFileName(AppendFileName(GetAppDataFolder(), profilesPath), path), "prefs.js");
StringParse prefs = LoadFile(pathPrefs);
if (!prefs.GoAfter("\"browser.download.dir\"")) {
if (!prefs.GoAfter("\"browser.download.lastDir\""))
return "";
}
if (!prefs.GoAfter(",")) return "";
return prefs.GetText();
}
#if defined(PLATFORM_WIN32)
String GetShellFolder(const char *local, const char *users)
{
String ret = FromSystemCharset(GetWinRegString(local, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
HKEY_CURRENT_USER));
if (ret == "" && *users != '\0')
return FromSystemCharset(GetWinRegString(users, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
HKEY_LOCAL_MACHINE));
return ret;
}
String GetIEDownloadFolder()
{
String ret = FromSystemCharset(GetWinRegString("Download Directory", "Software\\Microsoft\\Internet Explorer", HKEY_CURRENT_USER));
if (ret == "")
ret = FromSystemCharset(GetWinRegString("Save Directory", "Software\\Microsoft\\Internet Explorer\\Main", HKEY_CURRENT_USER));
return ret;
}
String GetDesktopFolder() {return GetShellFolder("Desktop", "Common Desktop");}
String GetProgramsFolder() {return FromSystemCharset(GetWinRegString("ProgramFilesDir", "Software\\Microsoft\\Windows\\CurrentVersion", HKEY_LOCAL_MACHINE));}
String GetAppDataFolder() {return GetShellFolder("AppData", "Common AppData");}
String GetMusicFolder() {return GetShellFolder("My Music", "CommonMusic");}
String GetPicturesFolder() {return GetShellFolder("My Pictures", "CommonPictures");}
String GetVideoFolder() {return GetShellFolder("My Video", "CommonVideo");}
String GetPersonalFolder() {return GetShellFolder("Personal", 0);}
String GetTemplatesFolder() {return GetShellFolder("Templates", "Common Templates");}
String GetDownloadFolder()
{
String browser = GetExtExecutable("html");
browser = ToLower(browser);
if (browser.Find("iexplore") >= 0)
return GetIEDownloadFolder();
else if (browser.Find("firefox") >= 0)
return GetFirefoxDownloadFolder();
return GetDesktopFolder(); // I do not know to do it in other browsers !!
};
String GetTempFolder()
{
String ret;
if ((ret = GetEnv("TEMP")) == "") // One or the other one
ret = GetEnv("TMP");
return ret;
}
String GetOsFolder()
{
char ret[MAX_PATH];
::GetWindowsDirectory(ret, MAX_PATH);
return String(ret);
}
String GetSystemFolder()
{
char ret[MAX_PATH];
::GetSystemDirectory(ret, MAX_PATH);
return String(ret);
}
#endif
#ifdef PLATFORM_POSIX
String GetPathXdg(String xdgConfigHome, String xdgConfigDirs)
{
String ret = "";
if (FileExists(ret = AppendFileName(xdgConfigHome, "user-dirs.dirs"))) ;
else if (FileExists(ret = AppendFileName(xdgConfigDirs, "user-dirs.defaults"))) ;
else if (FileExists(ret = AppendFileName(xdgConfigDirs, "user-dirs.dirs"))) ;
return ret;
}
String GetPathDataXdg(String fileConfig, const char *folder)
{
StringParse fileData = LoadFile(fileConfig);
if (!fileData.GoAfter(folder)) return "";
if (!fileData.GoAfter("=")) return "";
String ret = "";
StringParse path = fileData.GetText();
if(path.GoAfter("$HOME/"))
ret = AppendFileName(GetHomeDirectory(), path.Right());
else if (!FileExists(path))
ret = AppendFileName(GetHomeDirectory(), path);
return ret;
}
String GetShellFolder(const char *local, const char *users)
{
String xdgConfigHome = GetEnv("XDG_CONFIG_HOME");
if (xdgConfigHome == "") // By default
xdgConfigHome = AppendFileName(GetHomeDirectory(), ".config");
String xdgConfigDirs = GetEnv("XDG_CONFIG_DIRS");
if (xdgConfigDirs == "") // By default
xdgConfigDirs = "/etc/xdg";
String xdgFileConfigData = GetPathXdg(xdgConfigHome, xdgConfigDirs);
String ret = GetPathDataXdg(xdgFileConfigData, local);
if (ret == "" && *users != '\0')
return GetPathDataXdg(xdgFileConfigData, users);
else
return ret;
}
String GetDesktopFolder()
{
String ret = GetShellFolder("XDG_DESKTOP_DIR", "DESKTOP");
if (ret.IsEmpty())
return AppendFileName(GetHomeDirectory(), "Desktop");
else
return ret;
}
String GetProgramsFolder() {return String("/usr/bin");}
String GetAppDataFolder() {return GetHomeDirectory();};
String GetMusicFolder() {return GetShellFolder("XDG_MUSIC_DIR", "MUSIC");}
String GetPicturesFolder() {return GetShellFolder("XDG_PICTURES_DIR", "PICTURES");}
String GetVideoFolder() {return GetShellFolder("XDG_VIDEOS_DIR", "VIDEOS");}
String GetPersonalFolder() {return GetShellFolder("XDG_DOCUMENTS_DIR", "DOCUMENTS");}
String GetTemplatesFolder() {return GetShellFolder("XDG_TEMPLATES_DIR", "XDG_TEMPLATES_DIR");}
String GetDownloadFolder()
{
String browser = GetExtExecutable("html");
browser = ToLower(browser);
if (browser.Find("firefox") >= 0)
return GetFirefoxDownloadFolder();
return GetShellFolder("XDG_DOWNLOAD_DIR", "DOWNLOAD");
};
String GetTempFolder()
{
return GetHomeDirectory();
}
String GetOsFolder()
{
return String("/bin");
}
String GetSystemFolder()
{
return String("");
}
#endif
struct StringNormalCompare__ {
int operator()(char a, char b) const { return a - b; }
};
int Compare(const String& a, int i0, const String& b, int len) {
return IterCompare(a.Begin() + i0, a.Begin() + i0 + len, b.Begin(), b.Begin() + len, StringNormalCompare__());
}
int ReverseFind(const String& s, const String& toFind, int from) {
ASSERT(from >= 0 && from <= s.GetLength());
int lc = toFind.GetLength();
for (int i = from; i >= 0; --i) {
if (Compare(s, i, toFind, lc) == 0)
return i;
}
return -1;
}
// Like StrToDate but using Time
const char *StrToTime(struct Upp::Time& d, const char *s) {
s = StrToDate(d, s);
d.hour = 0;
d.minute = 0;
d.second = 0;
const char *fmt = "hms";
while(*fmt) {
while(*s && !IsDigit(*s))
s++;
int n;
if(IsDigit(*s)) {
char *q;
n = strtoul(s, &q, 10);
s = q;
} else
break;
switch(*fmt) {
case 'h':
if(n < 0 || n > 23)
return NULL;
d.hour = n;
break;
case 'm':
if(n < 0 || n > 59)
return NULL;
d.minute = n;
break;
case 's':
if(n < 0 || n > 59)
return NULL;
d.second = n;
break;
default:
NEVER();
}
fmt++;
}
return d.IsValid() ? s : NULL;
}
void StringToHMS(String durat, int &hour, int &min, double &seconds) {
StringParse duration(durat);
String s1, s2, s3;
s1 = duration.GetText(":");
s2 = duration.GetText(":");
s3 = duration.GetText();
if (s3 != "") {
hour = atoi(s1);
min = atoi(s2);
seconds = atof(s3);
} else if (s2 != "") {
hour = 0;
min = atoi(s1);
seconds = atof(s2);
} else {
hour = 0;
min = 0;
seconds = atof(s1);
}
}
double StringToSeconds(String duration) {
int hour, min;
double secs;
StringToHMS(duration, hour, min, secs);
return 60.*hour + 60.*min + secs;
}
String formatSeconds(double seconds) {
String ret = FormatIntDec((int)seconds, 2, '0');
double decs = seconds - (int)seconds;
if (decs > 0)
ret << "." << FormatIntDec((int)(decs*100), 2, '0');
return ret;
}
String HMSToString(int hour, int min, double seconds, bool units) {
String sunits;
if (units) {
if (hour >= 2)
sunits = t_("hours");
else if (hour >= 1)
sunits = t_("hour");
else if (min >= 2)
sunits = t_("mins");
else if (min >= 60)
sunits = t_("min");
else if (seconds > 1)
sunits = t_("secs");
else
sunits = t_("sec");
}
String ret;
if (hour > 0)
ret << hour << ":";
if (min > 0 || hour > 0)
ret << (ret.IsEmpty() ? FormatInt(min) : FormatIntDec(min, 2, '0')) << ":";
ret << (ret.IsEmpty() ? FormatDouble(seconds, 2, FD_REL) : formatSeconds(seconds));
if (units)
ret << " " << sunits;
return ret;
}
String SecondsToString(double seconds, bool units) {
int hour, min;
hour = (int)(seconds/3600.);
seconds -= hour*3600;
min = (int)(seconds/60.);
seconds -= min*60;
return HMSToString(hour, min, seconds, units);
}
String BytesToString(uint64 _bytes)
{
String ret;
uint64 bytes = _bytes;
if (bytes >= 1024) {
bytes /= 1024;
if (bytes >= 1024) {
bytes /= 1024;
if (bytes >= 1024) {
bytes /= 1024;
if (bytes >= 1024) {
bytes /= 1024;
ret = Format("%.1f %s", _bytes/(1024*1024*1024*1024.), "Tb");
} else
ret = Format("%.1f %s", _bytes/(1024*1024*1024.), "Gb");
} else
ret = Format("%.1f %s", _bytes/(1024*1024.), "Mb");
} else
ret = Format("%.1f %s", _bytes/1024., "Kb");
} else
ret << _bytes << " b";
return ret;
}
String RemoveAccent(wchar c) {
WString wsret;
if (IsAlNum(c) || IsSpace(c)) {
wsret.Cat(c);
return wsret.ToString();
}
const WString accented = "ÂÃÀÁÇÈÉÊËẼÌÍÎÏÑÒÓÔÕÙÚÛÝàáâãçèéêëẽìíîïñòóôõùúûýÿ";
const char *unaccented = "AAAACEEEEEIIIINOOOOUUUYaaaaceeeeeiiiinoooouuuyy";
for (int i = 0; accented[i]; ++i) {
if (accented[i] == c) {
wsret.Cat(unaccented[i]);
return wsret.ToString();
}
}
const WString maccented = "ÅåÆæØøþÞßÐðÄäÖöÜü";
const char *unmaccented[] = {"AA", "aa", "AE", "ae", "OE", "oe", "TH", "th", "SS", "ETH",
"eth", "AE", "ae", "OE", "oe", "UE", "ue"};
for (int i = 0; maccented[i]; ++i) {
if (maccented[i] == c)
return unmaccented[i];
}
wsret.Cat(c);
return wsret.ToString();
}
bool IsPunctuation(wchar c) {
const WString punct = "\"'()[]{}<>:;,‒–—―….,¡!¿?«»-"
"‘’“”/\\&@*\\•^©¤฿¢$€ƒ£₦¥₩₪†‡〃"
"#№ºª\%‰‱ ¶′®§℠℗~™_|¦=";
for (int i = 0; punct[i]; ++i) {
if (punct[i] == c)
return true;
}
return false;
}
String RemoveAccents(String str) {
String ret;
WString wstr = str.ToWString();
for (int i = 0; i < wstr.GetCount(); ++i) {
String schar = RemoveAccent(wstr[i]);
if (i == 0 || ((i > 0) && ((IsSpace(wstr[i-1]) || IsPunctuation(wstr[i-1]))))) {
if (schar.GetCount() > 1) {
if (IsUpper(schar[0]) && IsLower(wstr[1]))
schar = schar[0] + ToLower(schar.Mid(1));
}
}
ret += schar;
}
return ret;
}
int DayOfYear(Date d) {
return 1 + d - FirstDayOfYear(d);
}
Color RandomColor() {
int num = Random();
return Color(num&0xFF, (num&0xFF00)>>8, (num&0xFF0000)>>16);
}
String GetUpperFolder(String folderName)
{
if (folderName.IsEmpty())
return "";
#ifdef PLATFORM_WIN32
if (folderName.GetCount() == 3)
#else
if (folderName.GetCount() == 1)
#endif
return folderName;
int len = folderName.GetCount();
if (folderName[len-1] == DIR_SEP)
len--;
int pos = folderName.ReverseFind(DIR_SEP, len-1);
#ifdef PLATFORM_WIN32
if (pos == 2)
#else
if (pos == 0)
#endif
pos++;
return folderName.Left(pos);
}
bool CreateFolderDeep(const char *dir)
{
if (DirectoryExists(dir))
return true;
String upper = GetUpperFolder(dir);
if (CreateFolderDeep(upper))
return DirectoryCreate(dir);
else
return false;
}
bool DeleteFolderDeepWildcards(const char *path)
{
FindFile ff(path);
String dir = GetFileDirectory(path);
while(ff) {
String name = ff.GetName();
String p = AppendFileName(dir, name);
if(ff.IsFile())
FileDelete(p);
else
if(ff.IsFolder())
DeleteFolderDeep(p);
ff.Next();
}
return DirectoryDelete(dir);
}
bool DirectoryCopy_Each(const char *dir, const char *newPlace, String relPath)
{
String dirPath = AppendFileName(dir, relPath);
String newPath = AppendFileName(newPlace, relPath);
FindFile ff(AppendFileName(dirPath, "*.*"));
while(ff) {
if(ff.IsFile())
FileCopy(AppendFileName(dirPath, ff.GetName()), AppendFileName(newPath, ff.GetName()));
else if(ff.IsFolder()) {
DirectoryCreate(AppendFileName(newPath, ff.GetName()));
if(!DirectoryCopy_Each(dir, newPlace, AppendFileName(relPath, ff.GetName())))
return false;
}
ff.Next();
}
return true;
}
bool DirectoryCopy(const char *dir, const char *newPlace)
{
return DirectoryCopy_Each(dir, newPlace, "");
}
void SearchFile_Each(String dir, String condFile, String text, Array<String> &files, Array<String> &errorList)
{
FindFile ff;
if (ff.Search(AppendFileName(dir, condFile))) {
do {
if(ff.IsFile()) {
String p = AppendFileName(dir, ff.GetName());
if (text.IsEmpty())
files.Add(p);
else {
#ifdef PLATFORM_POSIX
FILE *fp = fopen(p, "rb");
#else
FILE *fp = _wfopen(p.ToWString(), L"rb");
#endif
if (fp != NULL) {
int i = 0, c;
while ((c = fgetc(fp)) != EOF) {
if (c == text[i]) {
++i;
if (i == text.GetCount()) {
files.Add(p);
break;
}
} else {
if (i != 0)
fseek(fp, -(i-1), SEEK_CUR);
i = 0;
}
}
fclose(fp);
} else
errorList.Add(AppendFileName(dir, ff.GetName()) + String(": ") + t_("Impossible to open file"));
}
}
} while (ff.Next());
}
ff.Search(AppendFileName(dir, "*"));
do {
String name = ff.GetName();
if(ff.IsDirectory() && name != "." && name != "..") {
String p = AppendFileName(dir, name);
SearchFile_Each(p, condFile, text, files, errorList);
}
} while (ff.Next());
}
Array<String> SearchFile(String dir, String condFile, String text, Array<String> &errorList)
{
Array<String> ret;
errorList.Clear();
SearchFile_Each(dir, condFile, text, ret, errorList);
return ret;
}
Array<String> SearchFile(String dir, String condFile, String text)
{
Array<String> errorList;
Array<String> ret;
SearchFile_Each(dir, condFile, text, ret, errorList);
return ret;
}
bool fileDataSortAscending;
char fileDataSortBy;
FileDataArray::FileDataArray(bool use)
{
Clear();
fileDataSortAscending = true;
fileDataSortBy = 'n';
useId = use;
}
bool FileDataArray::Init(String folder, FileDataArray &orig, FileDiffArray &diff)
{
basePath = orig.basePath;
fileCount = orig.fileCount;
folderCount = orig.folderCount;
fileSize = orig.fileSize;
useId = orig.useId;
fileList.SetCount(orig.GetCount());
for (int i = 0; i < orig.GetCount(); ++i)
fileList[i] = orig[i];
for (int i = 0; i < diff.GetCount(); ++i) {
long id;
if (diff[i].action != 'n') {
id = Find(diff[i].relPath, diff[i].fileName, diff[i].isFolder);
if (id < 0)
return false;
}
switch(diff[i].action) {
case 'u':
fileList[id].id = diff[i].idMaster;
fileList[id].length = diff[i].lengthMaster;
fileList[id].t = diff[i].tMaster;
break;
case 'n':
fileList.Add(FileData(diff[i].isFolder, diff[i].fileName, diff[i].relPath, diff[i].lengthMaster, diff[i].tMaster, diff[i].idMaster));
if (diff[i].isFolder)
folderCount++;
else
fileCount++;
break;
case 'd':
fileList.Remove(id);
if (diff[i].isFolder)
folderCount--;
else
fileCount--;
break;
break;
case 'p':
SetLastError(t_("Problem found"));
return false;
}
}
return true;
}
void FileDataArray::Clear()
{
fileList.Clear();
errorList.Clear();
fileCount = folderCount = 0;
fileSize = 0;
basePath = "";
}
bool FileDataArray::Search(String dir, String condFile, bool recurse, String text)
{
Clear();
basePath = dir;
Search_Each(dir, condFile, recurse, text);
return errorList.IsEmpty();
}
void FileDataArray::Search_Each(String dir, String condFile, bool recurse, String text)
{
FindFile ff;
if (ff.Search(AppendFileName(dir, condFile))) {
do {
if(ff.IsFile()) {
String p = AppendFileName(dir, ff.GetName());
if (text.IsEmpty()) {
uint64 len = ff.GetLength();
fileList.Add(FileData(false, ff.GetName(), GetRelativePath(dir), len, ff.GetLastWriteTime(),
(useId && ff.GetLength() > 0) ? GetFileId(p) : 0));
fileCount++;
fileSize += len;
} else {
FILE *fp = fopen(p, "r");
if (fp != NULL) {
int i = 0, c;
while ((c = fgetc(fp)) != EOF) {
if (c == text[i]) {
++i;
if (i == text.GetCount()) {
uint64 len = ff.GetLength();
fileList.Add(FileData(false, ff.GetName(), GetRelativePath(dir), len, ff.GetLastWriteTime(), useId ? GetFileId(p) : 0));
fileCount++;
fileSize += len;
break;
}
} else {
if (i != 0)
fseek(fp, -(i-1), SEEK_CUR);
i = 0;
}
}
fclose(fp);
} else
errorList.Add(AppendFileName(dir, ff.GetName()) + String(": ") + t_("Impossible to open file"));
}
}
} while (ff.Next());
}
ff.Search(AppendFileName(dir, "*"));
do {
String name = ff.GetName();
if(ff.IsDirectory() && name != "." && name != "..") {
String p = AppendFileName(dir, name);
fileList.Add(FileData(true, name, GetRelativePath(dir), 0, ff.GetLastWriteTime(), 0));
folderCount++;
if (recurse)
Search_Each(p, condFile, recurse, text);
}
} while (ff.Next());
}
int64 FileDataArray::GetFileId(String fileName)
{
int64 id = -1;
#ifdef PLATFORM_POSIX
FILE *fp = fopen(fileName, "rb");
#else
FILE *fp = _wfopen(fileName.ToWString(), L"rb");
#endif
if (fp != NULL) {
int c;
long i = 0;
while ((c = fgetc(fp)) != EOF) {
id += c*i;
i++;
}
fclose(fp);
}
return id;
}
void FileDataArray::SortByName(bool ascending)
{
fileDataSortBy = 'n';
fileDataSortAscending = ascending;
Sort(fileList);
}
void FileDataArray::SortByDate(bool ascending)
{
fileDataSortBy = 'd';
fileDataSortAscending = ascending;
Sort(fileList);
}
void FileDataArray::SortBySize(bool ascending)
{
fileDataSortBy = 's';
fileDataSortAscending = ascending;
Sort(fileList);
}
bool operator<(const FileData& a, const FileData& b)
{
if ((a.isFolder && b.isFolder) || (!a.isFolder && !b.isFolder)) {
switch (fileDataSortBy) {
case 'n': return (ToLower(a.fileName) < ToLower(b.fileName))&fileDataSortAscending;
case 'd': return (a.t < b.t)&fileDataSortAscending;
default: return (a.length < b.length)&fileDataSortAscending;
}
} else
return a.isFolder;
}
int FileDataArray::Find(String &relFileName, String &fileName, bool isFolder)
{
for (int i = 0; i < fileList.GetCount(); ++i) {
if ((ToLower(fileList[i].relFilename) == ToLower(relFileName)) && (ToLower(fileList[i].fileName) == ToLower(fileName)) && (fileList[i].isFolder == isFolder))
return i;
}
return -1;
}
bool FileDataArray::SaveFile(const char *fileName)
{
String ret;
for (int i = 0; i < fileList.GetCount(); ++i) {
ret << fileList[i].relFilename << "; ";
ret << fileList[i].fileName << "; ";
ret << fileList[i].isFolder << "; ";
ret << fileList[i].length << "; ";
ret << fileList[i].t << "; ";
ret << fileList[i].id << "; ";
ret << "\n";
}
return ::SaveFile(fileName, ret);
}
bool FileDataArray::LoadFile(const char *fileName)
{
Clear();
StringParse in = ::LoadFile(fileName);
if (in == "")
return false;
int numData = in.Count("\n");
fileList.SetCount(numData);
for (int row = 0; row < numData; ++row) {
fileList[row].relFilename = in.GetText(";");
fileList[row].fileName = in.GetText(";");
fileList[row].isFolder = in.GetText(";") == "true" ? true : false;
if (fileList[row].isFolder)
folderCount++;
else
fileCount++;
fileList[row].length = in.GetUInt64(";");
struct Upp::Time t;
StrToTime(t, in.GetText(";"));
fileList[row].t = t;
fileList[row].id = in.GetUInt64(";");
}
return true;
}
String FileDataArray::GetRelativePath(String fullPath)
{
if (basePath != fullPath.Left(basePath.GetCount()))
return "";
return fullPath.Mid(basePath.GetCount());
}
int64 GetDirectoryLength(String directoryName)
{
FileDataArray files;
files.Search(directoryName, "*.*", true);
return files.GetSize();
}
int64 GetLength(String fileName)
{
if (FileExists(fileName))
return GetFileLength(fileName);
else
return GetDirectoryLength(fileName);
}
FileDiffArray::FileDiffArray()
{
Clear();
}
void FileDiffArray::Clear()
{
diffList.Clear();
}
// True if equal
bool FileDiffArray::Compare(FileDataArray &master, FileDataArray &secondary)
{
if (master.GetCount() == 0) {
if (secondary.GetCount() == 0)
return true;
else
return false;
} else if (secondary.GetCount() == 0)
return false;
bool equal = true;
diffList.Clear();
Array<bool> secReviewed;
secReviewed.SetCount(secondary.GetCount(), false);
for (int i = 0; i < master.GetCount(); ++i) {
int idSec = secondary.Find(master[i].relFilename, master[i].fileName, master[i].isFolder);
if (idSec >= 0) {
bool useId = master.UseId() && secondary.UseId();
secReviewed[idSec] = true;
if (master[i].isFolder)
;
else if ((useId && (master[i].id == secondary[idSec].id)) ||
(!useId && (master[i].length == secondary[idSec].length) && (master[i].t == secondary[idSec].t)))
;
else {
equal = false;
FileDiff &f = diffList.Add();
bool isf = f.isFolder = master[i].isFolder;
f.relPath = master[i].relFilename;
String name = f.fileName = master[i].fileName;
f.idMaster = master[i].id;
f.idSecondary = secondary[idSec].id;
f.tMaster = master[i].t;
f.tSecondary = secondary[idSec].t;
f.lengthMaster = master[i].length;
f.lengthSecondary = secondary[idSec].length;
if (master[i].t >= secondary[idSec].t)
f.action = 'u';
else
f.action = 'p';
}
} else {
equal = false;
FileDiff &f = diffList.Add();
f.isFolder = master[i].isFolder;
f.relPath = master[i].relFilename;
f.fileName = master[i].fileName;
f.idMaster = master[i].id;
f.idSecondary = 0;
f.tMaster = master[i].t;
f.tSecondary = Null;
f.lengthMaster = master[i].length;
f.lengthSecondary = 0;
f.action = 'n';
}
}
for (int i = 0; i < secReviewed.GetCount(); ++i) {
if (!secReviewed[i]) {
equal = false;
FileDiff &f = diffList.Add();
f.isFolder = secondary[i].isFolder;
f.relPath = secondary[i].relFilename;
f.fileName = secondary[i].fileName;
f.idMaster = 0;
f.idSecondary = secondary[i].id;
f.tMaster = Null;
f.tSecondary = secondary[i].t;
f.lengthMaster = 0;
f.lengthSecondary = secondary[i].length;
f.action = 'd';
}
}
return equal;
}
bool FileDiffArray::Apply(String toFolder, String fromFolder)
{
for (int i = 0; i < diffList.GetCount(); ++i) {
bool ok = true;
String dest = AppendFileName(toFolder,
AppendFileName(diffList[i].relPath, diffList[i].fileName));
switch (diffList[i].action) {
case 'n': case 'u':
if (diffList[i].isFolder) {
if (!DirectoryExists(dest))
ok = DirectoryCreate(dest);
} else
ok = FileCopy(AppendFileName(fromFolder, FormatInt(i)), dest);
if (!ok) {
SetLastError(t_("Not possible to create") + String(" ") + dest);
return false;
}
break;
case 'd':
if (diffList[i].isFolder) {
if (DirectoryExists(dest))
ok = DeleteFolderDeep(dest);
} else {
if (FileExists(dest))
ok = FileDelete(dest);
}
if (!ok) {
SetLastError(t_("Not possible to delete") + String(" ") + dest);
return false;
}
break;
case 'p':
SetLastError(t_("There was a problem in the copy"));
return false;
}
}
return true;
}
bool FileDiffArray::SaveFile(const char *fileName)
{
return ::SaveFile(fileName, ToString());
}
String FileDiffArray::ToString()
{
String ret;
for (int i = 0; i < diffList.GetCount(); ++i) {
ret << diffList[i].action << "; ";
ret << diffList[i].isFolder << "; ";
ret << diffList[i].relPath << "; ";
ret << diffList[i].fileName << "; ";
ret << diffList[i].idMaster << "; ";
ret << diffList[i].idSecondary << "; ";
ret << diffList[i].tMaster << "; ";
ret << diffList[i].tSecondary << "; ";
ret << diffList[i].lengthMaster << "; ";
ret << diffList[i].lengthSecondary << "; ";
ret << "\n";
}
return ret;
}
bool FileDiffArray::LoadFile(const char *fileName)
{
Clear();
StringParse in = ::LoadFile(fileName);
if (in == "")
return false;
int numData = in.Count("\n");
diffList.SetCount(numData);
for (int row = 0; row < numData; ++row) {
diffList[row].action = TrimLeft(in.GetText(";"))[0];
diffList[row].isFolder = in.GetText(";") == "true" ? true : false;
diffList[row].relPath = in.GetText(";");
diffList[row].fileName = in.GetText(";");
diffList[row].idMaster = in.GetUInt64(";");
diffList[row].idSecondary = in.GetUInt64(";");
struct Upp::Time t;
StrToTime(t, in.GetText(";"));
diffList[row].tMaster = t;
StrToTime(t, in.GetText(";"));
diffList[row].tSecondary = t;
diffList[row].lengthMaster = in.GetUInt64(";");
diffList[row].lengthSecondary = in.GetUInt64(";");
}
return true;
}
#if defined(PLATFORM_WIN32)
Value GetVARIANT(VARIANT &result)
{
Value ret;
switch(result.vt) {
case VT_EMPTY:
case VT_NULL:
case VT_BLOB:
break;
case VT_BOOL:
ret = result.boolVal;// ? "true" : "false";
break;
case VT_I2:
ret = result.iVal;
break;
case VT_I4:
ret = (int64)result.lVal;
break;
case VT_R4:
ret = AsString(result.fltVal);
break;
case VT_R8:
ret = AsString(result.dblVal);
break;
case VT_BSTR:
{
char dbcs[1024];
char *pbstr = (char *)result.bstrVal;
int i = wcstombs(dbcs, result.bstrVal, *((DWORD *)(pbstr-4)));
dbcs[i] = 0;
ret = dbcs;
}
break;
case VT_LPSTR:
//ret = result.pszVal;
ret = "Unknown VT_LPSTR";
case VT_DATE:
SYSTEMTIME stime;
VariantTimeToSystemTime(result.date, &stime);
{
Time t;
t.day = (Upp::byte)stime.wDay;
t.month = (Upp::byte)stime.wMonth;
t.year = stime.wYear;
t.hour = (Upp::byte)stime.wHour;
t.minute = (Upp::byte)stime.wMinute;
t.second = (Upp::byte)stime.wSecond;
ret = t;
}
break;
case VT_CF:
ret = "(Clipboard format)";
break;
}
return ret;
}
#endif