~ubuntu-dev/wxwidgets2.6/upstream-debian

« back to all changes in this revision

Viewing changes to src/common/uri.cpp

  • Committer: Daniel T Chen
  • Date: 2006-06-26 10:15:11 UTC
  • Revision ID: crimsun@ubuntu.com-20060626101511-a4436cec4c6d9b35
ImportĀ DebianĀ 2.6.3.2.1

Show diffs side-by-side

added added

removed removed

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