1 /**
2     Path buffers
3 
4     Contains helpers for constructing paths in a type-safe way.
5 
6     Copyright:
7         Copyright © 2023-2025, Kitsunebi Games
8         Copyright © 2023-2025, Inochi2D Project
9     
10     License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
11     Authors:   Luna Nielsen
12 */
13 module nulib.uri;
14 import nulib.collections;
15 import nulib.string;
16 import nulib.text.ascii;
17 import numem;
18 
19 /**
20     The path seperator of the system.
21 */
22 version(Windows) enum NU_PATHSEP = '\\';
23 else enum NU_PATHSEP = '/';
24 
25 /**
26     PathBufs allows for type-safe path passing to 
27     nulib APIs.
28 */
29 struct URI {
30 @nogc nothrow:
31 private:
32     nstring store;
33 
34     // Slices into store
35     string scheme_;
36     string authority_;
37     string path_;
38     string query_;
39     string fragment_;
40 
41     void parse(string url) {
42         store.clear();
43 
44         // Local paths.
45         if (isLocalPath(url)) {
46             store = nstring(url);
47             path_ = store;
48             return;
49         }
50     }
51 
52     bool isPathSep(char c) {
53         return c == '/' || c == NU_PATHSEP;
54     }
55 
56     bool isLocalPath(string path) {
57 
58         //  NOTE:   The Windows/DOS path scheme uses a drive letter as a scheme,
59         //          followed by any of the path seperators.
60         version(Windows) {
61             if (path.length >= 3) {
62                 return 
63                     isAlpha(path[0]) &&
64                     path[1] == ':' && 
65                     isPathSep(path[2]);
66             }
67 
68             //  NOTE: Windows denotes SMB shares with \\, these are NOT local.
69             if (path.length > 2) {
70                 if (path[0..2] == "\\\\")
71                     return false;
72             }
73         }
74 
75         size_t i;
76         while (i++ < path.length) {
77             char c = path[i];
78 
79             if (c == ':' && i > 1)
80                 return false;
81 
82             if (c == NU_PATHSEP)
83                 return true;
84         }
85 
86         return false;
87     }
88 public:
89     @disable this();
90 
91     ~this() {
92         store.clear();
93     }
94 
95     /**
96         Creates a URI from a string.
97     */
98     this(string url) {
99         this.parse(url);
100     }
101 
102     /**
103         Copy constructor.
104     */
105     this(ref typeof(this) rhs) {
106         this.store = rhs.store;
107     }
108 
109     /**
110         Whether the URI refers to a local path.
111     */
112     @property bool isLocal() {
113         return
114             scheme_.length == 0 && 
115             authority_.length == 0 && 
116             path_.length > 0;
117     }
118 
119     /**
120         Gets the path portion of the URI
121     */
122     @property string path() { return path_; }
123 }