1 /* 2 *Copyright (C) 2018 Laurent Tréguier 3 * 4 *This file is part of DLS. 5 * 6 *DLS is free software: you can redistribute it and/or modify 7 *it under the terms of the GNU General Public License as published by 8 *the Free Software Foundation, either version 3 of the License, or 9 *(at your option) any later version. 10 * 11 *DLS is distributed in the hope that it will be useful, 12 *but WITHOUT ANY WARRANTY; without even the implied warranty of 13 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 *GNU General Public License for more details. 15 * 16 *You should have received a copy of the GNU General Public License 17 *along with DLS. If not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 module dls.util.uri; 22 23 class Uri 24 { 25 import dls.protocol.definitions : DocumentUri; 26 import std.regex : regex; 27 28 private static enum _reg = regex(`([\w-]+):(?://([\w.@]+(?::\d+)?))?([^\?#]+)(?:\?([\w=&]+))?(?:#([\w-]+))?`); 29 private string _uri; 30 private string _scheme; 31 private string _authority; 32 private string _path; 33 private string _query; 34 private string _fragment; 35 36 @property string path() const 37 { 38 return _path; 39 } 40 41 this(DocumentUri uri) 42 { 43 import std.regex : matchAll; 44 import std.uri : decodeComponent; 45 46 _uri = decodeComponent(uri); 47 auto matches = matchAll(_uri, _reg); 48 49 //dfmt off 50 _scheme = matches.front[1]; 51 _authority = matches.front[2]; 52 _path = matches.front[3].normalized; 53 _query = matches.front[4]; 54 _fragment = matches.front[5]; 55 //dfmt on 56 } 57 58 private this(string scheme, string authority, string path, string query, string fragment) 59 { 60 _uri = scheme ~ ':'; 61 62 if (authority !is null) 63 { 64 _uri ~= "//" ~ authority; 65 } 66 67 _uri ~= path; 68 69 if (query !is null) 70 { 71 _uri ~= '?' ~ query; 72 } 73 74 if (fragment !is null) 75 { 76 _uri ~= '#' ~ fragment; 77 } 78 79 //dfmt off 80 _scheme = scheme; 81 _authority = authority; 82 _path = path.normalized; 83 _query = query; 84 _fragment = fragment; 85 //dfmt on 86 } 87 88 override string toString() const 89 { 90 return _uri; 91 } 92 93 static Uri fromPath(string path) 94 { 95 import std.algorithm : startsWith; 96 import std.format : format; 97 import std..string : tr; 98 import std.uri : encode; 99 100 immutable uriPath = path.tr(`\`, `/`); 101 return new Uri("file", "", (uriPath.startsWith('/') ? "" : "/") ~ uriPath, null, null); 102 } 103 104 alias toString this; 105 } 106 107 string normalized(const string path) 108 { 109 import std.array : array; 110 import std.path : asNormalizedPath; 111 112 string res; 113 114 version (Windows) 115 { 116 import std.algorithm : startsWith; 117 import std.path : driveName, stripDrive; 118 import std.uni : asUpperCase; 119 import std.utf : toUTF8; 120 121 if (path.startsWith('/') || path.startsWith('\\')) 122 { 123 return path[1 .. $].normalized; 124 } 125 126 res = driveName(path).asUpperCase().toUTF8() ~ stripDrive(path); 127 } 128 else 129 { 130 res = path; 131 } 132 133 return asNormalizedPath(res).array; 134 } 135 136 int filenameCmp(const Uri a, const Uri b) 137 { 138 import std.path : filenameCmp; 139 140 return filenameCmp(a.path, b.path); 141 } 142 143 bool sameFile(const Uri a, const Uri b) 144 { 145 return filenameCmp(a, b) == 0; 146 }