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 }