MPEGPlayer: Skip to next file when there is a problem with a video file in all-play...
[kugel-rb.git] / rbutil / rbutilqt / base / utils.cpp
blobbd2bce060939be76660fc789bcbd02ba52c129d4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
9 * Copyright (C) 2007 by Dominik Wenger
10 * $Id$
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "utils.h"
21 #include "rockboxinfo.h"
22 #include "system.h"
23 #include "rbsettings.h"
24 #include "systeminfo.h"
26 #ifdef UNICODE
27 #define _UNICODE
28 #endif
30 #include <QtCore>
31 #include <QDebug>
32 #include <cstdlib>
33 #include <stdio.h>
35 #if defined(Q_OS_WIN32)
36 #include <windows.h>
37 #include <tchar.h>
38 #include <winioctl.h>
39 #endif
40 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
41 #include <sys/statvfs.h>
42 #endif
44 // recursive function to delete a dir with files
45 bool Utils::recursiveRmdir( const QString &dirName )
47 QString dirN = dirName;
48 QDir dir(dirN);
49 // make list of entries in directory
50 QStringList list = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
51 QFileInfo fileInfo;
52 QString curItem, lstAt;
53 for(int i = 0; i < list.size(); i++){ // loop through all items of list
54 QString name = list.at(i);
55 curItem = dirN + "/" + name;
56 fileInfo.setFile(curItem);
57 if(fileInfo.isDir()) // is directory
58 recursiveRmdir(curItem); // call recRmdir() recursively for
59 // deleting subdirectory
60 else // is file
61 QFile::remove(curItem); // ok, delete file
63 dir.cdUp();
64 return dir.rmdir(dirN); // delete empty dir and return if (now empty)
65 // dir-removing was successfull
69 //! @brief resolves the given path, ignoring case.
70 //! @param path absolute path to resolve.
71 //! @return returns exact casing of path, empty string if path not found.
72 QString Utils::resolvePathCase(QString path)
74 QStringList elems;
75 QString realpath;
77 elems = path.split("/", QString::SkipEmptyParts);
78 int start;
79 #if defined(Q_OS_WIN32)
80 // on windows we must make sure to start with the first entry (i.e. the
81 // drive letter) instead of a single / to make resolving work.
82 start = 1;
83 realpath = elems.at(0) + "/";
84 #else
85 start = 0;
86 realpath = "/";
87 #endif
89 for(int i = start; i < elems.size(); i++) {
90 QStringList direlems
91 = QDir(realpath).entryList(QDir::AllEntries|QDir::Hidden|QDir::System);
92 if(direlems.contains(elems.at(i), Qt::CaseInsensitive)) {
93 // need to filter using QRegExp as QStringList::filter(QString)
94 // matches any substring
95 QString expr = QString("^" + elems.at(i) + "$");
96 QRegExp rx = QRegExp(expr, Qt::CaseInsensitive);
97 QStringList a = direlems.filter(rx);
99 if(a.size() != 1)
100 return QString("");
101 if(!realpath.endsWith("/"))
102 realpath += "/";
103 realpath += a.at(0);
105 else
106 return QString("");
108 qDebug() << "[Utils] resolving path" << path << "->" << realpath;
109 return realpath;
113 //! @brief figure the free disk space on a filesystem
114 //! @param path path on the filesystem to check
115 //! @return size in bytes
116 qulonglong Utils::filesystemFree(QString path)
118 qlonglong size = 0;
119 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
120 // the usage of statfs() is deprecated by the LSB so use statvfs().
121 struct statvfs fs;
122 int ret;
124 ret = statvfs(qPrintable(path), &fs);
126 if(ret == 0)
127 size = (qulonglong)fs.f_frsize * (qulonglong)fs.f_bavail;
128 #endif
129 #if defined(Q_OS_WIN32)
130 BOOL ret;
131 ULARGE_INTEGER freeAvailBytes;
133 ret = GetDiskFreeSpaceExW((LPCTSTR)path.utf16(), &freeAvailBytes, NULL, NULL);
134 if(ret)
135 size = freeAvailBytes.QuadPart;
136 #endif
137 qDebug() << "[Utils] Filesystem free:" << path << size;
138 return size;
141 //! \brief searches for a Executable in the Environement Path
142 QString Utils::findExecutable(QString name)
144 QString exepath;
145 //try autodetect tts
146 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX) || defined(Q_OS_OPENBSD)
147 QStringList path = QString(getenv("PATH")).split(":", QString::SkipEmptyParts);
148 #elif defined(Q_OS_WIN)
149 QStringList path = QString(getenv("PATH")).split(";", QString::SkipEmptyParts);
150 #endif
151 qDebug() << "[Utils] system path:" << path;
152 for(int i = 0; i < path.size(); i++)
154 QString executable = QDir::fromNativeSeparators(path.at(i)) + "/" + name;
155 #if defined(Q_OS_WIN)
156 executable += ".exe";
157 QStringList ex = executable.split("\"", QString::SkipEmptyParts);
158 executable = ex.join("");
159 #endif
160 qDebug() << "[Utils] executable:" << executable;
161 if(QFileInfo(executable).isExecutable())
163 return QDir::toNativeSeparators(executable);
166 return "";
170 /** @brief checks different Enviroment things. Ask if user wants to continue.
171 * @param permission if it should check for permission
172 * @return string with error messages if problems occurred, empty strings if none.
174 QString Utils::checkEnvironment(bool permission)
176 QString text = "";
178 // check permission
179 if(permission)
181 #if defined(Q_OS_WIN32)
182 if(System::userPermissions() != System::ADMIN)
184 text += tr("<li>Permissions insufficient for bootloader "
185 "installation.\nAdministrator priviledges are necessary.</li>");
187 #endif
190 // Check TargetId
191 RockboxInfo rbinfo(RbSettings::value(RbSettings::Mountpoint).toString());
192 QString installed = rbinfo.target();
193 if(!installed.isEmpty() && installed !=
194 SystemInfo::value(SystemInfo::CurConfigureModel).toString())
196 text += tr("<li>Target mismatch detected.\n"
197 "Installed target: %1, selected target: %2.</li>")
198 .arg(installed, SystemInfo::value(SystemInfo::CurPlatformName).toString());
199 // FIXME: replace installed by human-friendly name
202 if(!text.isEmpty())
203 return tr("Problem detected:") + "<ul>" + text + "</ul>";
204 else
205 return text;
207 /** @brief Compare two version strings.
208 * @param s1 first version string
209 * @param s2 second version string
210 * @return 0 if strings identical, 1 if second is newer, -1 if first.
212 int Utils::compareVersionStrings(QString s1, QString s2)
214 qDebug() << "[Utils] comparing version strings" << s1 << "and" << s2;
215 QString a = s1.trimmed();
216 QString b = s2.trimmed();
217 // if strings are identical return 0.
218 if(a.isEmpty())
219 return 1;
220 if(b.isEmpty())
221 return -1;
223 while(!a.isEmpty() || !b.isEmpty()) {
224 // trim all leading non-digits and non-dots (dots are removed afterwards)
225 a.remove(QRegExp("^[^\\d\\.]*"));
226 b.remove(QRegExp("^[^\\d\\.]*"));
228 // trim all trailing non-digits for conversion (QString::toInt()
229 // requires this). Copy strings first as replace() changes the string.
230 QString numa = a;
231 QString numb = b;
232 numa.remove(QRegExp("\\D+.*$"));
233 numb.remove(QRegExp("\\D+.*$"));
235 // convert to number
236 bool ok1, ok2;
237 int vala = numa.toUInt(&ok1);
238 int valb = numb.toUInt(&ok2);
239 // if none of the numbers converted successfully we're at trailing garbage.
240 if(!ok1 && !ok2)
241 break;
242 if(!ok1)
243 return 1;
244 if(!ok2)
245 return -1;
247 // if numbers mismatch we have a decision.
248 if(vala != valb)
249 return (vala > valb) ? -1 : 1;
251 // trim leading digits.
252 a.remove(QRegExp("^\\d*"));
253 b.remove(QRegExp("^\\d*"));
255 // If only one of the following characters is a dot that one is
256 // "greater" then anything else. Make sure it's followed by a number,
257 // Otherwise it might be the end of the string or suffix. Do this
258 // before version addon characters check to avoid stopping too early.
259 bool adot = a.contains(QRegExp("^[a-zA-Z]*\\.[0-9]"));
260 bool bdot = b.contains(QRegExp("^[a-zA-Z]*\\.[0-9]"));
261 if(adot && !bdot)
262 return -1;
263 if(!adot && bdot)
264 return 1;
265 // if number is immediately followed by a character consider it as
266 // version addon (like 1.2.3b). In this case compare characters and end
267 // (version numbers like 1.2b.3 aren't handled).
268 QChar ltra;
269 QChar ltrb;
270 if(a.contains(QRegExp("^[a-zA-Z]")))
271 ltra = a.at(0);
272 if(b.contains(QRegExp("^[a-zA-Z]")))
273 ltrb = b.at(0);
274 if(ltra != ltrb)
275 return (ltra < ltrb) ? 1 : -1;
277 // both are identical or no addon characters, ignore.
278 // remove modifiers and following dot.
279 a.remove(QRegExp("^[a-zA-Z]*\\."));
280 b.remove(QRegExp("^[a-zA-Z]*\\."));
283 // no differences found.
284 return 0;