]> git.saurik.com Git - wxWidgets.git/blob - src/common/uri.cpp
Borland warning fix.
[wxWidgets.git] / src / common / uri.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: uri.cpp
3 // Purpose: Implementation of a uri parser
4 // Author: Ryan Norton
5 // Created: 10/26/04
6 // RCS-ID: $Id$
7 // Copyright: (c) 2004 Ryan Norton
8 // Licence: wxWindows
9 /////////////////////////////////////////////////////////////////////////////
10
11 //
12 //TODO: RN: I had some massive doxygen docs, I need to move these
13 //in a presentable form in these sources
14 //
15
16 // ===========================================================================
17 // declarations
18 // ===========================================================================
19
20 // ---------------------------------------------------------------------------
21 // headers
22 // ---------------------------------------------------------------------------
23
24 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
25 #pragma implementation "uri.h"
26 #endif
27
28 // For compilers that support precompilation, includes "wx.h".
29 #include "wx/wxprec.h"
30
31 #ifdef __BORLANDC__
32 #pragma hdrstop
33 #endif
34
35 #include "wx/uri.h"
36
37 // ---------------------------------------------------------------------------
38 // definitions
39 // ---------------------------------------------------------------------------
40
41 IMPLEMENT_CLASS(wxURI, wxObject);
42
43 // ===========================================================================
44 // implementation
45 // ===========================================================================
46
47 // ---------------------------------------------------------------------------
48 // utilities
49 // ---------------------------------------------------------------------------
50
51 // ---------------------------------------------------------------------------
52 //
53 // wxURI
54 //
55 // ---------------------------------------------------------------------------
56
57 // ---------------------------------------------------------------------------
58 // Constructors
59 // ---------------------------------------------------------------------------
60
61 wxURI::wxURI() : m_hostType(wxURI_REGNAME), m_fields(0)
62 {
63 }
64
65 wxURI::wxURI(const wxString& uri) : m_hostType(wxURI_REGNAME), m_fields(0)
66 {
67 Create(uri);
68 }
69
70 wxURI::wxURI(const wxURI& uri) : m_hostType(wxURI_REGNAME), m_fields(0)
71 {
72 Assign(uri);
73 }
74
75 // ---------------------------------------------------------------------------
76 // Destructor and cleanup
77 // ---------------------------------------------------------------------------
78
79 wxURI::~wxURI()
80 {
81 Clear();
82 }
83
84 void wxURI::Clear()
85 {
86 m_scheme = m_user = m_server = m_port = m_path =
87 m_query = m_fragment = wxT("");
88
89 m_hostType = wxURI_REGNAME;
90
91 m_fields = 0;
92 }
93
94 // ---------------------------------------------------------------------------
95 // Create
96 //
97 // This creates the URI - all we do here is call the main parsing method
98 // ---------------------------------------------------------------------------
99
100 const wxChar* wxURI::Create(const wxString& uri)
101 {
102 if (m_fields)
103 Clear();
104
105 return Parse(uri);
106 }
107
108 // ---------------------------------------------------------------------------
109 // Escape/TranslateEscape/IsEscape
110 //
111 // TranslateEscape 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 // ---------------------------------------------------------------------------
116
117 wxChar wxURI::TranslateEscape(const wxChar* s)
118 {
119 wxASSERT_MSG(IsHex(*s) && IsHex(*(s+1)), wxT("Invalid escape!"));
120
121 return CharToHex(*s) * 0x10 + CharToHex(*++s);
122 }
123
124 wxString wxURI::Unescape(const wxString& uri)
125 {
126 wxString new_uri;
127
128 for(size_t i = 0; i < uri.length(); ++i)
129 {
130 if (uri[i] == wxT('%'))
131 {
132 new_uri += wxURI::TranslateEscape( &(uri.c_str()[i+1]) );
133 i += 2;
134 }
135 }
136
137 return new_uri;
138 }
139
140 void wxURI::Escape(wxString& s, const wxChar& c)
141 {
142 const wxChar* hdig = wxT("0123456789abcdef");
143 s += '%';
144 s += hdig[(c >> 4) & 15];
145 s += hdig[c & 15];
146 }
147
148 bool wxURI::IsEscape(const wxChar*& uri)
149 {
150 if(*uri == '%' && IsHex(*(uri+1)) && IsHex(*(uri+2)))
151 {
152 uri += 3;
153 return true;
154 }
155 else
156 return false;
157 }
158
159 // ---------------------------------------------------------------------------
160 // BuildURI
161 //
162 // BuildURI() builds the entire URI into a useable
163 // representation, including proper identification characters such as slashes
164 // ---------------------------------------------------------------------------
165
166 wxString wxURI::BuildURI() const
167 {
168 wxString ret;
169
170 if (HasScheme())
171 ret = ret + m_scheme + wxT(":");
172
173 if (HasServer())
174 {
175 ret += wxT("//");
176
177 if (HasUser())
178 ret = ret + m_user + wxT("@");
179
180 ret += m_server;
181
182 if (HasPort())
183 ret = ret + wxT(":") + m_port;
184 }
185
186 ret += m_path;
187
188 if (HasQuery())
189 ret = ret + wxT("?") + m_query;
190
191 if (HasFragment())
192 ret = ret + wxT("#") + m_fragment;
193
194 return ret;
195 }
196
197 wxString wxURI::BuildUnescapedURI() const
198 {
199 wxString ret;
200
201 if (HasScheme())
202 ret = ret + m_scheme + wxT(":");
203
204 if (HasServer())
205 {
206 ret += wxT("//");
207
208 if (HasUser())
209 ret = ret + wxURI::Unescape(m_user) + wxT("@");
210
211 if (m_hostType == wxURI_REGNAME)
212 ret += wxURI::Unescape(m_server);
213 else
214 ret += m_server;
215
216 if (HasPort())
217 ret = ret + wxT(":") + m_port;
218 }
219
220 ret += wxURI::Unescape(m_path);
221
222 if (HasQuery())
223 ret = ret + wxT("?") + wxURI::Unescape(m_query);
224
225 if (HasFragment())
226 ret = ret + wxT("#") + wxURI::Unescape(m_fragment);
227
228 return ret;
229 }
230
231 // ---------------------------------------------------------------------------
232 // operator = and ==
233 // ---------------------------------------------------------------------------
234
235 wxURI& wxURI::operator = (const wxURI& uri)
236 {
237 return Assign(uri);
238 }
239
240 wxURI& wxURI::Assign(const wxURI& uri)
241 {
242 //assign fields
243 m_fields = uri.m_fields;
244
245 //ref over components
246 m_scheme = uri.m_scheme;
247 m_user = uri.m_user;
248 m_server = uri.m_server;
249 m_hostType = uri.m_hostType;
250 m_port = uri.m_port;
251 m_path = uri.m_path;
252 m_query = uri.m_query;
253 m_fragment = uri.m_fragment;
254
255 return *this;
256 }
257
258 wxURI& wxURI::operator = (const wxString& string)
259 {
260 Create(string);
261 return *this;
262 }
263
264 bool wxURI::operator == (const wxURI& uri) const
265 {
266 if (HasScheme())
267 {
268 if(m_scheme != uri.m_scheme)
269 return false;
270 }
271 else if (uri.HasScheme())
272 return false;
273
274
275 if (HasServer())
276 {
277 if (HasUser())
278 {
279 if (m_user != uri.m_user)
280 return false;
281 }
282 else if (uri.HasUser())
283 return false;
284
285 if (m_server != uri.m_server ||
286 m_hostType != uri.m_hostType)
287 return false;
288
289 if (HasPort())
290 {
291 if(m_port != uri.m_port)
292 return false;
293 }
294 else if (uri.HasPort())
295 return false;
296 }
297 else if (uri.HasServer())
298 return false;
299
300
301 if (HasPath())
302 {
303 if(m_path != uri.m_path)
304 return false;
305 }
306 else if (uri.HasPath())
307 return false;
308
309 if (HasQuery())
310 {
311 if (m_query != uri.m_query)
312 return false;
313 }
314 else if (uri.HasQuery())
315 return false;
316
317 if (HasFragment())
318 {
319 if (m_fragment != uri.m_fragment)
320 return false;
321 }
322 else if (uri.HasFragment())
323 return false;
324
325 return true;
326 }
327
328 // ---------------------------------------------------------------------------
329 // IsReference
330 //
331 // if there is no authority or scheme, it is a reference
332 // ---------------------------------------------------------------------------
333
334 bool wxURI::IsReference() const
335 { return !HasScheme() || !HasServer(); }
336
337 // ---------------------------------------------------------------------------
338 // Parse
339 //
340 // Master URI parsing method. Just calls the individual parsing methods
341 //
342 // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
343 // URI-reference = URI / relative-URITestCase
344 // ---------------------------------------------------------------------------
345
346 const wxChar* wxURI::Parse(const wxChar* uri)
347 {
348 uri = ParseScheme(uri);
349 uri = ParseAuthority(uri);
350 uri = ParsePath(uri);
351 uri = ParseQuery(uri);
352 return ParseFragment(uri);
353 }
354
355 // ---------------------------------------------------------------------------
356 // ParseXXX
357 //
358 // Individual parsers for each URI component
359 // ---------------------------------------------------------------------------
360
361 const wxChar* wxURI::ParseScheme(const wxChar* uri)
362 {
363 wxASSERT(uri != NULL);
364
365 //copy of the uri - used for figuring out
366 //length of each component
367 const wxChar* uricopy = uri;
368
369 //Does the uri have a scheme (first character alpha)?
370 if (IsAlpha(*uri))
371 {
372 m_scheme += *uri++;
373
374 //scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
375 //RN: Scheme can not be escaped
376 while (IsAlpha(*uri) || IsDigit(*uri) ||
377 *uri == '+' ||
378 *uri == '-' ||
379 *uri == '.')
380 {
381 m_scheme += *uri++;
382 }
383
384 //valid scheme?
385 if (*uri == ':')
386 {
387 //mark the scheme as valid
388 m_fields |= wxURI_SCHEME;
389
390 //move reference point up to input buffer
391 uricopy = ++uri;
392 }
393 else
394 //relative uri with relative path reference
395 m_scheme = wxT("");
396 }
397 // else
398 //relative uri with _possible_ relative path reference
399
400 return uricopy;
401 }
402
403 const wxChar* wxURI::ParseAuthority(const wxChar* uri)
404 {
405 // authority = [ userinfo "@" ] host [ ":" port ]
406 if (*uri == '/' && *(uri+1) == '/')
407 {
408 uri += 2;
409
410 uri = ParseUser(uri);
411 uri = ParseServer(uri);
412 return ParsePort(uri);
413 }
414
415 return uri;
416 }
417
418 const wxChar* wxURI::ParseUser(const wxChar* uri)
419 {
420 wxASSERT(uri != NULL);
421
422 //copy of the uri - used for figuring out
423 //length of each component
424 const wxChar* uricopy = uri;
425
426 // userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
427 while(*uri && *uri != '@' && *uri != '/' && *uri != '#' && *uri != '?')
428 {
429 if(IsUnreserved(*uri) || IsEscape(uri) ||
430 IsSubDelim(*uri) || *uri == ':')
431 m_user += *uri++;
432 else
433 Escape(m_user, *uri++);
434 }
435
436 if(*uri == '@')
437 {
438 //valid userinfo
439 m_fields |= wxURI_USER;
440
441 uricopy = ++uri;
442 }
443 else
444 m_user = wxT("");
445
446 return uricopy;
447 }
448
449 const wxChar* wxURI::ParseServer(const wxChar* uri)
450 {
451 wxASSERT(uri != NULL);
452
453 //copy of the uri - used for figuring out
454 //length of each component
455 const wxChar* uricopy = uri;
456
457 // host = IP-literal / IPv4address / reg-name
458 // IP-literal = "[" ( IPv6address / IPvFuture ) "]"
459 if (*uri == '[')
460 {
461 if (ParseIPv6address(++uri) && *uri == ']')
462 {
463 ++uri;
464 m_hostType = wxURI_IPV6ADDRESS;
465
466 wxStringBufferLength theBuffer(m_server, uri - uricopy);
467 wxMemcpy(theBuffer, uricopy, uri-uricopy);
468 theBuffer.SetLength(uri-uricopy);
469 }
470 else
471 {
472 uri = uricopy;
473
474 if (ParseIPvFuture(++uri) && *uri == ']')
475 {
476 ++uri;
477 m_hostType = wxURI_IPVFUTURE;
478
479 wxStringBufferLength theBuffer(m_server, uri - uricopy);
480 wxMemcpy(theBuffer, uricopy, uri-uricopy);
481 theBuffer.SetLength(uri-uricopy);
482 }
483 else
484 uri = uricopy;
485 }
486 }
487 else
488 {
489 if (ParseIPv4address(uri))
490 {
491 m_hostType = wxURI_IPV4ADDRESS;
492
493 wxStringBufferLength theBuffer(m_server, uri - uricopy);
494 wxMemcpy(theBuffer, uricopy, uri-uricopy);
495 theBuffer.SetLength(uri-uricopy);
496 }
497 else
498 uri = uricopy;
499 }
500
501 if(m_hostType == wxURI_REGNAME)
502 {
503 uri = uricopy;
504 // reg-name = *( unreserved / pct-encoded / sub-delims )
505 while(*uri && *uri != '/' && *uri != ':' && *uri != '#' && *uri != '?')
506 {
507 if(IsUnreserved(*uri) || IsEscape(uri) || IsSubDelim(*uri))
508 m_server += *uri++;
509 else
510 Escape(m_server, *uri++);
511 }
512 }
513
514 //mark the server as valid
515 m_fields |= wxURI_SERVER;
516
517 return uri;
518 }
519
520
521 const wxChar* wxURI::ParsePort(const wxChar* uri)
522 {
523 wxASSERT(uri != NULL);
524
525 // port = *DIGIT
526 if(*uri == ':')
527 {
528 ++uri;
529 while(IsDigit(*uri))
530 {
531 m_port += *uri++;
532 }
533
534 //mark the port as valid
535 m_fields |= wxURI_PORT;
536 }
537
538 return uri;
539 }
540
541 const wxChar* wxURI::ParsePath(const wxChar* uri, bool bReference, bool bNormalize)
542 {
543 wxASSERT(uri != NULL);
544
545 //copy of the uri - used for figuring out
546 //length of each component
547 const wxChar* uricopy = uri;
548
549 /// hier-part = "//" authority path-abempty
550 /// / path-absolute
551 /// / path-rootless
552 /// / path-empty
553 ///
554 /// relative-part = "//" authority path-abempty
555 /// / path-absolute
556 /// / path-noscheme
557 /// / path-empty
558 ///
559 /// path-abempty = *( "/" segment )
560 /// path-absolute = "/" [ segment-nz *( "/" segment ) ]
561 /// path-noscheme = segment-nz-nc *( "/" segment )
562 /// path-rootless = segment-nz *( "/" segment )
563 /// path-empty = 0<pchar>
564 ///
565 /// segment = *pchar
566 /// segment-nz = 1*pchar
567 /// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
568 /// ; non-zero-length segment without any colon ":"
569 ///
570 /// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
571 if (*uri == '/')
572 {
573 m_path += *uri++;
574
575 while(*uri && *uri != '#' && *uri != '?')
576 {
577 if( IsUnreserved(*uri) || IsSubDelim(*uri) || IsEscape(uri) ||
578 *uri == ':' || *uri == '@' || *uri == '/')
579 m_path += *uri++;
580 else
581 Escape(m_path, *uri++);
582 }
583
584 if (bNormalize)
585 {
586 wxStringBufferLength theBuffer(m_path, m_path.length() + 1);
587 Normalize(theBuffer, true);
588 theBuffer.SetLength(wxStrlen(theBuffer));
589 }
590 //mark the path as valid
591 m_fields |= wxURI_PATH;
592 }
593 else if(*uri) //Relative path
594 {
595 if (bReference)
596 {
597 //no colon allowed
598 while(*uri && *uri != '#' && *uri != '?')
599 {
600 if(IsUnreserved(*uri) || IsSubDelim(*uri) || IsEscape(uri) ||
601 *uri == '@' || *uri == '/')
602 m_path += *uri++;
603 else
604 Escape(m_path, *uri++);
605 }
606 }
607 else
608 {
609 while(*uri && *uri != '#' && *uri != '?')
610 {
611 if(IsUnreserved(*uri) || IsSubDelim(*uri) || IsEscape(uri) ||
612 *uri == ':' || *uri == '@' || *uri == '/')
613 m_path += *uri++;
614 else
615 Escape(m_path, *uri++);
616 }
617 }
618
619 if (uri != uricopy)
620 {
621 if (bNormalize)
622 {
623 wxStringBufferLength theBuffer(m_path, m_path.length() + 1);
624 Normalize(theBuffer);
625 theBuffer.SetLength(wxStrlen(theBuffer));
626 }
627
628 //mark the path as valid
629 m_fields |= wxURI_PATH;
630 }
631 }
632
633 return uri;
634 }
635
636
637 const wxChar* wxURI::ParseQuery(const wxChar* uri)
638 {
639 wxASSERT(uri != NULL);
640
641 // query = *( pchar / "/" / "?" )
642 if (*uri == '?')
643 {
644 ++uri;
645 while(*uri && *uri != '#')
646 {
647 if (IsUnreserved(*uri) || IsSubDelim(*uri) || IsEscape(uri) ||
648 *uri == ':' || *uri == '@' || *uri == '/' || *uri == '?')
649 m_query += *uri++;
650 else
651 Escape(m_query, *uri++);
652 }
653
654 //mark the server as valid
655 m_fields |= wxURI_QUERY;
656 }
657
658 return uri;
659 }
660
661
662 const wxChar* wxURI::ParseFragment(const wxChar* uri)
663 {
664 wxASSERT(uri != NULL);
665
666 // fragment = *( pchar / "/" / "?" )
667 if (*uri == '#')
668 {
669 ++uri;
670 while(*uri)
671 {
672 if (IsUnreserved(*uri) || IsSubDelim(*uri) || IsEscape(uri) ||
673 *uri == ':' || *uri == '@' || *uri == '/' || *uri == '?')
674 m_fragment += *uri++;
675 else
676 Escape(m_fragment, *uri++);
677 }
678
679 //mark the server as valid
680 m_fields |= wxURI_FRAGMENT;
681 }
682
683 return uri;
684 }
685
686 // ---------------------------------------------------------------------------
687 // Resolve URI
688 //
689 // Builds missing components of this uri from a base uri
690 //
691 // A version of the algorithm outlined in the RFC is used here
692 // (it is shown in comments)
693 // ---------------------------------------------------------------------------
694
695 void wxURI::Resolve(const wxURI& base, int flags)
696 {
697 wxASSERT_MSG(!base.IsReference(),
698 wxT("wxURI to inherit from must not be a reference!"));
699
700 // If we arn't being strict, enable the older
701 // loophole that allows this uri to inherit other
702 // properties from the base uri - even if the scheme
703 // is defined
704 if ( !(flags & wxURI_STRICT) &&
705 HasScheme() && base.HasScheme() &&
706 m_scheme == base.m_scheme )
707 {
708 m_fields -= wxURI_SCHEME;
709 }
710
711
712 // Do nothing if this is an absolute wxURI
713 // if defined(R.scheme) then
714 // T.scheme = R.scheme;
715 // T.authority = R.authority;
716 // T.path = remove_dot_segments(R.path);
717 // T.query = R.query;
718 if (HasScheme())
719 {
720 return;
721 }
722
723 //No sheme - inherit
724 m_scheme = base.m_scheme;
725 m_fields |= wxURI_SCHEME;
726
727 // All we need to do for relative URIs with an
728 // authority component is just inherit the scheme
729 // if defined(R.authority) then
730 // T.authority = R.authority;
731 // T.path = remove_dot_segments(R.path);
732 // T.query = R.query;
733 if (HasServer())
734 {
735 return;
736 }
737
738 //No authority - inherit
739 if (base.HasUser())
740 {
741 m_user = base.m_user;
742 m_fields |= wxURI_USER;
743 }
744
745 m_server = base.m_server;
746 m_hostType = base.m_hostType;
747 m_fields |= wxURI_SERVER;
748
749 if (base.HasPort())
750 {
751 m_port = base.m_port;
752 m_fields |= wxURI_PORT;
753 }
754
755
756 // Simple path inheritance from base
757 if (!HasPath())
758 {
759 // T.path = Base.path;
760 m_path = base.m_path;
761 m_fields |= wxURI_PATH;
762
763
764 // if defined(R.query) then
765 // T.query = R.query;
766 // else
767 // T.query = Base.query;
768 // endif;
769 if (!HasQuery())
770 {
771 m_query = base.m_query;
772 m_fields |= wxURI_QUERY;
773 }
774 }
775 else
776 {
777 // if (R.path starts-with "/") then
778 // T.path = remove_dot_segments(R.path);
779 // else
780 // T.path = merge(Base.path, R.path);
781 // T.path = remove_dot_segments(T.path);
782 // endif;
783 // T.query = R.query;
784 if (!m_path.StartsWith(wxT("/")))
785 {
786 //Marge paths
787 const wxChar* op = m_path.c_str();
788 const wxChar* bp = base.m_path.c_str() + base.m_path.Length();
789
790 //not a ending directory? move up
791 if (base.m_path[0] && *(bp-1) != '/')
792 UpTree(base.m_path, bp);
793
794 //normalize directories
795 while(*op == '.' && *(op+1) == '.' &&
796 (*(op+2) == '\0' || *(op+2) == '/') )
797 {
798 UpTree(base.m_path, bp);
799
800 if (*(op+2) == '\0')
801 op += 2;
802 else
803 op += 3;
804 }
805
806 m_path = base.m_path.substr(0, bp - base.m_path.c_str()) +
807 m_path.Mid((op - m_path.c_str()), m_path.Length());
808 }
809 }
810 }
811
812 // ---------------------------------------------------------------------------
813 // Directory Normalization (static)
814 //
815 // UpTree goes up a directory in a string and moves the pointer as such,
816 // while Normalize gets rid of duplicate/erronues directories in a URI
817 // according to RFC 2396 and modified quite a bit to meet the unit tests
818 // in it.
819 // ---------------------------------------------------------------------------
820
821 void wxURI::UpTree(const wxChar* uristart, const wxChar*& uri)
822 {
823 if (uri != uristart && *(uri-1) == '/')
824 {
825 uri -= 2;
826 }
827
828 for(;uri != uristart; --uri)
829 {
830 if (*uri == '/')
831 {
832 ++uri;
833 break;
834 }
835 }
836
837 //!!!TODO:HACK!!!//
838 if (uri == uristart && *uri == '/')
839 ++uri;
840 //!!!//
841 }
842
843 void wxURI::Normalize(wxChar* s, bool bIgnoreLeads)
844 {
845 wxChar* cp = s;
846 wxChar* bp = s;
847
848 if(s[0] == '/')
849 ++bp;
850
851 while(*cp)
852 {
853 if (*cp == '.' && (*(cp+1) == '/' || *(cp+1) == '\0')
854 && (bp == cp || *(cp-1) == '/'))
855 {
856 //. _or_ ./ - ignore
857 if (*(cp+1) == '\0')
858 cp += 1;
859 else
860 cp += 2;
861 }
862 else if (*cp == '.' && *(cp+1) == '.' &&
863 (*(cp+2) == '/' || *(cp+2) == '\0')
864 && (bp == cp || *(cp-1) == '/'))
865 {
866 //.. _or_ ../ - go up the tree
867 if (s != bp)
868 {
869 UpTree((const wxChar*)bp, (const wxChar*&)s);
870
871 if (*(cp+2) == '\0')
872 cp += 2;
873 else
874 cp += 3;
875 }
876 else if (!bIgnoreLeads)
877
878 {
879 *bp++ = *cp++;
880 *bp++ = *cp++;
881 if (*cp)
882 *bp++ = *cp++;
883
884 s = bp;
885 }
886 else
887 {
888 if (*(cp+2) == '\0')
889 cp += 2;
890 else
891 cp += 3;
892 }
893 }
894 else
895 *s++ = *cp++;
896 }
897
898 *s = '\0';
899 }
900
901 // ---------------------------------------------------------------------------
902 // Misc. Parsing Methods
903 // ---------------------------------------------------------------------------
904
905 bool wxURI::ParseIPv4address(const wxChar*& uri)
906 {
907 //IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
908 //
909 //dec-octet = DIGIT ; 0-9
910 // / %x31-39 DIGIT ; 10-99
911 // / "1" 2DIGIT ; 100-199
912 // / "2" %x30-34 DIGIT ; 200-249
913 // / "25" %x30-35 ; 250-255
914 size_t iIPv4 = 0;
915 if (IsDigit(*uri))
916 {
917 ++iIPv4;
918
919
920 //each ip part must be between 0-255 (dupe of version in for loop)
921 if( IsDigit(*++uri) && IsDigit(*++uri) &&
922 //100 or less (note !)
923 !( (*(uri-2) < '2') ||
924 //240 or less
925 (*(uri-2) == '2' &&
926 (*(uri-1) < '5' || (*(uri-1) == '5' && *uri <= '5'))
927 )
928 )
929 )
930 {
931 return false;
932 }
933
934 if(IsDigit(*uri))++uri;
935
936 //compilers should unroll this loop
937 for(; iIPv4 < 4; ++iIPv4)
938 {
939 if (*uri != '.' || !IsDigit(*++uri))
940 break;
941
942 //each ip part must be between 0-255
943 if( IsDigit(*++uri) && IsDigit(*++uri) &&
944 //100 or less (note !)
945 !( (*(uri-2) < '2') ||
946 //240 or less
947 (*(uri-2) == '2' &&
948 (*(uri-1) < '5' || (*(uri-1) == '5' && *uri <= '5'))
949 )
950 )
951 )
952 {
953 return false;
954 }
955 if(IsDigit(*uri))++uri;
956 }
957 }
958 return iIPv4 == 4;
959 }
960
961 bool wxURI::ParseH16(const wxChar*& uri)
962 {
963 // h16 = 1*4HEXDIG
964 if(!IsHex(*++uri))
965 return false;
966
967 if(IsHex(*++uri) && IsHex(*++uri) && IsHex(*++uri))
968 ++uri;
969
970 return true;
971 }
972
973 bool wxURI::ParseIPv6address(const wxChar*& uri)
974 {
975 // IPv6address = 6( h16 ":" ) ls32
976 // / "::" 5( h16 ":" ) ls32
977 // / [ h16 ] "::" 4( h16 ":" ) ls32
978 // / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
979 // / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
980 // / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
981 // / [ *4( h16 ":" ) h16 ] "::" ls32
982 // / [ *5( h16 ":" ) h16 ] "::" h16
983 // / [ *6( h16 ":" ) h16 ] "::"
984
985 size_t numPrefix = 0,
986 maxPostfix;
987
988 bool bEndHex = false;
989
990 for( ; numPrefix < 6; ++numPrefix)
991 {
992 if(!ParseH16(uri))
993 {
994 --uri;
995 bEndHex = true;
996 break;
997 }
998
999 if(*uri != ':')
1000 {
1001 break;
1002 }
1003 }
1004
1005 if(!bEndHex && !ParseH16(uri))
1006 {
1007 --uri;
1008
1009 if (numPrefix)
1010 return false;
1011
1012 if (*uri == ':')
1013 {
1014 if (*++uri != ':')
1015 return false;
1016
1017 maxPostfix = 5;
1018 }
1019 else
1020 maxPostfix = 6;
1021 }
1022 else
1023 {
1024 if (*uri != ':' || *(uri+1) != ':')
1025 {
1026 if (numPrefix != 6)
1027 return false;
1028
1029 while (*--uri != ':') {}
1030 ++uri;
1031
1032 const wxChar* uristart = uri;
1033 //parse ls32
1034 // ls32 = ( h16 ":" h16 ) / IPv4address
1035 if (ParseH16(uri) && *uri == ':' && ParseH16(uri))
1036 return true;
1037
1038 uri = uristart;
1039
1040 if (ParseIPv4address(uri))
1041 return true;
1042 else
1043 return false;
1044 }
1045 else
1046 {
1047 uri += 2;
1048
1049 if (numPrefix > 3)
1050 maxPostfix = 0;
1051 else
1052 maxPostfix = 4 - numPrefix;
1053 }
1054 }
1055
1056 bool bAllowAltEnding = maxPostfix == 0;
1057
1058 for(; maxPostfix != 0; --maxPostfix)
1059 {
1060 if(!ParseH16(uri) || *uri != ':')
1061 return false;
1062 }
1063
1064 if(numPrefix <= 4)
1065 {
1066 const wxChar* uristart = uri;
1067 //parse ls32
1068 // ls32 = ( h16 ":" h16 ) / IPv4address
1069 if (ParseH16(uri) && *uri == ':' && ParseH16(uri))
1070 return true;
1071
1072 uri = uristart;
1073
1074 if (ParseIPv4address(uri))
1075 return true;
1076
1077 uri = uristart;
1078
1079 if (!bAllowAltEnding)
1080 return false;
1081 }
1082
1083 if(numPrefix <= 5 && ParseH16(uri))
1084 return true;
1085
1086 return true;
1087 }
1088
1089 bool wxURI::ParseIPvFuture(const wxChar*& uri)
1090 {
1091 // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
1092 if (*++uri != 'v' || !IsHex(*++uri))
1093 return false;
1094
1095 while (IsHex(*++uri)) {}
1096
1097 if (*uri != '.' || !(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == ':'))
1098 return false;
1099
1100 while(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == ':') {}
1101
1102 return true;
1103 }
1104
1105
1106 // ---------------------------------------------------------------------------
1107 // Misc methods - IsXXX and CharToHex
1108 // ---------------------------------------------------------------------------
1109
1110 wxInt32 wxURI::CharToHex(const wxChar& c)
1111 {
1112 if ((c >= 'A') && (c <= 'Z')) return c - 'A' + 0x0A;
1113 if ((c >= 'a') && (c <= 'z')) return c - 'a' + 0x0a;
1114 if ((c >= '0') && (c <= '9')) return c - '0' + 0x00;
1115
1116 return 0;
1117 }
1118
1119 //! unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1120 bool wxURI::IsUnreserved (const wxChar& c)
1121 { return IsAlpha(c) || IsDigit(c) ||
1122 c == '-' ||
1123 c == '.' ||
1124 c == '_' ||
1125 c == '~' //tilde
1126 ;
1127 }
1128
1129 bool wxURI::IsReserved (const wxChar& c)
1130 {
1131 return IsGenDelim(c) || IsSubDelim(c);
1132 }
1133
1134 //! gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
1135 bool wxURI::IsGenDelim (const wxChar& c)
1136 {
1137 return c == ':' ||
1138 c == '/' ||
1139 c == '?' ||
1140 c == '#' ||
1141 c == '[' ||
1142 c == ']' ||
1143 c == '@';
1144 }
1145
1146 //! sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1147 //! / "*" / "+" / "," / ";" / "="
1148 bool wxURI::IsSubDelim (const wxChar& c)
1149 {
1150 return c == '!' ||
1151 c == '$' ||
1152 c == '&' ||
1153 c == '\'' ||
1154 c == '(' ||
1155 c == ')' ||
1156 c == '*' ||
1157 c == '+' ||
1158 c == ',' ||
1159 c == ';' ||
1160 c == '='
1161 ;
1162 }
1163
1164 bool wxURI::IsHex(const wxChar& c)
1165 { return IsDigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); }
1166
1167 bool wxURI::IsAlpha(const wxChar& c)
1168 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
1169
1170 bool wxURI::IsDigit(const wxChar& c)
1171 { return c >= '0' && c <= '9'; }
1172
1173
1174 // ---------------------------------------------------------------------------
1175 //
1176 // wxURL Compatability
1177 //
1178 // ---------------------------------------------------------------------------
1179
1180 #if wxUSE_URL
1181
1182 #if WXWIN_COMPATIBILITY_2_4
1183
1184 #include "wx/url.h"
1185
1186 wxString wxURL::ConvertToValidURI(const wxString& uri, const wxChar* WXUNUSED(delims))
1187 {
1188 return wxURI(uri).BuildURI();
1189 }
1190
1191 wxString wxURL::ConvertFromURI(const wxString& uri)
1192 {
1193 return wxURI::Unescape(uri);
1194 }
1195
1196 #endif //WXWIN_COMPATIBILITY_2_4
1197
1198 #endif //wxUSE_URL
1199
1200 //end of uri.cpp
1201
1202
1203