• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

xlnt-community / xlnt / 40fb2b47-5037-4769-ada4-e5a5c0d256a6

06 May 2026 11:36AM UTC coverage: 84.252% (+0.1%) from 84.151%
40fb2b47-5037-4769-ada4-e5a5c0d256a6

push

circleci

fxrstor
remove unused function `bracket_ipv6_if_needed`

15636 of 20424 branches covered (76.56%)

12877 of 15284 relevant lines covered (84.25%)

11960.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.2
./source/packaging/uri.cpp
1
// Copyright (c) 2014-2022 Thomas Fussell
2
// Copyright (c) 2024-2026 xlnt-community
3
//
4
// Permission is hereby granted, free of charge, to any person obtaining a copy
5
// of this software and associated documentation files (the "Software"), to deal
6
// in the Software without restriction, including without limitation the rights
7
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
// copies of the Software, and to permit persons to whom the Software is
9
// furnished to do so, subject to the following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included in
12
// all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
// THE SOFTWARE
21
//
22
// @license: http://www.opensource.org/licenses/mit-license.php
23
// @author: see AUTHORS file
24

25
#include <xlnt/packaging/uri.hpp>
26

27
#include <algorithm>
28
#include <cctype>
29
#include <limits>
30
#include <string>
31
#include <vector>
32

