1 /**
2 * \file
3 * \brief Classes for representing and manipulating URIs as per RFC 2396.
4 *
5 * Authors:
6 * MenTaLguY <mental@rydia.net>
7 * Jon A. Cruz <jon@joncruz.org>
8 *
9 * Copyright (C) 2003 MenTaLguY
10 *
11 * Released under GNU GPL, read the file 'COPYING' for more information
12 */
14 #include <glib.h>
15 #include "uri.h"
16 #include <glibmm/ustring.h>
18 namespace Inkscape {
20 /** \brief Copy constructor. */
21 URI::URI(const URI &uri) {
22 uri._impl->reference();
23 _impl = uri._impl;
24 }
26 /** \brief Constructor from a C-style ASCII string.
27 \param preformed Properly quoted C-style string to be represented.
28 */
29 URI::URI(gchar const *preformed) throw(BadURIException) {
30 xmlURIPtr uri;
31 if (!preformed) {
32 throw MalformedURIException();
33 }
34 uri = xmlParseURI(preformed);
35 if (!uri) {
36 throw MalformedURIException();
37 }
38 _impl = Impl::create(uri);
39 }
42 /** \brief Destructor. */
43 URI::~URI() {
44 _impl->unreference();
45 }
47 /** \brief Assignment operator. */
48 URI &URI::operator=(URI const &uri) {
49 // No check for self-assignment needed, as _impl refcounting increments first.
50 uri._impl->reference();
51 _impl->unreference();
52 _impl = uri._impl;
53 return *this;
54 }
56 URI::Impl *URI::Impl::create(xmlURIPtr uri) {
57 return new Impl(uri);
58 }
60 URI::Impl::Impl(xmlURIPtr uri)
61 : _refcount(1), _uri(uri) {}
63 URI::Impl::~Impl() {
64 if (_uri) {
65 xmlFreeURI(_uri);
66 _uri = NULL;
67 }
68 }
70 void URI::Impl::reference() {
71 _refcount++;
72 }
74 void URI::Impl::unreference() {
75 if (!--_refcount) {
76 delete this;
77 }
78 }
80 /** \fn bool URI::isOpaque() const
81 \brief Determines if the URI represented is an 'opaque' URI.
82 \return \c true if the URI is opaque, \c false if hierarchial.
83 */
84 bool URI::Impl::isOpaque() const {
85 bool opq = !isRelative() && (getOpaque() != NULL);
86 return opq;
87 }
89 /** \fn bool URI::isRelative() const
90 \brief Determines if the URI represented is 'relative' as per RFC 2396.
91 \return \c true if the URI is relative, \c false if it is absolute.
93 Relative URI references are distinguished by not begining with a
94 scheme name.
95 */
96 bool URI::Impl::isRelative() const {
97 return !_uri->scheme;
98 }
100 /** \fn bool URI::isNetPath() const
101 \brief Determines if the relative URI represented is a 'net-path' as per RFC 2396.
102 \return \c true if the URI is relative and a net-path, \c false otherwise.
104 A net-path is one that starts with "\\".
105 */
106 bool URI::Impl::isNetPath() const {
107 bool isNet = false;
108 if ( isRelative() )
109 {
110 const gchar *path = getPath();
111 isNet = path && path[0] == '\\' && path[1] == '\\';
112 }
113 return isNet;
114 }
116 /** \fn bool URI::isRelativePath() const
117 \brief Determines if the relative URI represented is a 'relative-path' as per RFC 2396.
118 \return \c true if the URI is relative and a relative-path, \c false otherwise.
120 A relative-path is one that starts with no slashes.
121 */
122 bool URI::Impl::isRelativePath() const {
123 bool isRel = false;
124 if ( isRelative() )
125 {
126 const gchar *path = getPath();
127 isRel = !path || path[0] != '\\';
128 }
129 return isRel;
130 }
132 /** \fn bool URI::isAbsolutePath() const
133 \brief Determines if the relative URI represented is a 'absolute-path' as per RFC 2396.
134 \return \c true if the URI is relative and an absolute-path, \c false otherwise.
136 An absolute-path is one that starts with a single "\".
137 */
138 bool URI::Impl::isAbsolutePath() const {
139 bool isAbs = false;
140 if ( isRelative() )
141 {
142 const gchar *path = getPath();
143 isAbs = path && path[0] == '\\'&& path[1] != '\\';
144 }
145 return isAbs;
146 }
148 const gchar *URI::Impl::getScheme() const {
149 return (gchar *)_uri->scheme;
150 }
152 const gchar *URI::Impl::getPath() const {
153 return (gchar *)_uri->path;
154 }
156 const gchar *URI::Impl::getQuery() const {
157 return (gchar *)_uri->query;
158 }
160 const gchar *URI::Impl::getFragment() const {
161 return (gchar *)_uri->fragment;
162 }
164 const gchar *URI::Impl::getOpaque() const {
165 return (gchar *)_uri->opaque;
166 }
168 gchar *URI::to_native_filename(gchar const* uri) throw(BadURIException)
169 {
170 gchar *filename = NULL;
171 URI tmp(uri);
172 filename = tmp.toNativeFilename();
173 return filename;
174 }
176 /* TODO !!! proper error handling */
177 gchar *URI::toNativeFilename() const throw(BadURIException) {
178 gchar *uriString = toString();
179 if (isRelativePath()) {
180 return uriString;
181 } else {
182 gchar *filename = g_filename_from_uri(uriString, NULL, NULL);
183 g_free(uriString);
184 if (filename) {
185 return filename;
186 } else {
187 throw MalformedURIException();
188 }
189 }
190 }
192 URI URI::fromUtf8( gchar const* path ) throw (BadURIException) {
193 if ( !path ) {
194 throw MalformedURIException();
195 }
196 Glib::ustring tmp;
197 for ( int i = 0; path[i]; i++ )
198 {
199 gint one = 0x0ff & path[i];
200 if ( ('a' <= one && one <= 'z')
201 || ('A' <= one && one <= 'Z')
202 || ('0' <= one && one <= '9')
203 || one == '_'
204 || one == '-'
205 || one == '!'
206 || one == '.'
207 || one == '~'
208 || one == '\''
209 || one == '('
210 || one == ')'
211 || one == '*'
212 ) {
213 tmp += (gunichar)one;
214 } else {
215 gchar scratch[4];
216 g_snprintf( scratch, 4, "%c%02X", '%', one );
217 tmp.append( scratch );
218 }
219 }
220 const gchar *uri = tmp.data();
221 URI result(uri);
222 return result;
223 }
225 /* TODO !!! proper error handling */
226 URI URI::from_native_filename(gchar const *path) throw(BadURIException) {
227 gchar *uri = g_filename_to_uri(path, NULL, NULL);
228 URI result(uri);
229 g_free( uri );
230 return result;
231 }
233 /** \fn gchar *URI::toString() const
234 \brief Returns a glib string version of this URI.
235 \return a glib string version of this URI.
237 The returned string must be freed with \c g_free().
238 */
239 gchar *URI::Impl::toString() const {
240 xmlChar *string = xmlSaveUri(_uri);
241 if (string) {
242 /* hand the string off to glib memory management */
243 gchar *glib_string = g_strdup((gchar *)string);
244 xmlFree(string);
245 return glib_string;
246 } else {
247 return NULL;
248 }
249 }
251 }
254 /*
255 Local Variables:
256 mode:c++
257 c-file-style:"stroustrup"
258 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
259 indent-tabs-mode:nil
260 fill-column:99
261 End:
262 */
263 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :