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(
29                 `(?:([\w-]+)://)?([\w.]+(?::\d+)?)?([^\?#]+)(?:\?([\w=&]+))?(?:#([\w-]+))?`);
30     private string _uri;
31     private string _scheme;
32     private string _authority;
33     private string _path;
34     private string _query;
35     private string _fragment;
36 
37     @property string path() const
38     {
39         return _path;
40     }
41 
42     this(DocumentUri uri)
43     {
44         import std.regex : matchAll;
45         import std.uri : decodeComponent;
46 
47         _uri = decodeComponent(uri);
48         auto matches = matchAll(_uri, _reg);
49 
50         //dfmt off
51         _scheme     = matches.front[1];
52         _authority  = matches.front[2];
53         _path       = matches.front[3].normalized;
54         _query      = matches.front[4];
55         _fragment   = matches.front[5];
56         //dfmt on
57     }
58 
59     override string toString() const
60     {
61         return _uri;
62     }
63 
64     static Uri fromPath(string path)
65     {
66         import std.algorithm : startsWith;
67         import std.format : format;
68         import std..string : tr;
69         import std.uri : encode;
70 
71         immutable uriPath = path.tr(`\`, `/`);
72         return new Uri(encode(format!"file://%s%s"(uriPath.startsWith('/') ? "" : "/", uriPath)));
73     }
74 
75     alias toString this;
76 }
77 
78 string normalized(const string path)
79 {
80     import std.array : array;
81     import std.path : asNormalizedPath;
82 
83     string res;
84 
85     version (Windows)
86     {
87         import std.algorithm : startsWith;
88         import std.path : driveName, stripDrive;
89         import std.uni : asUpperCase;
90         import std.utf : toUTF8;
91 
92         if (path.startsWith('/') || path.startsWith('\\'))
93         {
94             return path[1 .. $].normalized;
95         }
96 
97         res = driveName(path).asUpperCase().toUTF8() ~ stripDrive(path);
98     }
99     else
100     {
101         res = path;
102     }
103 
104     return asNormalizedPath(res).array;
105 }
106 
107 int filenameCmp(const Uri a, const Uri b)
108 {
109     import std.path : filenameCmp;
110 
111     return filenameCmp(a.path, b.path);
112 }
113 
114 bool sameFile(const Uri a, const Uri b)
115 {
116     return filenameCmp(a, b) == 0;
117 }