33
namespace xlnt
34
{
35
namespace
36
{
37
bool starts_with(const std::string &s, const char *prefix)
6,376✔
38
{
39
    const std::size_t n = std::char_traits<char>::length(prefix);
6,376✔
40
    return s.size() >= n && s.compare(0, n, prefix) == 0;
6,376✔
41
}
42

43
std::string lower_copy(std::string s)
23,540✔
44
{
45
    for (char &c : s)
24,044✔
46
    {
47
        c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
504✔
48
    }
49
    return s;
23,540✔
50
}
51

52
bool is_scheme_char(char c)
23,660✔
53
{
54
    return std::isalpha(static_cast<unsigned char>(c)) ||
24,318✔
55
           std::isdigit(static_cast<unsigned char>(c)) ||
658!
56
           c == '+' || c == '-' || c == '.';
24,318!
57
}
58

59
bool looks_like_scheme(const std::string& s)
6,376✔
60
{
61
    if (s.empty() || !std::isalpha(static_cast<unsigned char>(s[0])))
6,376✔
62
        return false;
1,820✔
63

64
    for (std::size_t i = 1; i < s.size(); ++i)
28,201✔
65
    {
66
        char c = s[i];
23,731✔
67
        if (c == ':') return true;
23,731✔
68
        if (!is_scheme_char(c)) return false;
23,660✔
69
    }
70
    return false;
4,470✔
71
}
72

73
bool parse_port(const std::string &s, std::size_t &port)
6✔
74
{
75
    if (s.empty())
6✔
76
    {
77
        return false;
1✔
78
    }
79

80
    std::size_t value = 0;
5✔
81
    for (char c : s)
18✔
82
    {
83
        if (!std::isdigit(static_cast<unsigned char>(c)))
14✔
84
        {
85
            return false;
1✔
86
        }
87

88
        const std::size_t digit = static_cast<std::size_t>(c - '0');
13✔
89
        if (value > (std::numeric_limits<std::size_t>::max() - digit) / 10)
13!
90
        {
91
            return false;
×
92
        }
93

94
        value = value * 10 + digit;
13✔
95
    }
96

97
    port = value;
4✔
98
    return true;
4✔
99
}
100

101
struct parsed_authority
102
{
103
    bool present = false;
104
    bool authentication = false;
105
    bool port_present = false;
106
    std::string username;
107
    std::string password;
108
    std::string host;
109
    std::size_t port = 0;
110
    bool ipv6 = false;
111
};
112

113
parsed_authority parse_authority(const std::string &authority)
64✔
114
{
115
    parsed_authority result;
64✔
116
    result.present = true;
64✔
117

118
    if (authority.empty())
64✔
119
    {
120
        return result;
2✔
121
    }
122

123
    std::string hostport = authority;
62✔
124

125
    const std::size_t at = authority.rfind('@');
62✔
126
    if (at != std::string::npos)
62✔
127
    {
128
        result.authentication = true;
4✔
129
        const std::string userinfo = authority.substr(0, at);
4✔
130
        hostport = authority.substr(at + 1);
4✔
131

132
        const std::size_t colon = userinfo.find(':');
4✔
133
        if (colon != std::string::npos)
4✔
134
        {
135
            result.username = userinfo.substr(0, colon);
3✔
136
            result.password = userinfo.substr(colon + 1);
3✔
137
        }
138
        else
139
        {
140
            result.username = userinfo;
1✔
141
        }
142
    }
4✔
143

144
    if (!hostport.empty() && hostport.front() == '[')
62!
145
    {
146
        result.ipv6 = true;
1✔
147
        const std::size_t close = hostport.find(']');
1✔
148
        if (close != std::string::npos)
1!
149
        {
150
            result.host = hostport.substr(1, close - 1);
1✔
151
            if (close + 1 < hostport.size() && hostport[close + 1] == ':')
1!
152
            {
153
                std::size_t port = 0;
1✔
154
                if (parse_port(hostport.substr(close + 2), port))
1!
155
                {
156
                    result.port_present = true;
1✔
157
                    result.port = port;
1✔
158
                }
159
            }
160
        }
161
        else
162
        {
163
            result.host = hostport;
×
164
        }
165
    }
166
    else
167
    {
168
        const std::size_t colon = hostport.rfind(':');
61✔
169
        if (colon != std::string::npos && hostport.find(':') == colon)
61!
170
        {
171
            std::size_t port = 0;
5✔
172
            if (parse_port(hostport.substr(colon + 1), port))
5✔
173
            {
174
                result.host = hostport.substr(0, colon);
3✔
175
                result.port_present = true;
3✔
176
                result.port = port;
3✔
177
            }
178
            else
179
            {
180
                result.host = hostport;
2✔
181
            }
182
        }
183
        else
184
        {
185
            result.host = hostport;
56✔
186
        }
187
    }
188

189
    return result;
62✔
190
}
62✔
191

192
std::string remove_dot_segments(std::string path)
11,785✔
193
{
194
    std::string output;
11,785✔
195
    while (!path.empty())
30,430✔
196
    {
197
        if (path.compare(0, 3, "../") == 0)
18,645✔
198
        {
199
            path.erase(0, 3);
106✔
200
        }
201
        else if (path.compare(0, 2, "./") == 0)
18,539!
202
        {
203
            path.erase(0, 2);
×
204
        }
205
        else if (path.compare(0, 3, "/./") == 0)
18,539✔
206
        {
207
            path.replace(0, 3, "/");
2✔
208
        }
209
        else if (path == "/.")
18,537✔
210
        {
211
            path = "/";
1✔
212
        }
213
        else if (path.compare(0, 4, "/../") == 0)
18,536✔
214
        {
215
            path.replace(0, 4, "/");
6✔
216
            std::size_t slash = output.find_last_of('/');
6✔
217
            if (slash != std::string::npos)
6!
218
                output.erase(slash);
6✔
219
            else
220
                output.clear();
×
221
        }
222
        else if (path == "/..")
18,530✔
223
        {
224
            path = "/";
2✔
225
            std::size_t slash = output.find_last_of('/');
2✔
226
            if (slash != std::string::npos)
2!
227
                output.erase(slash);
2✔
228
            else
229
                output.clear();
×
230
        }
231
        else if (path == "." || path == "..")
18,528!
232
        {
233
            path.clear();
×
234
        }
235
        else
236
        {
237
            std::size_t next = path.find('/', 1);
18,528✔
238
            if (next == std::string::npos)
18,528✔
239
            {
240
                output += path;
11,784✔
241
                path.clear();
11,784✔
242
            }
243
            else
244
            {
245
                output += path.substr(0, next);
6,744✔
246
                path.erase(0, next);
6,744✔
247
            }
248
        }
249
    }
250
    return output;
11,785✔
251
}
×
252

253
std::string merge_paths(const std::string &base_path, const std::string &relative_path, bool base_has_authority)
18✔
254
{
255
    if (base_has_authority && base_path.empty())
18!
256
    {
257
        return "/" + relative_path;
×
258
    }
259

260
    const std::size_t slash = base_path.find_last_of('/');
18✔
261
    if (slash == std::string::npos)
18!
262
    {
263
        return relative_path;
×
264
    }
265

266
    return base_path.substr(0, slash + 1) + relative_path;
18✔
267
}
268

269
struct parsed_uri
270
{
271
    bool absolute = false;
272
    bool has_authority = false;
273
    bool has_authentication = false;
274
    bool has_port = false;
275
    bool has_query = false;
276
    bool has_fragment = false;
277
    bool ipv6 = false;
278

279
    std::string scheme;
280
    std::string username;
281
    std::string password;
282
    std::string host;
283
    std::size_t port = 0;
284
    std::string query;
285
    std::string fragment;
286
    std::string path;
287
};
288

289
parsed_uri parse_uri_string(const std::string &uri_string)
6,376✔
290
{
291
    parsed_uri parsed;
6,376✔
292
    std::string work = uri_string;
6,376✔
293

294
    const std::size_t fragment_pos = work.find('#');
6,376✔
295
    if (fragment_pos != std::string::npos)
6,376✔
296
    {
297
        parsed.fragment = work.substr(fragment_pos + 1);
10✔
298
        parsed.has_fragment = true;
10✔
299
        work = work.substr(0, fragment_pos);
10✔
300
    }
301

302
    const std::size_t query_pos = work.find('?');
6,376✔
303
    if (query_pos != std::string::npos)
6,376✔
304
    {
305
        parsed.query = work.substr(query_pos + 1);
19✔
306
        parsed.has_query = true;
19✔
307
        work = work.substr(0, query_pos);
19✔
308
    }
309

310
    const std::size_t first_special = work.find_first_of("/?#");
6,376✔
311
    const std::string maybe_scheme = (first_special == std::string::npos) ? work : work.substr(0, first_special);
6,376✔
312

313
    std::size_t scheme_pos = std::string::npos;
6,376✔
314
    if (looks_like_scheme(maybe_scheme))
6,376✔
315
    {
316
        scheme_pos = maybe_scheme.find(':');
71✔
317
    }
318

319
    std::string rest = work;
6,376✔
320
    if (scheme_pos != std::string::npos)
6,376✔
321
    {
322
        parsed.scheme = work.substr(0, scheme_pos);
71✔
323
        parsed.absolute = true;
71✔
324
        rest = work.substr(scheme_pos + 1);
71✔
325
    }
326

327
    if (starts_with(rest, "//"))
6,376✔
328
    {
329
        parsed.has_authority = true;
64✔
330
        const std::size_t authority_begin = 2;
64✔
331
        const std::size_t authority_end = rest.find_first_of("/?", authority_begin);
64✔
332

333
        const std::string authority = rest.substr(
334
            authority_begin,
335
            authority_end == std::string::npos ? std::string::npos : authority_end - authority_begin);
64✔
336

337
        rest = (authority_end == std::string::npos) ? std::string() : rest.substr(authority_end);
64✔
338

339
        const parsed_authority auth = parse_authority(authority);
64✔
340
        parsed.ipv6 = auth.ipv6;
64✔
341
        parsed.has_authentication = auth.authentication;
64✔
342
        parsed.has_port = auth.port_present;
64✔
343
        parsed.username = auth.username;
64✔
344
        parsed.password = auth.password;
64✔
345
        parsed.host = auth.host;
64✔
346
        parsed.port = auth.port;
64✔
347
    }
64✔
348

349
    parsed.path = rest;
6,376✔
350
    return parsed;
6,376✔
351
}
6,376✔
352

353
std::string relative_path_from_base(const std::string &base_path, const std::string &target_path, bool base_has_authority)
2✔
354
{
355
    if (target_path == base_path)
2✔
356
    {
357
        return std::string();
1✔
358
    }
359

360
    std::string base_dir = base_path;
1✔
361
    if (base_dir.empty())
1!
362
    {
363
        if (base_has_authority)
×
364
        {
365
            base_dir = "/";
×
366
        }
367
    }
368
    else if (base_dir.back() != '/')
1!
369
    {
370
        const std::size_t slash = base_dir.find_last_of('/');
×
371
        if (slash != std::string::npos)
×
372
        {
373
            base_dir.erase(slash + 1);
×
374
        }
375
        else
376
        {
377
            base_dir.clear();
×
378
        }
379
    }
380

381
    auto split = [](const std::string &p)
2✔
382
    {
383
        std::vector<std::string> out;
2✔
384
        std::size_t start = 0;
2✔
385
        while (start <= p.size())
8!
386
        {
387
            std::size_t pos = p.find('/', start);
8✔
388
            if (pos == std::string::npos)
8✔
389
            {
390
                out.push_back(p.substr(start));
1✔
391
                break;
1✔
392
            }
393
            out.push_back(p.substr(start, pos - start));
7✔
394
            start = pos + 1;
7✔
395
            if (start == p.size())
7✔
396
            {
397
                out.push_back("");
1✔
398
                break;
1✔
399
            }
400
        }
401
        return out;
2✔
402
    };
×
403

404
    const std::vector<std::string> base_segments = split(base_dir);
1✔
405
    const std::vector<std::string> target_segments = split(target_path);
1✔
406

407
    std::size_t common = 0;
1✔
408
    while (common < base_segments.size() &&
8!
409
           common < target_segments.size() &&
8!
410
           base_segments[common] == target_segments[common])
4✔
411
    {
412
        ++common;
3✔
413
    }
414

415
    std::vector<std::string> result_segments;
1✔
416

417
    for (std::size_t i = common; i < base_segments.size(); ++i)
2✔
418
    {
419
        if (!base_segments[i].empty())
1!
420
        {
421
            result_segments.push_back("..");
×
422
        }
423
    }
424

425
    for (std::size_t i = common; i < target_segments.size(); ++i)
3✔
426
    {
427
        result_segments.push_back(target_segments[i]);
2✔
428
    }
429

430
    std::string result;
1✔
431
    for (std::size_t i = 0; i < result_segments.size(); ++i)
3✔
432
    {
433
        if (i != 0)
2✔
434
        {
435
            result.push_back('/');
1✔
436
        }
437
        result += result_segments[i];
2✔
438
    }
439

440
    return result;
1✔
441
}
1✔
442

443
std::string normalize_for_compare(const std::string &path)
11,764✔
444
{
445
    return remove_dot_segments(path);
11,764✔
446
}
447
} // namespace
448

449
uri::uri() = default;
7,792✔
450

451
uri::uri(const std::string &uri_string)
6,376✔
452
{
453
    const parsed_uri parsed = parse_uri_string(uri_string);
6,376✔
454

455
    absolute_ = parsed.absolute;
6,376✔
456
    has_authority_ = parsed.has_authority;
6,376✔
457
    ipv6_ = parsed.ipv6;
6,376✔
458
    has_authentication_ = parsed.has_authentication;
6,376✔
459
    has_port_ = parsed.has_port;
6,376✔
460
    has_query_ = parsed.has_query;
6,376✔
461
    has_fragment_ = parsed.has_fragment;
6,376✔
462

463
    scheme_ = parsed.scheme;
6,376✔
464
    username_ = parsed.username;
6,376✔
465
    password_ = parsed.password;
6,376✔
466
    host_ = parsed.host;
6,376✔
467
    port_ = parsed.port;
6,376✔
468
    query_ = parsed.query;
6,376✔
469
    fragment_ = parsed.fragment;
6,376✔
470
    path_ = xlnt::path(parsed.path);
6,376✔
471
}
6,376✔
472

473
uri::uri(const uri &base, const uri &relative)
25✔
474
{
475
    if (relative.absolute_)
25✔
476
    {
477
        *this = relative;
1✔
478
        return;
1✔
479
    }
480

481
    absolute_ = base.absolute_;
24✔
482
    scheme_ = base.scheme_;
24✔
483

484
    if (relative.has_authority_)
24✔
485
    {
486
        has_authority_ = true;
1✔
487
        has_authentication_ = relative.has_authentication_;
1✔
488
        has_port_ = relative.has_port_;
1✔
489
        username_ = relative.username_;
1✔
490
        password_ = relative.password_;
1✔
491
        host_ = relative.host_;
1✔
492
        port_ = relative.port_;
1✔
493
        path_ = xlnt::path(remove_dot_segments(relative.path_.string()));
1✔
494
        has_query_ = relative.has_query_;
1✔
495
        query_ = relative.query_;
1✔
496
    }
497
    else if (relative.path_.string().empty())
23✔
498
    {
499
        has_authority_ = base.has_authority_;
3✔
500
        has_authentication_ = base.has_authentication_;
3✔
501
        has_port_ = base.has_port_;
3✔
502
        username_ = base.username_;
3✔
503
        password_ = base.password_;
3✔
504
        host_ = base.host_;
3✔
505
        port_ = base.port_;
3✔
506
        path_ = base.path_;
3✔
507

508
        if (relative.has_query_)
3✔
509
        {
510
            has_query_ = true;
1✔
511
            query_ = relative.query_;
1✔
512
        }
513
        else
514
        {
515
            has_query_ = base.has_query_;
2✔
516
            query_ = base.query_;
2✔
517
        }
518
    }
519
    else
520
    {
521
        has_authority_ = base.has_authority_;
20✔
522
        has_authentication_ = base.has_authentication_;
20✔
523
        has_port_ = base.has_port_;
20✔
524
        username_ = base.username_;
20✔
525
        password_ = base.password_;
20✔
526
        host_ = base.host_;
20✔
527
        port_ = base.port_;
20✔
528

529
        const std::string rel_path = relative.path_.string();
20✔
530

531
        if (!rel_path.empty() && rel_path.front() == '/')
20!
532
        {
533
            path_ = xlnt::path(remove_dot_segments(rel_path));
2✔
534
        }
535
        else
536
        {
537
            const std::string base_path = base.path_.string();
18✔
538
            const std::string merged = merge_paths(base_path, rel_path, base.has_authority_);
18✔
539
            path_ = xlnt::path(remove_dot_segments(merged));
18✔
540
        }
18✔
541

542
        has_query_ = relative.has_query_;
20✔
543
        query_ = relative.query_;
20✔
544
    }
20✔
545

546
    ipv6_ = has_authority_ ? (relative.has_authority_ ? relative.ipv6_ : base.ipv6_) : false;
24!
547
    has_fragment_ = relative.has_fragment_;
24✔
548
    fragment_ = relative.fragment_;
24✔
549
}
×
550

551
uri::uri(const uri &base, const xlnt::path &relative)
1✔
552
{
553
    uri ref;
1✔
554
    ref.absolute_ = false;
1✔
555
    ref.has_authority_ = false;
1✔
556
    ref.path_ = relative;
1✔
557
    ref.ipv6_ = base.ipv6_;
1✔
558

559
    *this = uri(base, ref);
1✔
560
}
1✔
561

562
bool uri::is_relative() const
8✔
563
{
564
    return !absolute_;
8✔
565
}
566

567
bool uri::is_absolute() const
42✔
568
{
569
    return absolute_;
42✔
570
}
571

572
std::string uri::scheme() const
9✔
573
{
574
    return scheme_;
9✔
575
}
576

577
std::string uri::authority() const
142✔
578
{
579
    if (!has_authority_)
142✔
580
    {
581
        return std::string();
3✔
582
    }
583

584
    std::string result;
139✔
585

586
    if (has_authentication_)
139✔
587
    {
588
        result += username_;
7✔
589
        if (!password_.empty())
7✔
590
        {
591
            result += ':';
5✔
592
            result += password_;
5✔
593
        }
594
        result += '@';
7✔
595
    }
596

597
    if (ipv6_)
139✔
598
    {
599
        result += '[' + host_ + ']';
2✔
600
    }
601
    else
602
    {
603
        result += host_;
137✔
604
    }
605

606
    if (has_port_)
139✔
607
    {
608
        result += ':';
7✔
609
        result += std::to_string(port_);
7✔
610
    }
611

612
    return result;
139✔
613
}
139✔
614

615
bool uri::has_authentication() const
4✔
616
{
617
    return has_authentication_;
4✔
618
}
619

620
std::string uri::authentication() const
3✔
621
{
622
    if (!has_authentication_)
3✔
623
    {
624
        return std::string();
1✔
625
    }
626

627
    if (password_.empty())
2✔
628
    {
629
        return username_;
1✔
630
    }
631

632
    return username_ + ":" + password_;
2✔
633
}
634

635
std::string uri::username() const
3✔
636
{
637
    return username_;
3✔
638
}
639

640
std::string uri::password() const
3✔
641
{
642
    return password_;
3✔
643
}
644

645
std::string uri::host() const
8✔
646
{
647
    return host_;
8✔
648
}
649

650
bool uri::has_port() const
6✔
651
{
652
    return has_port_;
6✔
653
}
654

655
std::size_t uri::port() const
3✔
656
{
657
    return port_;
3✔
658
}
659

660
const class path &uri::path() const
13,629✔
661
{
662
    return path_;
13,629✔
663
}
664

665
bool uri::has_query() const
9✔
666
{
667
    return has_query_;
9✔
668
}
669

670
std::string uri::query() const
5✔
671
{
672
    return query_;
5✔
673
}
674

675
bool uri::has_fragment() const
9✔
676
{
677
    return has_fragment_;
9✔
678
}
679

680
std::string uri::fragment() const
5✔
681
{
682
    return fragment_;
5✔
683
}
684

685
std::string uri::to_string() const
888✔
686
{
687
    std::string result;
888✔
688

689
    if (!scheme_.empty())
888✔
690
    {
691
        result += scheme_;
158✔
692
        result += ':';
158✔
693
    }
694

695
    if (has_authority_)
888✔
696
    {
697
        result += "//";
132✔
698
        result += authority();
132✔
699
    }
700

701
    result += path_.string();
888✔
702

703
    if (has_query_)
888✔
704
    {
705
        result += '?';
40✔
706
        result += query_;
40✔
707
    }
708

709
    if (has_fragment_)
888✔
710
    {
711
        result += '#';
12✔
712
        result += fragment_;
12✔
713
    }
714

715
    return result;
888✔
716
}
×
717

718
uri uri::make_absolute(const uri &base)
24✔
719
{
720
    if (is_absolute())
24✔
721
    {
722
        return *this;
1✔
723
    }
724

725
    return uri(base, *this);
23✔
726
}
727

728
uri uri::make_reference(const uri &base)
4✔
729
{
730
    if (!is_absolute())
4✔
731
    {
732
        return *this;
1✔
733
    }
734

735
    if (lower_copy(scheme_) != lower_copy(base.scheme_) ||
9!
736
        has_authority_ != base.has_authority_ ||
3!
737
        has_authentication_ != base.has_authentication_ ||
3!
738
        has_port_ != base.has_port_ ||
3!
739
        lower_copy(host_) != lower_copy(base.host_) ||
6!
740
        username_ != base.username_ ||
2!
741
        password_ != base.password_ ||
14!
742
        port_ != base.port_)
2!
743
    {
744
        return *this;
1✔
745
    }
746

747
    uri result;
2✔
748
    result.absolute_ = false;
2✔
749
    result.has_authority_ = false;
2✔
750
    result.has_authentication_ = false;
2✔
751
    result.has_port_ = false;
2✔
752
    result.has_query_ = has_query_;
2✔
753
    result.query_ = query_;
2✔
754
    result.has_fragment_ = has_fragment_;
2✔
755
    result.fragment_ = fragment_;
2✔
756

757
    result.path_ = xlnt::path(relative_path_from_base(base.path_.string(), path_.string(), base.has_authority_));
2✔
758
    return result;
2✔
759
}
2✔
760

761
bool uri::has_authority() const
8✔
762
{
763
    return has_authority_;
8✔
764
}
765

766
bool uri::operator==(const uri &other) const
5,882✔
767
{
768
    return absolute_ == other.absolute_ &&
11,764✔
769
           has_authority_ == other.has_authority_ &&
5,882!
770
           has_authentication_ == other.has_authentication_ &&
5,882!
771
           has_port_ == other.has_port_ &&
5,882!
772
           has_query_ == other.has_query_ &&
5,882!
773
           has_fragment_ == other.has_fragment_ &&
11,764!
774
           lower_copy(scheme_) == lower_copy(other.scheme_) &&
17,646!
775
           username_ == other.username_ &&
11,764!
776
           password_ == other.password_ &&
11,764!
777
           lower_copy(host_) == lower_copy(other.host_) &&
11,764!
778
           port_ == other.port_ &&
11,764!
779
           query_ == other.query_ &&
11,764!
780
           fragment_ == other.fragment_ &&
17,646!
781
           normalize_for_compare(path_.string()) == normalize_for_compare(other.path_.string());
17,646!
782
}
783

784
bool uri::operator!=(const uri &other) const
2✔
785
{
786
    return !(*this == other);
2✔
787
}
788

789
} // namespace xlnt
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc