1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 3 /* 4 Dataquay 5 6 A C++/Qt library for simple RDF datastore management. 7 Copyright 2009-2012 Chris Cannam. 8 9 Permission is hereby granted, free of charge, to any person 10 obtaining a copy of this software and associated documentation 11 files (the "Software"), to deal in the Software without 12 restriction, including without limitation the rights to use, copy, 13 modify, merge, publish, distribute, sublicense, and/or sell copies 14 of the Software, and to permit persons to whom the Software is 15 furnished to do so, subject to the following conditions: 16 17 The above copyright notice and this permission notice shall be 18 included in all copies or substantial portions of the Software. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 24 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 25 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 28 Except as contained in this notice, the name of Chris Cannam 29 shall not be used in advertising or otherwise to promote the sale, 30 use or other dealings in this Software without prior written 31 authorization. 32 */ 33 34 #include "Uri.h" 35 36 #include <QDataStream> 37 #include <QTextStream> 38 #include <QVariant> 39 #include <QMutex> 40 #include <QHash> 41 #include <QRegExp> 42 43 #include <iostream> 44 45 #ifndef NDEBUG 46 #include <QRegExp> 47 #endif 48 49 #include "Debug.h" 50 #include "RDFException.h" 51 52 namespace Dataquay 53 { 54 55 class UriRegistrar { 56 public: 57 static UriRegistrar *instance() { 58 static UriRegistrar *inst = 0; 59 static QMutex mutex; 60 mutex.lock(); 61 if (inst == 0) inst = new UriRegistrar(); 62 mutex.unlock(); 63 return inst; 64 } 65 66 int getType() const { return type; } 67 QString getName() const { return name; } 68 69 private: 70 QString name; 71 int type; 72 73 UriRegistrar() : name("Dataquay::Uri") { 74 DQ_DEBUG << "UriRegistrar: registering Dataquay::Uri" << endl; 75 QByteArray bname = name.toLatin1(); 76 type = qRegisterMetaType<Uri>(bname.data()); 77 qRegisterMetaTypeStreamOperators<Uri>(bname.data()); 78 } 79 }; 80 81 QString 82 Uri::metaTypeName() 83 { 84 return UriRegistrar::instance()->getName(); 85 } 86 87 int 88 Uri::metaTypeId() 89 { 90 int t = UriRegistrar::instance()->getType(); 91 if (t <= 0) { 92 DQ_DEBUG << "Uri::metaTypeId: No meta type available -- did static registration fail?" << endl; 93 return 0; 94 } 95 return t; 96 } 97 98 void 99 Uri::checkComplete() 100 { 101 if (!canBeComplete(m_uri)) { // may modify m_uri 102 throw RDFIncompleteURI 103 ("Uri::Uri: Given string is not a complete absolute URI", m_uri); 104 } 105 } 106 107 bool 108 Uri::isCompleteUri(QString s) 109 { 110 QString s0(s); 111 return canBeComplete(s0); 112 } 113 114 bool 115 Uri::canBeComplete(QString &s) 116 { 117 // An RDF URI must be absolute, with a few special cases 118 119 if (s == "a") { 120 121 s = rdfTypeUri().toString(); 122 return true; 123 124 } else if (s.isEmpty() || s[0] == '#' || s[0] == ':') { 125 126 return false; 127 128 } else { 129 130 // look for scheme (and we know from the above that the first 131 // char is not ':') 132 133 bool hasScheme = false; 134 135 for (int i = 0; i < s.length(); ++i) { 136 if (s[i] == QChar(':')) { 137 if (s[i+1] != QChar('/')) break; 138 if (s[i+2] != QChar('/')) break; 139 hasScheme = true; 140 break; 141 } 142 if (!s[i].isLetter()) return false; 143 } 144 145 if (hasScheme) return true; 146 147 // we are generous with file URIs: if we get file:x, convert 148 // it to file://x 149 if (s.startsWith("file:")) { 150 s = "file://" + s.right(s.length() - 5); 151 return true; 152 } else { 153 return false; 154 } 155 } 156 } 157 158 QString 159 Uri::scheme() const 160 { 161 int index = m_uri.indexOf(':'); 162 if (index < 0) return ""; 163 return m_uri.left(index); 164 } 165 166 bool 167 Uri::operator==(const Uri &u) const 168 { 169 const QString &other = u.m_uri; 170 int len = length(); 171 if (len != other.length()) return false; 172 for (int i = len - 1; i >= 0; --i) { 173 if (m_uri.at(i) != other.at(i)) return false; 174 } 175 return true; 176 } 177 178 bool 179 Uri::hasUriType(const QVariant &v) 180 { 181 return (v.type() == QVariant::UserType && v.userType() == metaTypeId()); 182 } 183 184 Uri 185 Uri::rdfTypeUri() 186 { 187 return Uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); 188 } 189 190 QDataStream &operator<<(QDataStream &out, const Uri &u) { 191 return out << u.toString(); 192 } 193 194 QDataStream &operator>>(QDataStream &in, Uri &u) { 195 QString s; 196 in >> s; 197 u = Uri(s); 198 return in; 199 } 200 201 std::ostream &operator<<(std::ostream &out, const Uri &u) { 202 return out << u.toString().toLocal8Bit().data(); 203 } 204 205 QTextStream &operator<<(QTextStream &out, const Uri &u) { 206 return out << u.toString(); 207 } 208 209 } 210 211 unsigned int qHash(const Dataquay::Uri &u) 212 { 213 return qHash(u.toString()); 214 } 215 216 217 218