1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Implementation of a uri parser
7 // Copyright: (c) 2004 Ryan Norton
9 /////////////////////////////////////////////////////////////////////////////
12 //TODO: RN: I had some massive doxygen docs, I need to move these
13 //in a presentable form in these sources
16 // ===========================================================================
18 // ===========================================================================
20 // ---------------------------------------------------------------------------
22 // ---------------------------------------------------------------------------
24 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
25 #pragma implementation "uri.h"
28 // For compilers that support precompilation, includes "wx.h".
29 #include "wx/wxprec.h"
37 // ---------------------------------------------------------------------------
39 // ---------------------------------------------------------------------------
41 IMPLEMENT_CLASS(wxURI
, wxObject
);
43 // ===========================================================================
45 // ===========================================================================
47 // ---------------------------------------------------------------------------
49 // ---------------------------------------------------------------------------
51 // ---------------------------------------------------------------------------
55 // ---------------------------------------------------------------------------
57 // ---------------------------------------------------------------------------
59 // ---------------------------------------------------------------------------
61 wxURI
::wxURI() : m_hostType(wxURI_REGNAME
), m_fields(0)
65 wxURI
::wxURI(const wxString
& uri
) : m_hostType(wxURI_REGNAME
), m_fields(0)
70 wxURI
::wxURI(const wxURI
& uri
) : m_hostType(wxURI_REGNAME
), m_fields(0)
75 // ---------------------------------------------------------------------------
76 // Destructor and cleanup
77 // ---------------------------------------------------------------------------
86 m_scheme
= m_user
= m_server
= m_port
= m_path
=
87 m_query
= m_fragment
= wxT("");
89 m_hostType
= wxURI_REGNAME
;
94 // ---------------------------------------------------------------------------
97 // This creates the URI - all we do here is call the main parsing method
98 // ---------------------------------------------------------------------------
100 void wxURI
::Create(const wxString
& uri
)
108 // ---------------------------------------------------------------------------
109 // Escape/Unescape/IsEscape
111 // Unescape unencodes a 3 character URL escape sequence
112 // Escape encodes an invalid URI character into a 3 character sequence
113 // IsEscape determines if the input string contains an escape sequence,
114 // if it does, then it moves the input string past the escape sequence
115 // ---------------------------------------------------------------------------
117 wxChar wxURI
::Unescape(const wxChar
* s
)
119 wxASSERT_MSG(IsHex(*s
) && IsHex(*(s
+1)), wxT("Invalid escape!"));
121 return CharToHex(*s
) * 0x10 + CharToHex(*++s
);
124 void wxURI
::Escape(wxString
& s
, const wxChar
& c
)
126 const wxChar
* hdig
= wxT("0123456789abcdef");
128 s
+= hdig
[(c
>> 4) & 15];
132 bool wxURI
::IsEscape(const wxChar
*& uri
)
134 if(*uri
== '%' && IsHex(*(uri
+1)) && IsHex(*(uri
+2)))
143 // ---------------------------------------------------------------------------
146 // Get() actually builds the entire URI into a useable
147 // representation, including proper identification characters such as slashes
148 // ---------------------------------------------------------------------------
150 wxString wxURI
::Get() const
155 ret
= ret
+ m_scheme
+ wxT(":");
162 ret
= ret
+ m_user
+ wxT("@");
167 ret
= ret
+ wxT(":") + m_port
;
173 ret
= ret
+ wxT("?") + m_query
;
176 ret
= ret
+ wxT("#") + m_fragment
;
181 // ---------------------------------------------------------------------------
183 // ---------------------------------------------------------------------------
185 wxURI
& wxURI
::operator = (const wxURI
& uri
)
190 wxURI
& wxURI
::Assign(const wxURI
& uri
)
193 m_fields
= uri
.m_fields
;
195 //ref over components
196 m_scheme
= uri
.m_scheme
;
198 m_server
= uri
.m_server
;
199 m_hostType
= uri
.m_hostType
;
202 m_query
= uri
.m_query
;
203 m_fragment
= uri
.m_fragment
;
208 wxURI
& wxURI
::operator = (const wxString
& string
)
214 bool wxURI
::operator == (const wxURI
& uri
) const
218 if(m_scheme
!= uri
.m_scheme
)
221 else if (uri
.HasScheme())
229 if (m_user
!= uri
.m_user
)
232 else if (uri
.HasUser())
235 if (m_server
!= uri
.m_server
||
236 m_hostType
!= uri
.m_hostType
)
241 if(m_port
!= uri
.m_port
)
244 else if (uri
.HasPort())
247 else if (uri
.HasServer())
253 if(m_path
!= uri
.m_path
)
256 else if (uri
.HasPath())
261 if (m_query
!= uri
.m_query
)
264 else if (uri
.HasQuery())
269 if (m_fragment
!= uri
.m_fragment
)
272 else if (uri
.HasFragment())
278 // ---------------------------------------------------------------------------
281 // if there is no authority or scheme, it is a reference
282 // ---------------------------------------------------------------------------
284 bool wxURI
::IsReference() const
285 { return !HasScheme() || !HasServer(); }
287 // ---------------------------------------------------------------------------
290 // Master URI parsing method. Just calls the individual parsing methods
292 // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
293 // URI-reference = URI / relative-URITestCase
294 // ---------------------------------------------------------------------------
296 const wxChar
* wxURI
::Parse(const wxChar
* uri
)
298 uri
= ParseScheme(uri
);
299 uri
= ParseAuthority(uri
);
300 uri
= ParsePath(uri
);
301 uri
= ParseQuery(uri
);
302 return ParseFragment(uri
);
305 // ---------------------------------------------------------------------------
308 // Individual parsers for each URI component
309 // ---------------------------------------------------------------------------
311 const wxChar
* wxURI
::ParseScheme(const wxChar
* uri
)
313 wxASSERT(uri
!= NULL
);
315 //copy of the uri - used for figuring out
316 //length of each component
317 const wxChar
* uricopy
= uri
;
319 //Does the uri have a scheme (first character alpha)?
324 //scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
325 //RN: Scheme can not be escaped
326 while (IsAlpha(*uri
) || IsDigit(*uri
) ||
337 //mark the scheme as valid
338 m_fields
|= wxURI_SCHEME
;
340 //move reference point up to input buffer
344 //relative uri with relative path reference
348 //relative uri with _possible_ relative path reference
353 const wxChar
* wxURI
::ParseAuthority(const wxChar
* uri
)
355 // authority = [ userinfo "@" ] host [ ":" port ]
356 if (*uri
== '/' && *(uri
+1) == '/')
360 uri
= ParseUser(uri
);
361 uri
= ParseServer(uri
);
362 return ParsePort(uri
);
368 const wxChar
* wxURI
::ParseUser(const wxChar
* uri
)
370 wxASSERT(uri
!= NULL
);
372 //copy of the uri - used for figuring out
373 //length of each component
374 const wxChar
* uricopy
= uri
;
376 // userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
377 while(*uri
&& *uri
!= '@' && *uri
!= '/' && *uri
!= '#' && *uri
!= '?')
379 if(IsUnreserved(*uri
) || IsEscape(uri
) ||
380 IsSubDelim(*uri
) || *uri
== ':')
383 Escape(m_user
, *uri
++);
389 m_fields
|= wxURI_USER
;
399 const wxChar
* wxURI
::ParseServer(const wxChar
* uri
)
401 wxASSERT(uri
!= NULL
);
403 //copy of the uri - used for figuring out
404 //length of each component
405 const wxChar
* uricopy
= uri
;
407 // host = IP-literal / IPv4address / reg-name
408 // IP-literal = "[" ( IPv6address / IPvFuture ) "]"
411 if (ParseIPv6address(++uri
) && *uri
== ']')
414 m_hostType
= wxURI_IPV6ADDRESS
;
416 wxStringBufferLength
theBuffer(m_server
, uri
- uricopy
);
417 wxMemcpy(theBuffer
, uricopy
, uri
-uricopy
);
418 theBuffer
.SetLength(uri
-uricopy
);
424 if (ParseIPvFuture(++uri
) && *uri
== ']')
427 m_hostType
= wxURI_IPVFUTURE
;
429 wxStringBufferLength
theBuffer(m_server
, uri
- uricopy
);
430 wxMemcpy(theBuffer
, uricopy
, uri
-uricopy
);
431 theBuffer
.SetLength(uri
-uricopy
);
439 if (ParseIPv4address(uri
))
441 m_hostType
= wxURI_IPV4ADDRESS
;
443 wxStringBufferLength
theBuffer(m_server
, uri
- uricopy
);
444 wxMemcpy(theBuffer
, uricopy
, uri
-uricopy
);
445 theBuffer
.SetLength(uri
-uricopy
);
451 if(m_hostType
== wxURI_REGNAME
)
454 // reg-name = *( unreserved / pct-encoded / sub-delims )
455 while(*uri
&& *uri
!= '/' && *uri
!= ':' && *uri
!= '#' && *uri
!= '?')
457 if(IsUnreserved(*uri
) || IsEscape(uri
) || IsSubDelim(*uri
))
460 Escape(m_server
, *uri
++);
464 //mark the server as valid
465 m_fields
|= wxURI_SERVER
;
471 const wxChar
* wxURI
::ParsePort(const wxChar
* uri
)
473 wxASSERT(uri
!= NULL
);
484 //mark the port as valid
485 m_fields
|= wxURI_PORT
;
491 const wxChar
* wxURI
::ParsePath(const wxChar
* uri
, bool bReference
, bool bNormalize
)
493 wxASSERT(uri
!= NULL
);
495 //copy of the uri - used for figuring out
496 //length of each component
497 const wxChar
* uricopy
= uri
;
499 /// hier-part = "//" authority path-abempty
504 /// relative-part = "//" authority path-abempty
509 /// path-abempty = *( "/" segment )
510 /// path-absolute = "/" [ segment-nz *( "/" segment ) ]
511 /// path-noscheme = segment-nz-nc *( "/" segment )
512 /// path-rootless = segment-nz *( "/" segment )
513 /// path-empty = 0<pchar>
516 /// segment-nz = 1*pchar
517 /// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
518 /// ; non-zero-length segment without any colon ":"
520 /// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
525 while(*uri
&& *uri
!= '#' && *uri
!= '?')
527 if( IsUnreserved(*uri
) || IsSubDelim(*uri
) || IsEscape(uri
) ||
528 *uri
== ':' || *uri
== '@' || *uri
== '/')
531 Escape(m_path
, *uri
++);
536 wxStringBufferLength
theBuffer(m_path
, m_path
.length() + 1);
537 Normalize(theBuffer
, true);
538 theBuffer
.SetLength(wxStrlen(theBuffer
));
540 //mark the path as valid
541 m_fields
|= wxURI_PATH
;
543 else if(*uri
) //Relative path
548 while(*uri
&& *uri
!= '#' && *uri
!= '?')
550 if(IsUnreserved(*uri
) || IsSubDelim(*uri
) || IsEscape(uri
) ||
551 *uri
== '@' || *uri
== '/')
554 Escape(m_path
, *uri
++);
559 while(*uri
&& *uri
!= '#' && *uri
!= '?')
561 if(IsUnreserved(*uri
) || IsSubDelim(*uri
) || IsEscape(uri
) ||
562 *uri
== ':' || *uri
== '@' || *uri
== '/')
565 Escape(m_path
, *uri
++);
573 wxStringBufferLength
theBuffer(m_path
, m_path
.length() + 1);
574 Normalize(theBuffer
);
575 theBuffer
.SetLength(wxStrlen(theBuffer
));
578 //mark the path as valid
579 m_fields
|= wxURI_PATH
;
587 const wxChar
* wxURI
::ParseQuery(const wxChar
* uri
)
589 wxASSERT(uri
!= NULL
);
591 // query = *( pchar / "/" / "?" )
595 while(*uri
&& *uri
!= '#')
597 if (IsUnreserved(*uri
) || IsSubDelim(*uri
) || IsEscape(uri
) ||
598 *uri
== ':' || *uri
== '@' || *uri
== '/' || *uri
== '?')
601 Escape(m_query
, *uri
++);
604 //mark the server as valid
605 m_fields
|= wxURI_QUERY
;
612 const wxChar
* wxURI
::ParseFragment(const wxChar
* uri
)
614 wxASSERT(uri
!= NULL
);
616 // fragment = *( pchar / "/" / "?" )
622 if (IsUnreserved(*uri
) || IsSubDelim(*uri
) || IsEscape(uri
) ||
623 *uri
== ':' || *uri
== '@' || *uri
== '/' || *uri
== '?')
624 m_fragment
+= *uri
++;
626 Escape(m_fragment
, *uri
++);
629 //mark the server as valid
630 m_fields
|= wxURI_FRAGMENT
;
636 // ---------------------------------------------------------------------------
639 // Builds missing components of this uri from a base uri
641 // A version of the algorithm outlined in the RFC is used here
642 // (it is shown in comments)
643 // ---------------------------------------------------------------------------
645 void wxURI
::Resolve(const wxURI
& base
, int flags
)
647 wxASSERT_MSG(!base
.IsReference(),
648 wxT("wxURI to inherit from must not be a reference!"));
650 // If we arn't being strict, enable the older
651 // loophole that allows this uri to inherit other
652 // properties from the base uri - even if the scheme
654 if ( !(flags
& wxURI_STRICT
) &&
655 HasScheme() && base
.HasScheme() &&
656 m_scheme
== base
.m_scheme
)
658 m_fields
-= wxURI_SCHEME
;
662 // Do nothing if this is an absolute wxURI
663 // if defined(R.scheme) then
664 // T.scheme = R.scheme;
665 // T.authority = R.authority;
666 // T.path = remove_dot_segments(R.path);
667 // T.query = R.query;
674 m_scheme
= base
.m_scheme
;
675 m_fields
|= wxURI_SCHEME
;
677 // All we need to do for relative URIs with an
678 // authority component is just inherit the scheme
679 // if defined(R.authority) then
680 // T.authority = R.authority;
681 // T.path = remove_dot_segments(R.path);
682 // T.query = R.query;
688 //No authority - inherit
691 m_user
= base
.m_user
;
692 m_fields
|= wxURI_USER
;
695 m_server
= base
.m_server
;
696 m_hostType
= base
.m_hostType
;
697 m_fields
|= wxURI_SERVER
;
701 m_port
= base
.m_port
;
702 m_fields
|= wxURI_PORT
;
706 // Simple path inheritance from base
709 // T.path = Base.path;
710 m_path
= base
.m_path
;
711 m_fields
|= wxURI_PATH
;
714 // if defined(R.query) then
715 // T.query = R.query;
717 // T.query = Base.query;
721 m_query
= base
.m_query
;
722 m_fields
|= wxURI_QUERY
;
727 // if (R.path starts-with "/") then
728 // T.path = remove_dot_segments(R.path);
730 // T.path = merge(Base.path, R.path);
731 // T.path = remove_dot_segments(T.path);
733 // T.query = R.query;
734 if (m_path
[(const size_t&)0] != '/')
737 const wxChar
* op
= m_path
.c_str();
738 const wxChar
* bp
= base
.m_path
.c_str() + base
.m_path
.Length();
740 //not a ending directory? move up
741 if (base
.m_path
[0] && *(bp
-1) != '/')
742 UpTree(base
.m_path
, bp
);
744 //normalize directories
745 while(*op
== '.' && *(op
+1) == '.' &&
746 (*(op
+2) == '\0' || *(op
+2) == '/') )
748 UpTree(base
.m_path
, bp
);
756 m_path
= base
.m_path
.substr(0, bp
- base
.m_path
.c_str()) +
757 m_path
.Mid((op
- m_path
.c_str()), m_path
.Length());
762 // ---------------------------------------------------------------------------
763 // Directory Normalization (static)
765 // UpTree goes up a directory in a string and moves the pointer as such,
766 // while Normalize gets rid of duplicate/erronues directories in a URI
767 // according to RFC 2396 and modified quite a bit to meet the unit tests
769 // ---------------------------------------------------------------------------
771 void wxURI
::UpTree(const wxChar
* uristart
, const wxChar
*& uri
)
773 if (uri
!= uristart
&& *(uri
-1) == '/')
778 for(;uri
!= uristart
; --uri
)
788 if (uri
== uristart
&& *uri
== '/')
793 void wxURI
::Normalize(wxChar
* s
, bool bIgnoreLeads
)
803 if (*cp
== '.' && (*(cp
+1) == '/' || *(cp
+1) == '\0')
804 && (bp
== cp
|| *(cp
-1) == '/'))
812 else if (*cp
== '.' && *(cp
+1) == '.' &&
813 (*(cp
+2) == '/' || *(cp
+2) == '\0')
814 && (bp
== cp
|| *(cp
-1) == '/'))
816 //.. _or_ ../ - go up the tree
819 UpTree((const wxChar
*)bp
, (const wxChar
*&)s
);
826 else if (!bIgnoreLeads
)
851 // ---------------------------------------------------------------------------
852 // Misc. Parsing Methods
853 // ---------------------------------------------------------------------------
855 bool wxURI
::ParseIPv4address(const wxChar
*& uri
)
857 //IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
859 //dec-octet = DIGIT ; 0-9
860 // / %x31-39 DIGIT ; 10-99
861 // / "1" 2DIGIT ; 100-199
862 // / "2" %x30-34 DIGIT ; 200-249
863 // / "25" %x30-35 ; 250-255
870 //each ip part must be between 0-255 (dupe of version in for loop)
871 if( IsDigit(*++uri
) && IsDigit(*++uri
) &&
872 //100 or less (note !)
873 !( (*(uri
-2) < '2') ||
876 (*(uri
-1) < '5' || (*(uri
-1) == '5' && *uri
<= '5'))
884 if(IsDigit(*uri
))++uri
;
886 //compilers should unroll this loop
887 for(; iIPv4
< 4; ++iIPv4
)
889 if (*uri
!= '.' || !IsDigit(*++uri
))
892 //each ip part must be between 0-255
893 if( IsDigit(*++uri
) && IsDigit(*++uri
) &&
894 //100 or less (note !)
895 !( (*(uri
-2) < '2') ||
898 (*(uri
-1) < '5' || (*(uri
-1) == '5' && *uri
<= '5'))
905 if(IsDigit(*uri
))++uri
;
911 bool wxURI
::ParseH16(const wxChar
*& uri
)
917 if(IsHex(*++uri
) && IsHex(*++uri
) && IsHex(*++uri
))
923 bool wxURI
::ParseIPv6address(const wxChar
*& uri
)
925 // IPv6address = 6( h16 ":" ) ls32
926 // / "::" 5( h16 ":" ) ls32
927 // / [ h16 ] "::" 4( h16 ":" ) ls32
928 // / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
929 // / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
930 // / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
931 // / [ *4( h16 ":" ) h16 ] "::" ls32
932 // / [ *5( h16 ":" ) h16 ] "::" h16
933 // / [ *6( h16 ":" ) h16 ] "::"
935 size_t numPrefix
= 0,
938 bool bEndHex
= false;
940 for( ; numPrefix
< 6; ++numPrefix
)
955 if(!bEndHex
&& !ParseH16(uri
))
974 if (*uri
!= ':' || *(uri
+1) != ':')
979 while (*--uri
!= ':') {}
982 const wxChar
* uristart
= uri
;
984 // ls32 = ( h16 ":" h16 ) / IPv4address
985 if (ParseH16(uri
) && *uri
== ':' && ParseH16(uri
))
990 if (ParseIPv4address(uri
))
1002 maxPostfix
= 4 - numPrefix
;
1006 bool bAllowAltEnding
= maxPostfix
== 0;
1008 for(; maxPostfix
!= 0; --maxPostfix
)
1010 if(!ParseH16(uri
) || *uri
!= ':')
1016 const wxChar
* uristart
= uri
;
1018 // ls32 = ( h16 ":" h16 ) / IPv4address
1019 if (ParseH16(uri
) && *uri
== ':' && ParseH16(uri
))
1024 if (ParseIPv4address(uri
))
1029 if (!bAllowAltEnding
)
1033 if(numPrefix
<= 5 && ParseH16(uri
))
1039 bool wxURI
::ParseIPvFuture(const wxChar
*& uri
)
1041 // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
1042 if (*++uri
!= 'v' || !IsHex(*++uri
))
1045 while (IsHex(*++uri
)) {}
1047 if (*uri
!= '.' || !(IsUnreserved(*++uri
) || IsSubDelim(*uri
) || *uri
== ':'))
1050 while(IsUnreserved(*++uri
) || IsSubDelim(*uri
) || *uri
== ':') {}
1056 // ---------------------------------------------------------------------------
1057 // Misc methods - IsXXX and CharToHex
1058 // ---------------------------------------------------------------------------
1060 int wxURI
::CharToHex(const wxChar
& c
)
1062 if ((c
>= 'A') && (c
<= 'Z')) return c
- 'A' + 0x0A;
1063 if ((c
>= 'a') && (c
<= 'z')) return c
- 'a' + 0x0a;
1064 if ((c
>= '0') && (c
<= '9')) return c
- '0' + 0x00;
1069 //! unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1070 bool wxURI
::IsUnreserved (const wxChar
& c
)
1071 { return IsAlpha(c
) || IsDigit(c
) ||
1079 bool wxURI
::IsReserved (const wxChar
& c
)
1081 return IsGenDelim(c
) || IsSubDelim(c
);
1084 //! gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
1085 bool wxURI
::IsGenDelim (const wxChar
& c
)
1096 //! sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1097 //! / "*" / "+" / "," / ";" / "="
1098 bool wxURI
::IsSubDelim (const wxChar
& c
)
1114 bool wxURI
::IsHex(const wxChar
& c
)
1115 { return IsDigit(c
) || (c
>= 'a' && c
<= 'f') || (c
>= 'A' && c
<= 'F'); }
1117 bool wxURI
::IsAlpha(const wxChar
& c
)
1118 { return (c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z'); }
1120 bool wxURI
::IsDigit(const wxChar
& c
)
1121 { return c
>= '0' && c
<= '9'; }
1124 // ---------------------------------------------------------------------------
1126 // wxURL Compatability
1128 // TODO: Use wxURI instead here...
1129 // ---------------------------------------------------------------------------
1135 wxString wxURL
::ConvertToValidURI(const wxString
& uri
, const wxChar
* delims
)
1141 for (i
= 0; i
< uri
.Len(); i
++)
1143 wxChar c
= uri
.GetChar(i
);
1147 // GRG, Apr/2000: changed to "%20" instead of '+'
1149 out_str
+= wxT("%20");
1153 // GRG, Apr/2000: modified according to the URI definition (RFC 2396)
1155 // - Alphanumeric characters are never escaped
1156 // - Unreserved marks are never escaped
1157 // - Delimiters must be escaped if they appear within a component
1158 // but not if they are used to separate components. Here we have
1159 // no clear way to distinguish between these two cases, so they
1160 // are escaped unless they are passed in the 'delims' parameter
1161 // (allowed delimiters).
1163 static const wxChar marks
[] = wxT("-_.!~*()'");
1165 if ( !wxIsalnum(c
) && !wxStrchr(marks
, c
) && !wxStrchr(delims
, c
) )
1167 hexa_code
.Printf(wxT("%%%02X"), c
);
1168 out_str
+= hexa_code
;
1180 wxString wxURL
::ConvertFromURI(const wxString
& uri
)
1185 while (i
< uri
.Len())
1188 if (uri
[i
] == wxT('%'))
1191 if (uri
[i
] >= wxT('A') && uri
[i
] <= wxT('F'))
1192 code
= (uri
[i
] - wxT('A') + 10) * 16;
1193 else if (uri
[i
] >= wxT('a') && uri
[i
] <= wxT('f'))
1194 code
= (uri
[i
] - wxT('a') + 10) * 16;
1196 code
= (uri
[i
] - wxT('0')) * 16;
1199 if (uri
[i
] >= wxT('A') && uri
[i
] <= wxT('F'))
1200 code
+= (uri
[i
] - wxT('A')) + 10;
1201 else if (uri
[i
] >= wxT('a') && uri
[i
] <= wxT('f'))
1202 code
+= (uri
[i
] - wxT('a')) + 10;
1204 code
+= (uri
[i
] - wxT('0'));
1207 new_uri
+= (wxChar
)code
;