Coverage Report

Created: 2026-09-14 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poco/Foundation/src/Path.cpp
Line
Count
Source
1
//
2
// Path.cpp
3
//
4
// Library: Foundation
5
// Package: Filesystem
6
// Module:  Path
7
//
8
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9
// and Contributors.
10
//
11
// SPDX-License-Identifier: BSL-1.0
12
//
13
14
15
#include "Poco/Path.h"
16
#include "Poco/File.h"
17
#include "Poco/Exception.h"
18
#include "Poco/StringTokenizer.h"
19
#if defined(_WIN32)
20
#include "Poco/UnicodeConverter.h"
21
#include "Poco/Buffer.h"
22
#endif
23
#include <algorithm>
24
25
26
#if defined(POCO_OS_FAMILY_UNIX)
27
#include "Path_UNIX.cpp"
28
#elif defined(POCO_OS_FAMILY_WINDOWS)
29
#include "Path_WIN32U.cpp"
30
#endif
31
32
33
namespace Poco {
34
35
36
178k
Path::Path(): _absolute(false)
37
178k
{
38
178k
}
39
40
41
0
Path::Path(bool absolute): _absolute(absolute)
42
0
{
43
0
}
44
45
46
Path::Path(const std::string& path)
47
10.3k
{
48
10.3k
  assign(path);
49
10.3k
}
50
51
52
Path::Path(const std::string& path, Style style)
53
35.6k
{
54
35.6k
  assign(path, style);
55
35.6k
}
56
57
58
Path::Path(const char* path)
59
0
{
60
0
  poco_check_ptr(path);
61
0
  assign(path);
62
0
}
63
64
65
Path::Path(const char* path, Style style)
66
0
{
67
0
  poco_check_ptr(path);
68
0
  assign(path, style);
69
0
}
70
71
72
Path::Path(const Path& path):
73
5.56k
  _node(path._node),
74
5.56k
  _device(path._device),
75
5.56k
  _name(path._name),
76
5.56k
  _version(path._version),
77
5.56k
  _dirs(path._dirs),
78
5.56k
  _absolute(path._absolute)
79
5.56k
{
80
5.56k
}
81
82
83
Path::Path(Path&& path) noexcept:
84
0
  _node(std::move(path._node)),
85
0
  _device(std::move(path._device)),
86
0
  _name(std::move(path._name)),
87
0
  _version(std::move(path._version)),
88
0
  _dirs(std::move(path._dirs)),
89
0
  _absolute(std::move(path._absolute))
90
0
{
91
0
}
92
93
94
Path::Path(const Path& parent, const std::string& fileName):
95
0
  _node(parent._node),
96
0
  _device(parent._device),
97
0
  _name(parent._name),
98
0
  _version(parent._version),
99
0
  _dirs(parent._dirs),
100
0
  _absolute(parent._absolute)
101
0
{
102
0
  makeDirectory();
103
0
  _name = fileName;
104
0
}
105
106
107
Path::Path(const Path& parent, const char* fileName):
108
0
  _node(parent._node),
109
0
  _device(parent._device),
110
0
  _name(parent._name),
111
0
  _version(parent._version),
112
0
  _dirs(parent._dirs),
113
0
  _absolute(parent._absolute)
114
0
{
115
0
  makeDirectory();
116
0
  _name = fileName;
117
0
}
118
119
120
Path::Path(const Path& parent, const Path& relative):
121
2.90k
  _node(parent._node),
122
2.90k
  _device(parent._device),
123
2.90k
  _name(parent._name),
124
2.90k
  _version(parent._version),
125
2.90k
  _dirs(parent._dirs),
126
2.90k
  _absolute(parent._absolute)
127
2.90k
{
128
2.90k
  resolve(relative);
129
2.90k
}
130
131
132
Path::~Path()
133
232k
{
134
232k
}
135
136
137
Path& Path::operator = (const Path& path)
138
0
{
139
0
  return assign(path);
140
0
}
141
142
143
Path& Path::operator = (Path&& path) noexcept
144
0
{
145
0
  _node     = std::move(path._node);
146
0
  _device   = std::move(path._device);
147
0
  _name     = std::move(path._name);
148
0
  _version  = std::move(path._version);
149
0
  _dirs     = std::move(path._dirs);
150
0
  _absolute = std::move(path._absolute);
151
0
  return *this;
152
0
}
153
154
155
Path& Path::operator = (const std::string& path)
156
0
{
157
0
  return assign(path);
158
0
}
159
160
161
Path& Path::operator = (const char* path)
162
0
{
163
0
  poco_check_ptr(path);
164
0
  return assign(path);
165
0
}
166
167
168
void Path::swap(Path& path) noexcept
169
0
{
170
0
  std::swap(_node, path._node);
171
0
  std::swap(_device, path._device);
172
0
  std::swap(_name, path._name);
173
0
  std::swap(_version, path._version);
174
0
  std::swap(_dirs, path._dirs);
175
0
  std::swap(_absolute, path._absolute);
176
0
}
177
178
179
Path& Path::assign(const Path& path)
180
88.8k
{
181
88.8k
  if (&path != this)
182
88.8k
  {
183
88.8k
    _node     = path._node;
184
88.8k
    _device   = path._device;
185
88.8k
    _name     = path._name;
186
88.8k
    _version  = path._version;
187
88.8k
    _dirs     = path._dirs;
188
88.8k
    _absolute = path._absolute;
189
88.8k
  }
190
88.8k
  return *this;
191
88.8k
}
192
193
194
Path& Path::assign(const std::string& path)
195
13.2k
{
196
#if defined(POCO_OS_FAMILY_WINDOWS)
197
  parseWindows(path);
198
#else
199
13.2k
  parseUnix(path);
200
13.2k
#endif
201
13.2k
  return *this;
202
13.2k
}
203
204
205
Path& Path::assign(const std::string& path, Style style)
206
124k
{
207
124k
  switch (style)
208
124k
  {
209
37.2k
  case PATH_UNIX:
210
37.2k
    parseUnix(path);
211
37.2k
    break;
212
204
  case PATH_WINDOWS:
213
204
    parseWindows(path);
214
204
    break;
215
615
  case PATH_VMS:
216
615
    parseVMS(path);
217
615
    break;
218
57
  case PATH_NATIVE:
219
57
    assign(path);
220
57
    break;
221
86.7k
  case PATH_GUESS:
222
86.7k
    parseGuess(path);
223
86.7k
    break;
224
0
  default:
225
0
    poco_bugcheck();
226
124k
  }
227
123k
  return *this;
228
124k
}
229
230
231
Path& Path::assign(const char* path)
232
0
{
233
0
  return assign(std::string(path));
234
0
}
235
236
237
std::string Path::toString() const
238
243k
{
239
#if defined(POCO_OS_FAMILY_WINDOWS)
240
  return buildWindows();
241
#else
242
243k
  return buildUnix();
243
243k
#endif
244
243k
}
245
246
247
std::string Path::toString(Style style) const
248
2.90k
{
249
2.90k
  switch (style)
250
2.90k
  {
251
1.27k
  case PATH_UNIX:
252
1.27k
    return buildUnix();
253
489
  case PATH_WINDOWS:
254
489
    return buildWindows();
255
837
  case PATH_VMS:
256
837
    return buildVMS();
257
207
  case PATH_NATIVE:
258
301
  case PATH_GUESS:
259
301
    return toString();
260
0
  default:
261
0
    poco_bugcheck();
262
2.90k
  }
263
0
  return std::string();
264
2.90k
}
265
266
267
bool Path::tryParse(const std::string& path)
268
2.90k
{
269
2.90k
  try
270
2.90k
  {
271
2.90k
    Path p;
272
2.90k
    p.parse(path);
273
2.90k
    assign(p);
274
2.90k
    return true;
275
2.90k
  }
276
2.90k
  catch (...)
277
2.90k
  {
278
0
    return false;
279
0
  }
280
2.90k
}
281
282
283
bool Path::tryParse(const std::string& path, Style style)
284
86.3k
{
285
86.3k
  try
286
86.3k
  {
287
86.3k
    Path p;
288
86.3k
    p.parse(path, style);
289
86.3k
    assign(p);
290
86.3k
    return true;
291
86.3k
  }
292
86.3k
  catch (...)
293
86.3k
  {
294
564
    return false;
295
564
  }
296
86.3k
}
297
298
299
Path& Path::parseDirectory(const std::string& path)
300
0
{
301
0
  assign(addDirectorySeparator(path));
302
0
  return makeDirectory();
303
0
}
304
305
306
Path& Path::parseDirectory(const std::string& path, Style style)
307
0
{
308
0
  assign(addDirectorySeparator(path, style), style);
309
0
  return makeDirectory();
310
0
}
311
312
313
Path& Path::makeDirectory()
314
2.68k
{
315
2.68k
  pushDirectory(_name);
316
2.68k
  _name.clear();
317
2.68k
  _version.clear();
318
2.68k
  return *this;
319
2.68k
}
320
321
322
Path& Path::makeFile()
323
0
{
324
0
  if (!_dirs.empty() && _name.empty())
325
0
  {
326
0
    _name = _dirs.back();
327
0
    _dirs.pop_back();
328
0
  }
329
0
  return *this;
330
0
}
331
332
333
Path& Path::makeAbsolute()
334
2.66k
{
335
2.66k
  return makeAbsolute(current());
336
2.66k
}
337
338
339
Path& Path::makeAbsolute(const Path& base)
340
2.66k
{
341
2.66k
  if (!_absolute)
342
2.66k
  {
343
2.66k
    Path tmp = base;
344
2.66k
    tmp.makeDirectory();
345
2.66k
    for (const auto& d: _dirs)
346
2.82M
    {
347
2.82M
      tmp.pushDirectory(d);
348
2.82M
    }
349
2.66k
    _node     = tmp._node;
350
2.66k
    _device   = tmp._device;
351
2.66k
    _dirs     = tmp._dirs;
352
2.66k
    _absolute = base._absolute;
353
2.66k
  }
354
2.66k
  return *this;
355
2.66k
}
356
357
358
Path Path::absolute() const
359
2.90k
{
360
2.90k
  Path result(*this);
361
2.90k
  if (!result._absolute)
362
2.66k
  {
363
2.66k
    result.makeAbsolute();
364
2.66k
  }
365
2.90k
  return result;
366
2.90k
}
367
368
369
Path Path::absolute(const Path& base) const
370
0
{
371
0
  Path result(*this);
372
0
  if (!result._absolute)
373
0
  {
374
0
    result.makeAbsolute(base);
375
0
  }
376
0
  return result;
377
0
}
378
379
380
Path Path::parent() const
381
0
{
382
0
  Path p(*this);
383
0
  return p.makeParent();
384
0
}
385
386
387
Path& Path::makeParent()
388
0
{
389
0
  if (_name.empty())
390
0
  {
391
0
    if (_dirs.empty())
392
0
    {
393
0
      if (!_absolute)
394
0
        _dirs.push_back("..");
395
0
    }
396
0
    else
397
0
    {
398
0
      if (_dirs.back() == "..")
399
0
        _dirs.push_back("..");
400
0
      else
401
0
        _dirs.pop_back();
402
0
    }
403
0
  }
404
0
  else
405
0
  {
406
0
    _name.clear();
407
0
    _version.clear();
408
0
  }
409
0
  return *this;
410
0
}
411
412
413
Path& Path::append(const Path& path)
414
0
{
415
0
  makeDirectory();
416
0
  _dirs.insert(_dirs.end(), path._dirs.begin(), path._dirs.end());
417
0
  _name = path._name;
418
0
  _version = path._version;
419
0
  return *this;
420
0
}
421
422
423
Path& Path::resolve(const Path& path)
424
2.90k
{
425
2.90k
  if (path.isAbsolute())
426
153
  {
427
153
    assign(path);
428
153
  }
429
2.74k
  else
430
2.74k
  {
431
539k
    for (int i = 0; i < path.depth(); ++i)
432
536k
      pushDirectory(path[i]);
433
2.74k
    _name = path._name;
434
2.74k
  }
435
2.90k
  return *this;
436
2.90k
}
437
438
439
Path& Path::setNode(const std::string& node)
440
35.6k
{
441
35.6k
  _node     = node;
442
35.6k
  _absolute = _absolute || !node.empty();
443
35.6k
  return *this;
444
35.6k
}
445
446
447
Path& Path::setDevice(const std::string& device)
448
0
{
449
0
  _device   = device;
450
0
  _absolute = _absolute || !device.empty();
451
0
  return *this;
452
0
}
453
454
455
const std::string& Path::directory(int n) const
456
0
{
457
0
  poco_assert (0 <= n && static_cast<std::size_t>(n) <= _dirs.size());
458
459
0
  if (static_cast<std::size_t>(n) < _dirs.size())
460
0
    return _dirs[n];
461
0
  else
462
0
    return _name;
463
0
}
464
465
466
const std::string& Path::operator [] (int n) const
467
536k
{
468
536k
  poco_assert (0 <= n && static_cast<std::size_t>(n) <= _dirs.size());
469
470
536k
  if (static_cast<std::size_t>(n) < _dirs.size())
471
536k
    return _dirs[n];
472
0
  else
473
0
    return _name;
474
536k
}
475
476
477
Path& Path::pushDirectory(const std::string& dir)
478
348M
{
479
348M
  if (!dir.empty() && dir != ".")
480
348M
  {
481
348M
    if (dir == "..")
482
857k
    {
483
857k
      if (!_dirs.empty() && _dirs.back() != "..")
484
21.5k
        _dirs.pop_back();
485
835k
      else if (!_absolute)
486
643k
        _dirs.push_back(dir);
487
857k
    }
488
347M
    else _dirs.push_back(dir);
489
348M
  }
490
348M
  return *this;
491
348M
}
492
493
494
Path& Path::popDirectory()
495
0
{
496
0
  poco_assert (!_dirs.empty());
497
498
0
  _dirs.pop_back();
499
0
  return *this;
500
0
}
501
502
503
Path& Path::popFrontDirectory()
504
0
{
505
0
  poco_assert (!_dirs.empty());
506
507
0
  StringVec::iterator it = _dirs.begin();
508
0
  _dirs.erase(it);
509
0
  return *this;
510
0
}
511
512
513
Path& Path::setFileName(const std::string& name)
514
0
{
515
0
  _name = name;
516
0
  return *this;
517
0
}
518
519
520
Path& Path::setBaseName(const std::string& name)
521
0
{
522
0
  std::string ext = getExtension();
523
0
  _name = name;
524
0
  if (!ext.empty())
525
0
  {
526
0
    _name.append(".");
527
0
    _name.append(ext);
528
0
  }
529
0
  return *this;
530
0
}
531
532
533
std::string Path::getBaseName() const
534
0
{
535
0
  std::string::size_type pos = _name.rfind('.');
536
0
  if (pos != std::string::npos && pos != 0)
537
0
    return _name.substr(0, pos);
538
0
  else
539
0
    return _name;
540
0
}
541
542
543
Path& Path::setExtension(const std::string& extension)
544
0
{
545
0
  _name = getBaseName();
546
0
  if (!extension.empty())
547
0
  {
548
0
    _name.append(".");
549
0
    _name.append(extension);
550
0
  }
551
0
  return *this;
552
0
}
553
554
555
std::string Path::getExtension() const
556
0
{
557
0
  std::string::size_type pos = _name.rfind('.');
558
0
  if (pos != std::string::npos && pos != 0)
559
0
    return _name.substr(pos + 1);
560
0
  else
561
0
    return std::string();
562
0
}
563
564
565
Path& Path::clear()
566
138k
{
567
138k
  _node.clear();
568
138k
  _device.clear();
569
138k
  _name.clear();
570
138k
  _dirs.clear();
571
138k
  _version.clear();
572
138k
  _absolute = false;
573
138k
  return *this;
574
138k
}
575
576
577
std::string Path::addDirectorySeparator(const std::string& path)
578
0
{
579
0
  poco_assert(!path.empty());
580
581
0
  if (path.back() != separator())
582
0
  {
583
0
    return path + separator();
584
0
  }
585
0
  return path;
586
0
}
587
588
589
std::string Path::addDirectorySeparator(const std::string& path, Style style)
590
0
{
591
0
  poco_assert(!path.empty());
592
593
0
  char ch = '\0';
594
0
  switch (style)
595
0
  {
596
0
  case PATH_UNIX:
597
0
    ch = '/';
598
0
    break;
599
0
  case PATH_WINDOWS:
600
0
    ch = '\\';
601
0
    break;
602
0
  case PATH_VMS:
603
0
    ch = '.';
604
0
    break;
605
0
  case PATH_NATIVE:
606
0
    ch = separator();
607
0
    break;
608
0
  default:
609
0
    poco_bugcheck();
610
0
  }
611
612
0
  if (path.back() != ch)
613
0
  {
614
0
    return path + ch;
615
0
  }
616
0
  return path;
617
0
}
618
619
620
std::string Path::self()
621
0
{
622
0
  return PathImpl::selfImpl();
623
0
}
624
625
626
std::string Path::current()
627
2.66k
{
628
2.66k
  return PathImpl::currentImpl();
629
2.66k
}
630
631
632
std::string Path::home()
633
1.86k
{
634
1.86k
  return PathImpl::homeImpl();
635
1.86k
}
636
637
638
std::string Path::configHome()
639
0
{
640
0
#if defined(POCO_OS_FAMILY_UNIX) || defined(POCO_OS_FAMILY_WINDOWS)
641
0
  return PathImpl::configHomeImpl();
642
#else
643
  return PathImpl::homeImpl();
644
#endif
645
0
}
646
647
648
std::string Path::dataHome()
649
0
{
650
0
#if defined(POCO_OS_FAMILY_UNIX) || defined(POCO_OS_FAMILY_WINDOWS)
651
0
  return PathImpl::dataHomeImpl();
652
#else
653
  return PathImpl::homeImpl();
654
#endif
655
0
}
656
657
658
std::string Path::tempHome()
659
0
{
660
0
#if defined(POCO_OS_FAMILY_UNIX) || defined(POCO_OS_FAMILY_WINDOWS)
661
0
  return PathImpl::tempHomeImpl();
662
#else
663
  return PathImpl::tempImpl();
664
#endif
665
0
}
666
667
668
std::string Path::cacheHome()
669
0
{
670
0
#if defined(POCO_OS_FAMILY_UNIX) || defined(POCO_OS_FAMILY_WINDOWS)
671
0
  return PathImpl::cacheHomeImpl();
672
#else
673
  return PathImpl::homeImpl();
674
#endif
675
0
}
676
677
678
std::string Path::temp()
679
0
{
680
0
  return PathImpl::tempImpl();
681
0
}
682
683
684
std::string Path::config()
685
0
{
686
0
#if defined(POCO_OS_FAMILY_UNIX) || defined(POCO_OS_FAMILY_WINDOWS)
687
0
  return PathImpl::configImpl();
688
#else
689
  return PathImpl::currentImpl();
690
#endif
691
0
}
692
693
694
std::string Path::null()
695
0
{
696
0
  return PathImpl::nullImpl();
697
0
}
698
699
700
std::string Path::expand(const std::string& path)
701
2.90k
{
702
2.90k
  return PathImpl::expandImpl(path);
703
2.90k
}
704
705
706
void Path::listRoots(std::vector<std::string>& roots)
707
0
{
708
0
  PathImpl::listRootsImpl(roots);
709
0
}
710
711
712
bool Path::find(StringVec::const_iterator it, StringVec::const_iterator end, const std::string& name, Path& path)
713
0
{
714
0
  while (it != end)
715
0
  {
716
#if defined(WIN32)
717
    std::string cleanPath(*it);
718
    if (cleanPath.size() > 1 && cleanPath[0] == '"' && cleanPath[cleanPath.size() - 1] == '"')
719
    {
720
      cleanPath = cleanPath.substr(1, cleanPath.size() - 2);
721
    }
722
    Path p(cleanPath);
723
#else
724
0
    Path p(*it);
725
0
#endif
726
0
    p.makeDirectory();
727
0
    p.resolve(Path(name));
728
0
    File f(p);
729
0
    if (f.exists())
730
0
    {
731
0
      path = p;
732
0
      return true;
733
0
    }
734
0
    ++it;
735
0
  }
736
0
  return false;
737
0
}
738
739
740
bool Path::find(const std::string& pathList, const std::string& name, Path& path)
741
0
{
742
0
  StringTokenizer st(pathList, std::string(1, pathSeparator()), StringTokenizer::TOK_IGNORE_EMPTY + StringTokenizer::TOK_TRIM);
743
0
  return find(st.begin(), st.end(), name, path);
744
0
}
745
746
747
void Path::parseUnix(const std::string& path)
748
82.4k
{
749
82.4k
  clear();
750
751
82.4k
  std::string::const_iterator it  = path.begin();
752
82.4k
  std::string::const_iterator end = path.end();
753
754
82.4k
  if (it != end)
755
65.1k
  {
756
65.1k
    if (*it == '/')
757
44.2k
    {
758
44.2k
      _absolute = true; ++it;
759
44.2k
    }
760
20.9k
    else if (*it == '~')
761
2.26k
    {
762
2.26k
      ++it;
763
2.26k
      if (it == end || *it == '/')
764
1.86k
      {
765
1.86k
        Path cwd(home());
766
1.86k
        _dirs = cwd._dirs;
767
1.86k
        _absolute = true;
768
1.86k
      }
769
405
      else --it;
770
2.26k
    }
771
772
324M
    while (it != end)
773
324M
    {
774
324M
      std::string name;
775
2.54G
      while (it != end && *it != '/') name += *it++;
776
324M
      if (it != end)
777
324M
      {
778
324M
        if (_dirs.empty())
779
167k
        {
780
167k
          if (!name.empty() && *(name.rbegin()) == ':')
781
40.8k
          {
782
40.8k
            _absolute = true;
783
40.8k
            _device.assign(name, 0, name.length() - 1);
784
40.8k
          }
785
126k
          else
786
126k
          {
787
126k
            pushDirectory(name);
788
126k
          }
789
167k
        }
790
323M
        else pushDirectory(name);
791
324M
      }
792
26.6k
      else _name = name;
793
324M
      if (it != end) ++it;
794
324M
    }
795
65.1k
  }
796
82.4k
}
797
798
799
void Path::parseWindows(const std::string& path)
800
6.08k
{
801
6.08k
  clear();
802
803
6.08k
  std::string::const_iterator it  = path.begin();
804
6.08k
  std::string::const_iterator end = path.end();
805
806
6.08k
  if (it != end)
807
6.07k
  {
808
6.07k
    if (*it == '\\' || *it == '/') { _absolute = true; ++it; }
809
6.07k
    if (_absolute && it != end && (*it == '\\' || *it == '/')) // UNC
810
2.10k
    {
811
2.10k
      ++it;
812
135k
      while (it != end && *it != '\\' && *it != '/') _node += *it++;
813
2.10k
      if (it != end) ++it;
814
2.10k
    }
815
3.96k
    else if (it != end)
816
3.96k
    {
817
3.96k
      char d = *it++;
818
3.96k
      if (it != end && *it == ':') // drive letter
819
171
      {
820
171
        if (_absolute || !((d >= 'a' && d <= 'z') || (d >= 'A' && d <= 'Z'))) throw PathSyntaxException(path);
821
100
        _absolute = true;
822
100
        _device += d;
823
100
        ++it;
824
100
        if (it != end)
825
96
        {
826
96
          if ((*it != '\\' && *it != '/'))
827
16
          {
828
16
            throw PathSyntaxException(path);
829
16
          }
830
80
          ++it;
831
80
        }
832
100
      }
833
3.79k
      else --it;
834
3.96k
    }
835
21.0M
    while (it != end)
836
21.0M
    {
837
21.0M
      std::string name;
838
511M
      while (it != end && *it != '\\' && *it != '/') name += *it++;
839
21.0M
      if (it != end)
840
21.0M
        pushDirectory(name);
841
2.94k
      else
842
2.94k
        _name = name;
843
21.0M
      if (it != end) ++it;
844
21.0M
    }
845
5.99k
  }
846
5.99k
  if (!_node.empty() && _dirs.empty() && !_name.empty())
847
23
    makeDirectory();
848
5.99k
}
849
850
851
void Path::parseVMS(const std::string& path)
852
49.5k
{
853
49.5k
  clear();
854
855
49.5k
  std::string::const_iterator it  = path.begin();
856
49.5k
  std::string::const_iterator end = path.end();
857
858
49.5k
  if (it != end)
859
49.5k
  {
860
49.5k
    std::string name;
861
90.3M
    while (it != end && *it != ':' && *it != '[' && *it != ';') name += *it++;
862
49.5k
    if (it != end)
863
49.4k
    {
864
49.4k
      if (*it == ':')
865
12.7k
      {
866
12.7k
        ++it;
867
12.7k
        if (it != end && *it == ':')
868
12.1k
        {
869
12.1k
          _node = name;
870
12.1k
          ++it;
871
12.1k
        }
872
662
        else _device = name;
873
12.7k
        _absolute = true;
874
12.7k
        name.clear();
875
12.7k
      }
876
49.4k
      if (it != end)
877
49.4k
      {
878
49.4k
        if (_device.empty() && *it != '[')
879
44.9k
        {
880
13.2M
          while (it != end && *it != ':' && *it != ';') name += *it++;
881
44.9k
          if (it != end)
882
44.8k
          {
883
44.8k
            if (*it == ':')
884
905
            {
885
905
              _device = name;
886
905
              _absolute = true;
887
905
              name.clear();
888
905
              ++it;
889
905
            }
890
44.8k
          }
891
44.9k
        }
892
49.4k
      }
893
49.4k
      if (name.empty())
894
5.47k
      {
895
5.47k
        if (it != end && *it == '[')
896
4.81k
        {
897
4.81k
          ++it;
898
4.81k
          if (it != end)
899
4.37k
          {
900
4.37k
            _absolute = true;
901
4.37k
            if (*it == '.')
902
381
              { _absolute = false; ++it; }
903
3.99k
            else if (*it == ']' || *it == '-')
904
1.13k
              _absolute = false;
905
11.6M
            while (it != end && *it != ']')
906
11.6M
            {
907
11.6M
              name.clear();
908
11.6M
              if (*it == '-')
909
9.12M
                name = "-";
910
2.56M
              else
911
216M
                while (it != end && *it != '.' && *it != ']') name += *it++;
912
11.6M
              if (!name.empty())
913
11.5M
              {
914
11.5M
                if (name == "-")
915
9.12M
                {
916
9.12M
                  if (_dirs.empty() || _dirs.back() == "..")
917
9.00M
                    _dirs.push_back("..");
918
120k
                  else
919
120k
                    _dirs.pop_back();
920
9.12M
                }
921
2.44M
                else _dirs.push_back(name);
922
11.5M
              }
923
11.6M
              if (it != end && *it != ']') ++it;
924
11.6M
            }
925
4.37k
            if (it == end) throw PathSyntaxException(path);
926
3.88k
            ++it;
927
3.88k
            if (it != end && *it == '[')
928
1.54k
            {
929
1.54k
              if (!_absolute) throw PathSyntaxException(path);
930
1.50k
              ++it;
931
1.50k
              if (it != end && *it == '.') throw PathSyntaxException(path);
932
1.48k
              auto d = _dirs.size();
933
46.1M
              while (it != end && *it != ']')
934
46.1M
              {
935
46.1M
                name.clear();
936
46.1M
                if (*it == '-')
937
5.72k
                  name = "-";
938
46.1M
                else
939
424M
                  while (it != end && *it != '.' && *it != ']') name += *it++;
940
46.1M
                if (!name.empty())
941
46.1M
                {
942
46.1M
                  if (name == "-")
943
5.72k
                  {
944
5.72k
                    if (_dirs.size() > d)
945
2.20k
                      _dirs.pop_back();
946
5.72k
                  }
947
46.0M
                  else _dirs.push_back(name);
948
46.1M
                }
949
46.1M
                if (it != end && *it != ']') ++it;
950
46.1M
              }
951
1.48k
              if (it == end) throw PathSyntaxException(path);
952
1.12k
              ++it;
953
1.12k
            }
954
3.88k
          }
955
3.91k
          _name.clear();
956
3.91k
        }
957
9.06M
        while (it != end && *it != ';') _name += *it++;
958
4.56k
      }
959
43.9k
      else _name = name;
960
48.5k
      if (it != end && *it == ';')
961
45.3k
      {
962
45.3k
        ++it;
963
5.68M
        while (it != end) _version += *it++;
964
45.3k
      }
965
48.5k
    }
966
70
    else _name = name;
967
49.5k
  }
968
49.5k
}
969
970
971
void Path::parseGuess(const std::string& path)
972
86.7k
{
973
86.7k
  bool hasBackslash   = false;
974
86.7k
  bool hasSlash       = false;
975
86.7k
  bool hasOpenBracket = false;
976
86.7k
  bool hasClosBracket = false;
977
86.7k
  bool isWindows      = path.length() > 2 && path[1] == ':' && (path[2] == '/' || path[2] == '\\');
978
86.7k
  std::string::const_iterator end    = path.end();
979
86.7k
  std::string::const_iterator semiIt = end;
980
86.7k
  if (!isWindows)
981
86.3k
  {
982
970M
    for (std::string::const_iterator it = path.begin(); it != end; ++it)
983
970M
    {
984
970M
      switch (*it)
985
970M
      {
986
17.2M
      case '\\': hasBackslash = true; break;
987
6.75M
      case '/':  hasSlash = true; break;
988
29.1k
      case '[':  hasOpenBracket = true;
989
29.1k
        [[fallthrough]];
990
59.3k
      case ']':  hasClosBracket = hasOpenBracket;
991
59.3k
        [[fallthrough]];
992
213k
      case ';':  semiIt = it; break;
993
970M
      }
994
970M
    }
995
86.3k
  }
996
86.7k
  if (hasBackslash || isWindows)
997
5.87k
  {
998
5.87k
    parseWindows(path);
999
5.87k
  }
1000
80.8k
  else if (hasSlash)
1001
29.8k
  {
1002
29.8k
    parseUnix(path);
1003
29.8k
  }
1004
51.0k
  else
1005
51.0k
  {
1006
51.0k
    bool isVMS = hasClosBracket;
1007
51.0k
    if (!isVMS && semiIt != end)
1008
36.9k
    {
1009
36.9k
      isVMS = true;
1010
36.9k
      ++semiIt;
1011
66.6k
      while (semiIt != end)
1012
29.7k
      {
1013
29.7k
        if (*semiIt < '0' || *semiIt > '9')
1014
43
        {
1015
43
          isVMS = false; break;
1016
43
        }
1017
29.7k
        ++semiIt;
1018
29.7k
      }
1019
36.9k
    }
1020
51.0k
    if (isVMS)
1021
48.9k
      parseVMS(path);
1022
2.14k
    else
1023
2.14k
      parseUnix(path);
1024
51.0k
  }
1025
86.7k
}
1026
1027
1028
std::string Path::buildUnix() const
1029
244k
{
1030
244k
  std::string result;
1031
244k
  if (!_device.empty())
1032
2.46k
  {
1033
2.46k
    result.append("/");
1034
2.46k
    result.append(_device);
1035
2.46k
    result.append(":/");
1036
2.46k
  }
1037
241k
  else if (_absolute)
1038
157k
  {
1039
157k
    result.append("/");
1040
157k
  }
1041
244k
  for (const auto& d: _dirs)
1042
66.2M
  {
1043
66.2M
    result.append(d);
1044
66.2M
    result.append("/");
1045
66.2M
  }
1046
244k
  result.append(_name);
1047
244k
  return result;
1048
244k
}
1049
1050
1051
std::string Path::buildWindows() const
1052
489
{
1053
489
  std::string result;
1054
489
  if (!_node.empty())
1055
0
  {
1056
0
    result.append("\\\\");
1057
0
    result.append(_node);
1058
0
    result.append("\\");
1059
0
  }
1060
489
  else if (!_device.empty())
1061
52
  {
1062
52
    result.append(_device);
1063
52
    result.append(":\\");
1064
52
  }
1065
437
  else if (_absolute)
1066
74
  {
1067
74
    result.append("\\");
1068
74
  }
1069
489
  for (const auto& d: _dirs)
1070
108M
  {
1071
108M
    result.append(d);
1072
108M
    result.append("\\");
1073
108M
  }
1074
489
  result.append(_name);
1075
489
  return result;
1076
489
}
1077
1078
1079
std::string Path::buildVMS() const
1080
837
{
1081
837
  std::string result;
1082
837
  if (!_node.empty())
1083
0
  {
1084
0
    result.append(_node);
1085
0
    result.append("::");
1086
0
  }
1087
837
  if (!_device.empty())
1088
120
  {
1089
120
    result.append(_device);
1090
120
    result.append(":");
1091
120
  }
1092
837
  if (!_dirs.empty())
1093
734
  {
1094
734
    result.append("[");
1095
734
    if (!_absolute && _dirs[0] != "..")
1096
356
      result.append(".");
1097
133M
    for (StringVec::const_iterator it = _dirs.begin(); it != _dirs.end(); ++it)
1098
133M
    {
1099
133M
      if (it != _dirs.begin() && *it != "..")
1100
133M
        result.append(".");
1101
133M
      if (*it == "..")
1102
488k
        result.append("-");
1103
133M
      else
1104
133M
        result.append(*it);
1105
133M
    }
1106
734
    result.append("]");
1107
734
  }
1108
837
  result.append(_name);
1109
837
  if (!_version.empty())
1110
0
  {
1111
0
    result.append(";");
1112
0
    result.append(_version);
1113
0
  }
1114
837
  return result;
1115
837
}
1116
1117
1118
std::string Path::transcode(const std::string& path)
1119
0
{
1120
#if defined(_WIN32)
1121
  std::wstring uniPath;
1122
  UnicodeConverter::toUTF16(path, uniPath);
1123
  DWORD len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, uniPath.c_str(), static_cast<int>(uniPath.length()), nullptr, 0, nullptr, nullptr);
1124
  if (len > 0)
1125
  {
1126
    Buffer<char> buffer(len);
1127
    DWORD rc = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, uniPath.c_str(), static_cast<int>(uniPath.length()), buffer.begin(), static_cast<int>(buffer.size()), nullptr, nullptr);
1128
    if (rc)
1129
    {
1130
      return std::string(buffer.begin(), buffer.size());
1131
    }
1132
  }
1133
#endif
1134
0
  return path;
1135
0
}
1136
1137
1138
} // namespace Poco