1 | /*************************************************************************** |
2 | * Copyright (C) 2005-2014 by the Quassel Project * |
3 | * devel@quassel-irc.org * |
4 | * * |
5 | * This program is free software; you can redistribute it and/or modify * |
6 | * it under the terms of the GNU General Public License as published by * |
7 | * the Free Software Foundation; either version 2 of the License, or * |
8 | * (at your option) version 3. * |
9 | * * |
10 | * This program is distributed in the hope that it will be useful, * |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
13 | * GNU General Public License for more details. * |
14 | * * |
15 | * You should have received a copy of the GNU General Public License * |
16 | * along with this program; if not, write to the * |
17 | * Free Software Foundation, Inc., * |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
19 | ***************************************************************************/ |
20 | |
21 | #include "util.h" |
22 | |
23 | #include <QCoreApplication> |
24 | #include <QDebug> |
25 | #include <QFile> |
26 | #include <QTextCodec> |
27 | |
28 | #include "quassel.h" |
29 | |
30 | class QMetaMethod; |
31 | |
32 | // MIBenum values from http://www.iana.org/assignments/character-sets/character-sets.xml#table-character-sets-1 |
33 | static QList<int> utf8DetectionBlacklist = QList<int>() |
34 | << 39 /* ISO-2022-JP */; |
35 | |
36 | QString nickFromMask(QString mask) |
37 | { |
38 | return mask.section('!', 0, 0); |
39 | } |
40 | |
41 | |
42 | QString userFromMask(QString mask) |
43 | { |
44 | QString userhost = mask.section('!', 1); |
45 | if (userhost.isEmpty()) return QString(); |
46 | return userhost.section('@', 0, 0); |
47 | } |
48 | |
49 | |
50 | QString hostFromMask(QString mask) |
51 | { |
52 | QString userhost = mask.section('!', 1); |
53 | if (userhost.isEmpty()) return QString(); |
54 | return userhost.section('@', 1); |
55 | } |
56 | |
57 | |
58 | bool isChannelName(QString str) |
59 | { |
60 | return QString("#&!+" ).contains(str[0]); |
61 | } |
62 | |
63 | |
64 | QString stripFormatCodes(QString str) |
65 | { |
66 | str.remove(QRegExp("\x03(\\d\\d?(,\\d\\d?)?)?" )); |
67 | str.remove('\x02'); |
68 | str.remove('\x0f'); |
69 | str.remove('\x12'); |
70 | str.remove('\x16'); |
71 | str.remove('\x1d'); |
72 | str.remove('\x1f'); |
73 | return str; |
74 | } |
75 | |
76 | |
77 | QString stripAcceleratorMarkers(const QString &label_) |
78 | { |
79 | QString label = label_; |
80 | int p = 0; |
81 | forever { |
82 | p = label.indexOf('&', p); |
83 | if (p < 0 || p + 1 >= label.length()) |
84 | break; |
85 | |
86 | if (label.at(p + 1).isLetterOrNumber() || label.at(p + 1) == '&') |
87 | label.remove(p, 1); |
88 | |
89 | ++p; |
90 | } |
91 | return label; |
92 | } |
93 | |
94 | |
95 | QString decodeString(const QByteArray &input, QTextCodec *codec) |
96 | { |
97 | if (codec && utf8DetectionBlacklist.contains(codec->mibEnum())) |
98 | return codec->toUnicode(input); |
99 | |
100 | // First, we check if it's utf8. It is very improbable to encounter a string that looks like |
101 | // valid utf8, but in fact is not. This means that if the input string passes as valid utf8, it |
102 | // is safe to assume that it is. |
103 | // Q_ASSERT(sizeof(const char) == sizeof(quint8)); // In God we trust... |
104 | bool isUtf8 = true; |
105 | int cnt = 0; |
106 | for (int i = 0; i < input.size(); i++) { |
107 | if (cnt) { |
108 | // We check a part of a multibyte char. These need to be of the form 10yyyyyy. |
109 | if ((input[i] & 0xc0) != 0x80) { isUtf8 = false; break; } |
110 | cnt--; |
111 | continue; |
112 | } |
113 | if ((input[i] & 0x80) == 0x00) continue; // 7 bit is always ok |
114 | if ((input[i] & 0xf8) == 0xf0) { cnt = 3; continue; } // 4-byte char 11110xxx 10yyyyyy 10zzzzzz 10vvvvvv |
115 | if ((input[i] & 0xf0) == 0xe0) { cnt = 2; continue; } // 3-byte char 1110xxxx 10yyyyyy 10zzzzzz |
116 | if ((input[i] & 0xe0) == 0xc0) { cnt = 1; continue; } // 2-byte char 110xxxxx 10yyyyyy |
117 | isUtf8 = false; break; // 8 bit char, but not utf8! |
118 | } |
119 | if (isUtf8 && cnt == 0) { |
120 | QString s = QString::fromUtf8(input); |
121 | //qDebug() << "Detected utf8:" << s; |
122 | return s; |
123 | } |
124 | //QTextCodec *codec = QTextCodec::codecForName(encoding.toLatin1()); |
125 | if (!codec) return QString::fromLatin1(input); |
126 | return codec->toUnicode(input); |
127 | } |
128 | |
129 | |
130 | uint editingDistance(const QString &s1, const QString &s2) |
131 | { |
132 | uint n = s1.size()+1; |
133 | uint m = s2.size()+1; |
134 | QVector<QVector<uint> > matrix(n, QVector<uint>(m, 0)); |
135 | |
136 | for (uint i = 0; i < n; i++) |
137 | matrix[i][0] = i; |
138 | |
139 | for (uint i = 0; i < m; i++) |
140 | matrix[0][i] = i; |
141 | |
142 | uint min; |
143 | for (uint i = 1; i < n; i++) { |
144 | for (uint j = 1; j < m; j++) { |
145 | uint deleteChar = matrix[i-1][j] + 1; |
146 | uint insertChar = matrix[i][j-1] + 1; |
147 | |
148 | if (deleteChar < insertChar) |
149 | min = deleteChar; |
150 | else |
151 | min = insertChar; |
152 | |
153 | if (s1[i-1] == s2[j-1]) { |
154 | uint inheritChar = matrix[i-1][j-1]; |
155 | if (inheritChar < min) |
156 | min = inheritChar; |
157 | } |
158 | |
159 | matrix[i][j] = min; |
160 | } |
161 | } |
162 | return matrix[n-1][m-1]; |
163 | } |
164 | |
165 | |
166 | QString secondsToString(int timeInSeconds) |
167 | { |
168 | QList<QPair<int, QString> > timeUnit; |
169 | timeUnit.append(qMakePair(365*24*60*60, QCoreApplication::translate("Quassel::secondsToString()" , "year" ))); |
170 | timeUnit.append(qMakePair(24*60*60, QCoreApplication::translate("Quassel::secondsToString()" , "day" ))); |
171 | timeUnit.append(qMakePair(60*60, QCoreApplication::translate("Quassel::secondsToString()" , "h" ))); |
172 | timeUnit.append(qMakePair(60, QCoreApplication::translate("Quassel::secondsToString()" , "min" ))); |
173 | timeUnit.append(qMakePair(1, QCoreApplication::translate("Quassel::secondsToString()" , "sec" ))); |
174 | |
175 | QStringList returnString; |
176 | for (int i = 0; i < timeUnit.size(); i++) { |
177 | int n = timeInSeconds / timeUnit[i].first; |
178 | if (n > 0) { |
179 | returnString += QString("%1 %2" ).arg(QString::number(n), timeUnit[i].second); |
180 | } |
181 | timeInSeconds = timeInSeconds % timeUnit[i].first; |
182 | } |
183 | return returnString.join(", " ); |
184 | } |
185 | |
186 | |
187 | QByteArray prettyDigest(const QByteArray &digest) |
188 | { |
189 | QByteArray hexDigest = digest.toHex().toUpper(); |
190 | QByteArray prettyDigest; |
191 | prettyDigest.fill(':', hexDigest.count() + (hexDigest.count() / 2) - 1); |
192 | |
193 | for (int i = 0; i * 2 < hexDigest.count(); i++) { |
194 | prettyDigest.replace(i * 3, 2, hexDigest.mid(i * 2, 2)); |
195 | } |
196 | return prettyDigest; |
197 | } |
198 | |