KIO
dataprotocol.cpp
Go to the documentation of this file.
00001 // dataprotocol.cpp 00002 // ================== 00003 // 00004 // Implementation of the data protocol (rfc 2397) 00005 // 00006 // Author: Leo Savernik 00007 // Email: l.savernik@aon.at 00008 // Copyright (C) 2002, 2003 by Leo Savernik <l.savernik@aon.at> 00009 // Created: Sam Dez 28 14:11:18 CET 2002 00010 00011 /*************************************************************************** 00012 * * 00013 * This program is free software; you can redistribute it and/or modify * 00014 * it under the terms of the GNU Lesser General Public License as * 00015 * published by the Free Software Foundation; version 2. * 00016 * * 00017 ***************************************************************************/ 00018 00019 #include "dataprotocol.h" 00020 00021 #include <kdebug.h> 00022 #include <kurl.h> 00023 #include "global.h" 00024 #include <kglobal.h> 00025 00026 #include <QtCore/QByteArray> 00027 #include <QtCore/QCharRef> 00028 #include <QtCore/QMutableStringListIterator> 00029 #include <QtCore/QTextCodec> 00030 00031 #ifdef DATAKIOSLAVE 00032 # include <kinstance.h> 00033 # include <stdlib.h> 00034 #endif 00035 00036 #if !defined(DATAKIOSLAVE) 00037 # define DISPATCH(f) dispatch_##f 00038 #else 00039 # define DISPATCH(f) f 00040 #endif 00041 00042 using namespace KIO; 00043 #ifdef DATAKIOSLAVE 00044 extern "C" { 00045 00046 int kdemain( int argc, char **argv ) { 00047 KComponentData componentData( "kio_data" ); 00048 00049 kDebug(7101) << "*** Starting kio_data "; 00050 00051 if (argc != 4) { 00052 kDebug(7101) << "Usage: kio_data protocol domain-socket1 domain-socket2"; 00053 exit(-1); 00054 } 00055 00056 DataProtocol slave(argv[2], argv[3]); 00057 slave.dispatchLoop(); 00058 00059 kDebug(7101) << "*** kio_data Done"; 00060 return 0; 00061 } 00062 } 00063 #endif 00064 00066 struct DataHeader { 00067 QString mime_type; // mime type of content (lowercase) 00068 MetaData attributes; // attribute/value pairs (attribute lowercase, 00069 // value unchanged) 00070 bool is_base64; // true if data is base64 encoded 00071 QByteArray url; // reference to decoded url 00072 int data_offset; // zero-indexed position within url 00073 // where the real data begins. May point beyond 00074 // the end to indicate that there is no data 00075 }; 00076 00085 static int find(const QByteArray &buf, int begin, const char c1) 00086 { 00087 static const char comma = ','; 00088 static const char semicolon = ';'; 00089 int pos = begin; 00090 int size = buf.length(); 00091 while (pos < size) { 00092 const char ch = buf[pos]; 00093 if (ch == comma || ch == semicolon || (c1 != '\0' && ch == c1)) 00094 break; 00095 pos++; 00096 }/*wend*/ 00097 return pos; 00098 } 00099 00108 static inline QString extract(const QByteArray &buf, int &pos, 00109 const char c1 = '\0') 00110 { 00111 int oldpos = pos; 00112 pos = find(buf, oldpos, c1); 00113 return buf.mid(oldpos, pos-oldpos); 00114 } 00115 00122 static inline void ignoreWS(const QString &buf, int &pos) 00123 { 00124 int size = buf.length(); 00125 while (pos < size && buf[pos].isSpace()) 00126 ++pos; 00127 } 00128 00137 static QString parseQuotedString(const QString &buf, int &pos) { 00138 int size = buf.length(); 00139 QString res; 00140 res.reserve(size); // can't be larger than buf 00141 pos++; // jump over leading quote 00142 bool escaped = false; // if true means next character is literal 00143 bool parsing = true; // true as long as end quote not found 00144 while (parsing && pos < size) { 00145 const QChar ch = buf[pos++]; 00146 if (escaped) { 00147 res += ch; 00148 escaped = false; 00149 } else { 00150 switch (ch.unicode()) { 00151 case '"': parsing = false; break; 00152 case '\\': escaped = true; break; 00153 default: res += ch; break; 00154 }/*end switch*/ 00155 }/*end if*/ 00156 }/*wend*/ 00157 res.squeeze(); 00158 return res; 00159 } 00160 00166 static DataHeader parseDataHeader(const KUrl &url, const bool mimeOnly) 00167 { 00168 static const QString& text_plain = KGlobal::staticQString("text/plain"); 00169 static const QString& charset = KGlobal::staticQString("charset"); 00170 static const QString& us_ascii = KGlobal::staticQString("us-ascii"); 00171 static const QString& base64 = KGlobal::staticQString("base64"); 00172 00173 DataHeader header_info; 00174 00175 // initialize header info members 00176 header_info.mime_type = text_plain; 00177 header_info.attributes.insert(charset, us_ascii); 00178 header_info.is_base64 = false; 00179 00180 // decode url and save it 00181 const QByteArray &raw_url = header_info.url = QByteArray::fromPercentEncoding( url.encodedPath() ); 00182 const int raw_url_len = raw_url.length(); 00183 00184 header_info.data_offset = 0; 00185 00186 // read mime type 00187 if (raw_url_len == 0) 00188 return header_info; 00189 const QString mime_type = extract(raw_url, header_info.data_offset).trimmed(); 00190 if (!mime_type.isEmpty()) header_info.mime_type = mime_type; 00191 if (mimeOnly) 00192 return header_info; 00193 00194 if (header_info.data_offset >= raw_url_len) 00195 return header_info; 00196 // jump over delimiter token and return if data reached 00197 if (raw_url[header_info.data_offset++] == QLatin1Char(',')) 00198 return header_info; 00199 00200 // read all attributes and store them 00201 bool data_begin_reached = false; 00202 while (!data_begin_reached && header_info.data_offset < raw_url_len) { 00203 // read attribute 00204 const QString attribute = extract(raw_url, header_info.data_offset, '=').trimmed(); 00205 if (header_info.data_offset >= raw_url_len 00206 || raw_url[header_info.data_offset] != QLatin1Char('=')) { 00207 // no assigment, must be base64 option 00208 if (attribute == base64) 00209 header_info.is_base64 = true; 00210 } else { 00211 header_info.data_offset++; // jump over '=' token 00212 00213 // read value 00214 ignoreWS(raw_url,header_info.data_offset); 00215 if (header_info.data_offset >= raw_url_len) 00216 return header_info; 00217 00218 QString value; 00219 if (raw_url[header_info.data_offset] == QLatin1Char('"')) { 00220 value = parseQuotedString(raw_url,header_info.data_offset); 00221 ignoreWS(raw_url,header_info.data_offset); 00222 } else 00223 value = extract(raw_url, header_info.data_offset).trimmed(); 00224 00225 // add attribute to map 00226 header_info.attributes[attribute.toLower()] = value; 00227 00228 }/*end if*/ 00229 if (header_info.data_offset < raw_url_len 00230 && raw_url[header_info.data_offset] == QLatin1Char(',')) 00231 data_begin_reached = true; 00232 header_info.data_offset++; // jump over separator token 00233 }/*wend*/ 00234 00235 return header_info; 00236 } 00237 00238 #ifdef DATAKIOSLAVE 00239 DataProtocol::DataProtocol(const QByteArray &pool_socket, const QByteArray &app_socket) 00240 : SlaveBase("kio_data", pool_socket, app_socket) { 00241 #else 00242 DataProtocol::DataProtocol() { 00243 #endif 00244 kDebug(); 00245 } 00246 00247 /* --------------------------------------------------------------------- */ 00248 00249 DataProtocol::~DataProtocol() { 00250 kDebug(); 00251 } 00252 00253 /* --------------------------------------------------------------------- */ 00254 00255 void DataProtocol::get(const KUrl& url) { 00256 ref(); 00257 kDebug() << "kio_data@"<<this<<"::get(const KUrl& url)"; 00258 00259 const DataHeader hdr = parseDataHeader(url, false); 00260 00261 const int size = hdr.url.length(); 00262 const int data_ofs = qMin(hdr.data_offset, size); 00263 // FIXME: string is copied, would be nice if we could have a reference only 00264 const QByteArray url_data = hdr.url.mid(data_ofs); 00265 QByteArray outData; 00266 00267 if (hdr.is_base64) { 00268 // base64 stuff is expected to contain the correct charset, so we just 00269 // decode it and pass it to the receiver 00270 outData = QByteArray::fromBase64(url_data); 00271 } else { 00272 QTextCodec *codec = QTextCodec::codecForName(hdr.attributes["charset"].toLatin1()); 00273 if (codec != 0) { 00274 outData = codec->toUnicode(url_data).toUtf8(); 00275 } else { 00276 outData = url_data; 00277 }/*end if*/ 00278 }/*end if*/ 00279 00280 //kDebug() << "emit mimeType@"<<this; 00281 mimeType(hdr.mime_type); 00282 //kDebug() << "emit totalSize@"<<this; 00283 totalSize(outData.size()); 00284 00285 //kDebug() << "emit setMetaData@"<<this; 00286 #if defined(DATAKIOSLAVE) 00287 MetaData::ConstIterator it; 00288 for (it = hdr.attributes.constBegin(); it != hdr.attributes.constEnd(); ++it) { 00289 setMetaData(it.key(),it.value()); 00290 }/*next it*/ 00291 #else 00292 setAllMetaData(hdr.attributes); 00293 #endif 00294 00295 //kDebug() << "emit sendMetaData@"<<this; 00296 sendMetaData(); 00297 // kDebug() << "(1) queue size " << dispatchQueue.size(); 00298 // empiric studies have shown that this shouldn't be queued & dispatched 00299 data(outData); 00300 // kDebug() << "(2) queue size " << dispatchQueue.size(); 00301 DISPATCH(data(QByteArray())); 00302 // kDebug() << "(3) queue size " << dispatchQueue.size(); 00303 DISPATCH(finished()); 00304 // kDebug() << "(4) queue size " << dispatchQueue.size(); 00305 deref(); 00306 } 00307 00308 /* --------------------------------------------------------------------- */ 00309 00310 void DataProtocol::mimetype(const KUrl &url) { 00311 ref(); 00312 mimeType(parseDataHeader(url, true).mime_type); 00313 finished(); 00314 deref(); 00315 } 00316 00317 /* --------------------------------------------------------------------- */
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:34:57 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:34:57 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.