1 /**
2 * @file SBMLUri.cpp
3 * @brief Implementation of SBMLUri, the utility class for handling uris.
4 * @author Frank Bergmann
5 *
6 * <!--------------------------------------------------------------------------
7 * This file is part of libSBML. Please visit http://sbml.org for more
8 * information about SBML, and the latest version of libSBML.
9 *
10 * Copyright (C) 2020 jointly by the following organizations:
11 * 1. California Institute of Technology, Pasadena, CA, USA
12 * 2. University of Heidelberg, Heidelberg, Germany
13 * 3. University College London, London, UK
14 *
15 * Copyright (C) 2019 jointly by the following organizations:
16 * 1. California Institute of Technology, Pasadena, CA, USA
17 * 2. University of Heidelberg, Heidelberg, Germany
18 *
19 * Copyright (C) 2013-2018 jointly by the following organizations:
20 * 1. California Institute of Technology, Pasadena, CA, USA
21 * 2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
22 * 3. University of Heidelberg, Heidelberg, Germany
23 *
24 * Copyright 2011-2012 jointly by the following organizations:
25 * 1. California Institute of Technology, Pasadena, CA, USA
26 * 2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
27 *
28 * This library is free software; you can redistribute it and/or modify it
29 * under the terms of the GNU Lesser General Public License as published by
30 * the Free Software Foundation. A copy of the license agreement is provided
31 * in the file named "LICENSE.txt" included with this software distribution
32 * and also available online as http://sbml.org/software/libsbml/license.html
33 * ------------------------------------------------------------------------ -->
34 */
35
36 #include <sbml/packages/comp/util/SBMLUri.h>
37 #include <sbml/SBMLDocument.h>
38 #include <sbml/SBMLConstructorException.h>
39
40 #ifdef __cplusplus
41
42 #include <cctype>
43 #include <functional>
44 #include <iterator>
45 #include <string>
46 #include <algorithm>
47
48 using namespace std;
49 LIBSBML_CPP_NAMESPACE_BEGIN
50
SBMLUri(const std::string & uri)51 SBMLUri::SBMLUri (const std::string& uri)
52 {
53 parse(uri);
54 }
55
56
57 /*
58 * Copy constructor.
59 */
SBMLUri(const SBMLUri & orig)60 SBMLUri::SBMLUri(const SBMLUri& orig)
61 : mScheme (orig.mScheme)
62 , mHost (orig.mHost)
63 , mPath (orig.mPath)
64 , mQuery (orig.mQuery)
65 , mUri (orig.mUri)
66 {
67 }
68
69
70 /*
71 * Destroy this object.
72 */
~SBMLUri()73 SBMLUri::~SBMLUri ()
74 {
75
76 }
77
78
79 /*
80 * Assignment operator for SBMLUri.
81 */
82 SBMLUri&
operator =(const SBMLUri & rhs)83 SBMLUri::operator=(const SBMLUri& rhs)
84 {
85 if(&rhs!=this)
86 {
87 mScheme = rhs.mScheme;
88 mHost = rhs.mHost;
89 mPath = rhs.mPath;
90 mQuery = rhs.mQuery;
91 mUri = rhs.mUri;
92 }
93
94 return *this;
95 }
96
97 /*
98 * Assignment operator for strings.
99 */
100 SBMLUri&
operator =(const std::string & uri)101 SBMLUri::operator=(const std::string& uri)
102 {
103 parse(uri);
104 return *this;
105 }
106
107
108 SBMLUri*
clone() const109 SBMLUri::clone () const
110 {
111 return new SBMLUri(*this);
112 }
113
114 struct replace_back_slash
115 {
operator ()replace_back_slash116 void operator()(char& c) { if(c == '\\') c = '/'; }
117 };
118
119 /*
120 * adapted from: http://stackoverflow.com/questions/2616011/easy-way-to-parse-a-url-in-c-cross-platform
121 */
122 void
parse(const std::string & uri)123 SBMLUri::parse(const std::string& uri)
124 {
125 mScheme = "";
126 mHost = "";
127 mQuery = "";
128 mPath = "";
129 mUri = uri;
130
131 std::for_each( mUri.begin(), mUri.end(), replace_back_slash() );
132
133 const std::string constUri(mUri);
134
135 string prot_end("://");
136 string::const_iterator prot_i = search(constUri.begin(), constUri.end(),
137 prot_end.begin(), prot_end.end());
138 if (prot_i == constUri.end())
139 {
140 // not found ...
141 prot_end = ":";
142 prot_i = search(constUri.begin(), constUri.end(),
143 prot_end.begin(), prot_end.end());
144 if (prot_i == constUri.end() || prot_i == constUri.begin() + 1)
145 {
146 // if we still have not found it assume this is a file uri
147 mScheme = "file";
148 mPath = constUri ;
149 mUri = mScheme + ":///" + mPath;
150 return;
151 }
152 }
153
154 mScheme.reserve((size_t)distance(constUri.begin(), prot_i));
155 #ifdef __BORLANDC__
156 transform(constUri.begin(), prot_i,
157 back_inserter(mScheme),
158 (int(*)(int))(tolower)); // scheme is icase
159 #else
160 transform(constUri.begin(), prot_i,
161 back_inserter(mScheme),
162 ptr_fun<int,int>(tolower)); // scheme is icase
163 #endif
164
165 if( prot_i == constUri.end() )
166 {
167 return;
168 }
169
170 #ifdef __BORLANDC__
171 advance(prot_i, prot_end.length());
172 #else
173 advance(prot_i, (string::const_iterator::difference_type) prot_end.length());
174 #endif
175 if ((prot_i + 1) != constUri.end() && *(prot_i + 1) == ':')
176 {
177 // turns out there are invalid urls being used internally, of the form
178 // file:drive:/ ... this is just plain wrong but needs to be parsed correctly
179 //
180 mPath.reserve((size_t)distance(prot_i, constUri.end()));
181 #ifdef __BORLANDC__
182 mPath = std::string(prot_i, constUri.end());
183 #else
184 mPath.assign(prot_i, constUri.end());
185 #endif
186 // but we ought to fix the URI!
187 mUri = mScheme + ":///" + mPath;
188 return;
189 }
190
191 string::const_iterator path_i = find(prot_i, constUri.end(), '/');
192 if (mScheme != "file" && mScheme != "urn")
193 {
194 // file won't have a host (or could assume localhost)
195 mHost.reserve((size_t)distance(prot_i, path_i));
196 #ifdef __BORLANDC__
197 transform(prot_i, path_i,
198 back_inserter(mHost),
199 (int(*)(int))(tolower)); // host is icase
200 #else
201 transform(prot_i, path_i,
202 back_inserter(mHost),
203 ptr_fun<int,int>(tolower)); // host is icase
204 #endif
205 }
206 else if (mScheme == "urn")
207 {
208 // special handling for the miriam scheme, as it is something we ought
209 // to support
210 size_t pos = constUri.rfind(':');
211 mScheme = constUri.substr(0,pos);
212 mPath = constUri.substr(pos+1, constUri.length() - pos +1);
213 return;
214 }
215 else
216 {
217 #ifdef __BORLANDC__
218 mPath = std::string(prot_i, path_i);
219 #else
220 mPath.assign(prot_i, path_i);
221 #endif
222 if (mPath.size() > 0 && mPath[0] == '/')
223 {
224 #ifdef __BORLANDC__
225 mPath = std::string(mPath.begin() +1, mPath.end());
226 #else
227 mPath.assign(mPath.begin() +1, mPath.end());
228 #endif
229 }
230 }
231
232 if (path_i == constUri.end())
233 {
234 return;
235 }
236
237 string::const_iterator query_i = find(path_i, constUri.end(), '?');
238 #ifdef __BORLANDC__
239 mPath = std::string(path_i, query_i);
240 #else
241 mPath.assign(path_i, query_i);
242 #endif
243
244 if (mPath.size() > 0 && mPath[0] == '/')
245 {
246 #ifdef __BORLANDC__
247 mPath = std::string(mPath.begin() +1, mPath.end());
248 #else
249 mPath.assign(mPath.begin() +1, mPath.end());
250 #endif
251 }
252
253 if( query_i != constUri.end() )
254 ++query_i;
255
256 #ifdef __BORLANDC__
257 mQuery = std::string(query_i, constUri.end());
258 #else
259 mQuery.assign(query_i, constUri.end());
260 #endif
261 }
262
263 SBMLUri
relativeTo(const std::string & uri) const264 SBMLUri::relativeTo(const std::string& uri) const
265 {
266 SBMLUri other(uri);
267 other.mScheme = mScheme;
268 other.mHost = mHost;
269 bool slashNeeded = ((!other.mPath.empty() && other.mPath[0] != '/') ||
270 (!mPath.empty() && !other.mPath.empty() && other.mPath[0] != '/' && mPath[mPath.length() -1 ] != '/') ||
271 (!mPath.empty() && other.mPath.empty() && mPath[mPath.length() -1 ] != '/') );
272
273 if (slashNeeded && other.mPath.length() > 2 && other.mPath[1] == ':')
274 {
275 // the uri is a full path with drive letter
276 return other;
277 }
278
279 other.mPath = mPath + (slashNeeded ? "/" : "") + other.mPath;
280 other.mUri = mScheme + "://" + mHost + (slashNeeded ? "/" : "") + other.mPath;
281 if (!other.mQuery.empty())
282 other.mUri += "?" + other.mQuery;
283
284 return other;
285 }
286
287 const std::string&
getScheme() const288 SBMLUri::getScheme() const
289 {
290 return mScheme;
291 }
292
293 const std::string&
getHost() const294 SBMLUri::getHost() const
295 {
296 return mHost;
297 }
298
299 const std::string&
getPath() const300 SBMLUri::getPath() const
301 {
302 return mPath;
303 }
304
305 const std::string&
getUri() const306 SBMLUri::getUri() const
307 {
308 return mUri;
309 }
310
311 const std::string&
getQuery() const312 SBMLUri::getQuery() const
313 {
314 return mQuery;
315 }
316
317 /** @cond doxygenIgnored */
318 /** @endcond */
319
320 LIBSBML_CPP_NAMESPACE_END
321
322 #endif /* __cplusplus */
323
324
325