Upstream tarball 10013
[amule.git] / src / libs / common / StringFunctions.cpp
blobe51c5ee30159a7676107a6559a7b42a68fda11f1
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2004-2008 Angel Vidal ( kry@amule.org )
5 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #define STRINGFUNCTIONS_CPP
30 #include "StringFunctions.h"
31 #include "Path.h"
33 #include <wx/filename.h> // Needed for wxFileName
34 #include <wx/uri.h> // Needed for wxURI
36 // Implementation of the non-inlines
39 // Conversion of wxString so it can be used by printf() in a console
40 // On some platforms (Windows) the console allows only "plain" characters,
41 // so try to convert as much as possible and replace the others with '?'.
42 // On other platforms (some Linux) wxConvLocal silently converts to UTF8
43 // so the console can show even Chinese chars.
45 Unicode2CharBuf unicode2char(const wxChar* s)
47 // First try the straight way.
48 Unicode2CharBuf buf1(wxConvLocal.cWX2MB(s));
49 if ((const char *) buf1) {
50 return buf1;
52 // Failed. Try to convert as much as possible.
53 size_t len = wxStrlen(s);
54 size_t maxlen = len * 4; // Allow for an encoding of up to 4 byte per char.
55 wxCharBuffer buf(maxlen + 1); // This is wasteful, but the string is used temporary anyway.
56 char * data = buf.data();
57 for (size_t i = 0, pos = 0; i < len; i++) {
58 size_t len_char = wxConvLocal.FromWChar(data + pos, maxlen - pos, s + i, 1);
59 if (len_char != wxCONV_FAILED) {
60 pos += len_char - 1;
61 } else if (pos < maxlen) {
62 data[pos++] = '?';
63 data[pos] = 0;
66 return buf;
69 static byte base16Chars[17] = "0123456789ABCDEF";
71 wxString URLEncode(const wxString& sIn)
73 wxString sOut;
74 unsigned char curChar;
76 for ( unsigned int i = 0; i < sIn.Length(); ++i ) {
77 curChar = sIn.GetChar( i );
79 if ( isalnum( curChar ) ) {
80 sOut += curChar;
81 } else if( isspace ( curChar ) ) {
82 sOut += wxT("+");
83 } else {
84 sOut += wxT("%");
85 sOut += base16Chars[ curChar >> 4];
86 sOut += base16Chars[ curChar & 0xf];
91 return sOut;
94 wxString TruncateFilename(const CPath& filename, size_t length, bool isFilePath)
96 wxString file = filename.GetPrintable();
98 // Check if there's anything to do
99 if (file.Length() <= length)
100 return file;
102 // If the filename is a path, then prefer to remove from the path, rather than the filename
103 if ( isFilePath ) {
104 wxString path = wxFileName(file).GetPath();
105 file = wxFileName(file).GetFullName();
107 if ( path.Length() >= length ) {
108 path.Clear();
109 } else if ( file.Length() >= length ) {
110 path.Clear();
111 } else {
112 // Minus 6 for "[...]" + separator
113 int pathlen = (int)(length - file.Length() - 6);
115 if ( pathlen > 0 ) {
116 path = wxT("[...]") + path.Right( pathlen );
117 } else {
118 path.Clear();
122 file = JoinPaths(path, file);
125 if ( file.Length() > length ) {
126 if ( length > 5 ) {
127 file = file.Left( length - 5 ) + wxT("[...]");
128 } else {
129 file.Clear();
134 return file;
139 wxString StripSeparators(wxString path, wxString::stripType type)
141 wxASSERT((type == wxString::leading) || (type == wxString::trailing));
142 const wxString seps = wxFileName::GetPathSeparators();
144 while (!path.IsEmpty()) {
145 size_t pos = ((type == wxString::leading) ? 0 : path.Length() - 1);
147 if (seps.Contains(path.GetChar(pos))) {
148 path.Remove(pos, 1);
149 } else {
150 break;
154 return path;
158 wxString JoinPaths(const wxString& path, const wxString& file)
160 if (path.IsEmpty()) {
161 return file;
162 } else if (file.IsEmpty()) {
163 return path;
166 return StripSeparators(path, wxString::trailing)
167 + wxFileName::GetPathSeparator()
168 + StripSeparators(file, wxString::leading);
172 wxChar HexToDec( const wxString& hex )
174 wxChar result = 0;
175 wxString str = hex.Upper();
177 for ( size_t i = 0; i < str.Len(); ++i ) {
178 result *= 16;
179 wxChar cur = str.GetChar(i);
181 if ( isdigit( cur ) ) {
182 result += cur - wxT('0');
183 } else if ( cur >= wxT('A') && cur <= wxT('F') ) {
184 result += cur - wxT('A') + 10;
185 } else {
186 return wxT('\0');
190 return result;
194 wxString UnescapeHTML( const wxString& str )
196 wxString result;
197 result.Alloc( str.Len() );
199 for ( size_t i = 0; i < str.Len(); ++i ) {
200 if ( str.GetChar(i) == wxT('%') && ( i + 2 < str.Len() ) ) {
201 wxChar unesc = HexToDec( str.Mid( i + 1, 2 ) );
203 if ( unesc ) {
204 i += 2;
206 result += unesc;
207 } else {
208 // If conversion failed, then we just add the escape-code
209 // and continue past it like nothing happened.
210 result += str.at(i);
212 } else {
213 result += str.at(i);
217 return result;
221 wxString validateURI(const wxString& url)
223 wxURI uri(url);
225 return uri.BuildURI();
229 enum ECharType {
230 ECTInteger,
231 ECTText,
232 ECTNone
235 inline wxString GetNextField(const wxString& str, size_t& cookie)
237 // These are taken to seperate "fields"
238 static const wxChar* s_delims = wxT("\t\n\x0b\x0c\r !\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~");
240 wxString field;
241 ECharType curType = ECTNone;
242 for (; cookie < str.Length(); ++cookie) {
243 wxChar c = str[cookie];
245 if ((c >= wxT('0')) && (c <= wxT('9'))) {
246 if (curType == ECTText) {
247 break;
250 curType = ECTInteger;
251 field += c;
252 } else if (wxStrchr(s_delims, c)) {
253 if (curType == ECTNone) {
254 continue;
255 } else {
256 break;
258 } else {
259 if (curType == ECTInteger) {
260 break;
263 curType = ECTText;
264 field += c;
268 return field;
272 int FuzzyStrCmp(const wxString& a, const wxString& b)
274 size_t aCookie = 0, bCookie = 0;
275 wxString aField, bField;
277 do {
278 aField = GetNextField(a, aCookie);
279 bField = GetNextField(b, bCookie);
281 if (aField.IsNumber() && bField.IsNumber()) {
282 unsigned long aInteger = StrToULong(aField);
283 unsigned long bInteger = StrToULong(bField);
285 if (aInteger < bInteger) {
286 return -1;
287 } else if (aInteger > bInteger) {
288 return 1;
290 } else if (aField < bField) {
291 return -1;
292 } else if (aField > bField) {
293 return 1;
295 } while (!aField.IsEmpty() && !bField.IsEmpty());
297 return 0;
301 int FuzzyStrCaseCmp(const wxString& a, const wxString& b)
303 return FuzzyStrCmp(a.Lower(), b.Lower());
308 CSimpleTokenizer::CSimpleTokenizer(const wxString& str, wxChar token)
309 : m_string(str),
310 m_delim(token),
311 m_ptr(m_string.c_str()),
312 m_count(0)
317 wxString CSimpleTokenizer::next()
319 const wxChar* start = m_ptr;
320 const wxChar* end = m_string.c_str() + m_string.Len() + 1;
322 for (; m_ptr < end; ++m_ptr) {
323 if (*m_ptr == m_delim) {
324 m_count++;
325 break;
329 // Return the token
330 return m_string.Mid(start - m_string.c_str(), m_ptr++ - start);
334 wxString CSimpleTokenizer::remaining() const
336 return m_string.Mid(m_ptr - m_string.c_str());
340 size_t CSimpleTokenizer::tokenCount() const
342 return m_count;
346 // File_checked_for_headers