2 // This file is part of the aMule Project.
4 // Copyright (c) 2004-2008 Angel Vidal ( kry@amule.org )
5 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
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
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.
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"
33 #include <wx/filename.h> // Needed for wxFileName
34 #include <wx/uri.h> // Needed for wxURI
36 // Implementation of the non-inlines
37 static byte base16Chars
[17] = "0123456789ABCDEF";
39 wxString
URLEncode(const wxString
& sIn
)
42 unsigned char curChar
;
44 for ( unsigned int i
= 0; i
< sIn
.Length(); ++i
) {
45 curChar
= sIn
.GetChar( i
);
47 if ( isalnum( curChar
) ) {
49 } else if( isspace ( curChar
) ) {
53 sOut
+= base16Chars
[ curChar
>> 4];
54 sOut
+= base16Chars
[ curChar
& 0xf];
62 wxString
TruncateFilename(const CPath
& filename
, size_t length
, bool isFilePath
)
64 wxString file
= filename
.GetPrintable();
66 // Check if there's anything to do
67 if (file
.Length() <= length
)
70 // If the filename is a path, then prefer to remove from the path, rather than the filename
72 wxString path
= wxFileName(file
).GetPath();
73 file
= wxFileName(file
).GetFullName();
75 if ( path
.Length() >= length
) {
77 } else if ( file
.Length() >= length
) {
80 // Minus 6 for "[...]" + separator
81 int pathlen
= (int)(length
- file
.Length() - 6);
84 path
= wxT("[...]") + path
.Right( pathlen
);
90 file
= JoinPaths(path
, file
);
93 if ( file
.Length() > length
) {
95 file
= file
.Left( length
- 5 ) + wxT("[...]");
107 wxString
StripSeparators(wxString path
, wxString::stripType type
)
109 wxASSERT((type
== wxString::leading
) || (type
== wxString::trailing
));
110 const wxString seps
= wxFileName::GetPathSeparators();
112 while (!path
.IsEmpty()) {
113 size_t pos
= ((type
== wxString::leading
) ? 0 : path
.Length() - 1);
115 if (seps
.Contains(path
.GetChar(pos
))) {
126 wxString
JoinPaths(const wxString
& path
, const wxString
& file
)
128 if (path
.IsEmpty()) {
130 } else if (file
.IsEmpty()) {
134 return StripSeparators(path
, wxString::trailing
)
135 + wxFileName::GetPathSeparator()
136 + StripSeparators(file
, wxString::leading
);
140 wxChar
HexToDec( const wxString
& hex
)
143 wxString str
= hex
.Upper();
145 for ( size_t i
= 0; i
< str
.Len(); ++i
) {
147 wxChar cur
= str
.GetChar(i
);
149 if ( isdigit( cur
) ) {
150 result
+= cur
- wxT('0');
151 } else if ( cur
>= wxT('A') && cur
<= wxT('F') ) {
152 result
+= cur
- wxT('A') + 10;
162 wxString
UnescapeHTML( const wxString
& str
)
165 result
.Alloc( str
.Len() );
167 for ( size_t i
= 0; i
< str
.Len(); ++i
) {
168 if ( str
.GetChar(i
) == wxT('%') && ( i
+ 2 < str
.Len() ) ) {
169 wxChar unesc
= HexToDec( str
.Mid( i
+ 1, 2 ) );
176 // If conversion failed, then we just add the escape-code
177 // and continue past it like nothing happened.
189 wxString
validateURI(const wxString
& url
)
193 return uri
.BuildURI();
203 inline wxString
GetNextField(const wxString
& str
, size_t& cookie
)
205 // These are taken to seperate "fields"
206 static const wxChar
* s_delims
= wxT("\t\n\x0b\x0c\r !\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~");
209 ECharType curType
= ECTNone
;
210 for (; cookie
< str
.Length(); ++cookie
) {
211 wxChar c
= str
[cookie
];
213 if ((c
>= wxT('0')) && (c
<= wxT('9'))) {
214 if (curType
== ECTText
) {
218 curType
= ECTInteger
;
220 } else if (wxStrchr(s_delims
, c
)) {
221 if (curType
== ECTNone
) {
227 if (curType
== ECTInteger
) {
240 int FuzzyStrCmp(const wxString
& a
, const wxString
& b
)
242 size_t aCookie
= 0, bCookie
= 0;
243 wxString aField
, bField
;
246 aField
= GetNextField(a
, aCookie
);
247 bField
= GetNextField(b
, bCookie
);
249 if (aField
.IsNumber() && bField
.IsNumber()) {
250 unsigned long aInteger
= StrToULong(aField
);
251 unsigned long bInteger
= StrToULong(bField
);
253 if (aInteger
< bInteger
) {
255 } else if (aInteger
> bInteger
) {
258 } else if (aField
< bField
) {
260 } else if (aField
> bField
) {
263 } while (!aField
.IsEmpty() && !bField
.IsEmpty());
269 int FuzzyStrCaseCmp(const wxString
& a
, const wxString
& b
)
271 return FuzzyStrCmp(a
.Lower(), b
.Lower());
276 CSimpleTokenizer::CSimpleTokenizer(const wxString
& str
, wxChar token
)
279 m_ptr(m_string
.c_str()),
285 wxString
CSimpleTokenizer::next()
287 const wxChar
* start
= m_ptr
;
288 const wxChar
* end
= m_string
.c_str() + m_string
.Len() + 1;
290 for (; m_ptr
< end
; ++m_ptr
) {
291 if (*m_ptr
== m_delim
) {
298 return m_string
.Mid(start
- m_string
.c_str(), m_ptr
++ - start
);
302 wxString
CSimpleTokenizer::remaining() const
304 return m_string
.Mid(m_ptr
- m_string
.c_str());
308 size_t CSimpleTokenizer::tokenCount() const
314 // File_checked_for_headers