KIO
dataprotocol.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "dataprotocol.h"
00020
00021 #include <kdebug.h>
00022 #include <kcodecs.h>
00023 #include <kurl.h>
00024 #include "global.h"
00025 #include <kglobal.h>
00026
00027 #include <QtCore/QByteArray>
00028 #include <QtCore/QCharRef>
00029 #include <QtCore/QMutableStringListIterator>
00030 #include <QtCore/QTextCodec>
00031
00032 #ifdef DATAKIOSLAVE
00033 # include <kinstance.h>
00034 # include <stdlib.h>
00035 #endif
00036
00037 #if !defined(DATAKIOSLAVE) && !defined(TESTKIO)
00038 # define DISPATCH(f) dispatch_##f
00039 #else
00040 # define DISPATCH(f) f
00041 #endif
00042
00043 using namespace KIO;
00044 #ifdef DATAKIOSLAVE
00045 extern "C" {
00046
00047 int kdemain( int argc, char **argv ) {
00048 KComponentData componentData( "kio_data" );
00049
00050 kDebug(7101) << "*** Starting kio_data ";
00051
00052 if (argc != 4) {
00053 kDebug(7101) << "Usage: kio_data protocol domain-socket1 domain-socket2";
00054 exit(-1);
00055 }
00056
00057 DataProtocol slave(argv[2], argv[3]);
00058 slave.dispatchLoop();
00059
00060 kDebug(7101) << "*** kio_data Done";
00061 return 0;
00062 }
00063 }
00064 #endif
00065
00067 struct DataHeader {
00068 QString mime_type;
00069 MetaData attributes;
00070
00071 bool is_base64;
00072 QString url;
00073 int data_offset;
00074
00075
00076 QString charset;
00077 };
00078
00088 static int find(const QString &buf, int begin, QChar c1,
00089 QChar c2 = QLatin1Char('\0'), QChar c3 = QLatin1Char('\0')) {
00090 int pos = begin;
00091 int size = buf.length();
00092 while (pos < size) {
00093 QChar ch = buf[pos];
00094 if (ch == c1
00095 || (c2 != QLatin1Char('\0') && ch == c2)
00096 || (c3 != QLatin1Char('\0') && ch == c3))
00097 break;
00098 pos++;
00099 }
00100 return pos;
00101 }
00102
00113 inline QString extract(const QString &buf, int &pos, QChar c1,
00114 QChar c2 = QLatin1Char('\0'), QChar c3 = QLatin1Char('\0')) {
00115 int oldpos = pos;
00116 pos = find(buf,oldpos,c1,c2,c3);
00117 return buf.mid(oldpos, pos-oldpos);
00118 }
00119
00126 inline void ignoreWS(const QString &buf, int &pos) {
00127 int size = buf.length();
00128 QChar ch = buf[pos];
00129 while (pos < size && ch.isSpace())
00130 ch = buf[++pos];
00131 }
00132
00141 static QString parseQuotedString(const QString &buf, int &pos) {
00142 int size = buf.length();
00143 QString res;
00144 res.reserve(size);
00145 pos++;
00146 bool escaped = false;
00147 bool parsing = true;
00148 while (parsing && pos < size) {
00149 QChar ch = buf[pos++];
00150 if (escaped) {
00151 res += ch;
00152 escaped = false;
00153 } else {
00154 switch (ch.unicode()) {
00155 case '"': parsing = false; break;
00156 case '\\': escaped = true; break;
00157 default: res += ch; break;
00158 }
00159 }
00160 }
00161 res.squeeze();
00162 return res;
00163 }
00164
00170 static void parseDataHeader(const KUrl &url, DataHeader &header_info) {
00171 static const QString& text_plain = KGlobal::staticQString("text/plain");
00172 static const QString& charset = KGlobal::staticQString("charset");
00173 static const QString& us_ascii = KGlobal::staticQString("us-ascii");
00174 static const QString& base64 = KGlobal::staticQString("base64");
00175
00176
00177 header_info.mime_type = text_plain;
00178 header_info.charset = header_info.attributes.insert(charset,us_ascii).value();
00179 header_info.is_base64 = false;
00180
00181
00182 QString &raw_url = header_info.url = QUrl::fromPercentEncoding( url.url().toLatin1() );
00183 int raw_url_len = raw_url.length();
00184
00185
00186 header_info.data_offset = raw_url.indexOf(QLatin1Char(':'));
00187 header_info.data_offset++;
00188
00189
00190 if (header_info.data_offset >= raw_url_len) return;
00191 QString mime_type = extract(raw_url, header_info.data_offset,
00192 QLatin1Char(';'), QLatin1Char(',')).trimmed();
00193 if (!mime_type.isEmpty()) header_info.mime_type = mime_type;
00194
00195 if (header_info.data_offset >= raw_url_len) return;
00196
00197 if (raw_url[header_info.data_offset++] == QLatin1Char(',')) return;
00198
00199
00200 bool data_begin_reached = false;
00201 while (!data_begin_reached && header_info.data_offset < raw_url_len) {
00202
00203 QString attribute = extract(raw_url, header_info.data_offset,
00204 QLatin1Char('='), QLatin1Char(';'),
00205 QLatin1Char(',')).trimmed();
00206 if (header_info.data_offset >= raw_url_len
00207 || raw_url[header_info.data_offset] != QLatin1Char('=')) {
00208
00209 if (attribute == base64)
00210 header_info.is_base64 = true;
00211 } else {
00212 header_info.data_offset++;
00213
00214
00215 ignoreWS(raw_url,header_info.data_offset);
00216 if (header_info.data_offset >= raw_url_len) return;
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, QLatin1Char(';'),
00224 QLatin1Char(',')).trimmed();
00225
00226
00227 header_info.attributes[attribute.toLower()] = value;
00228
00229 }
00230 if (header_info.data_offset < raw_url_len
00231 && raw_url[header_info.data_offset] == QLatin1Char(','))
00232 data_begin_reached = true;
00233 header_info.data_offset++;
00234 }
00235 }
00236
00237 #ifdef DATAKIOSLAVE
00238 DataProtocol::DataProtocol(const QByteArray &pool_socket, const QByteArray &app_socket)
00239 : SlaveBase("kio_data", pool_socket, app_socket) {
00240 #else
00241 DataProtocol::DataProtocol() {
00242 #endif
00243 kDebug();
00244 }
00245
00246
00247
00248 DataProtocol::~DataProtocol() {
00249 kDebug();
00250 }
00251
00252
00253
00254 void DataProtocol::get(const KUrl& url) {
00255 ref();
00256 kDebug() << "kio_data@"<<this<<"::get(const KUrl& url)";
00257
00258 DataHeader hdr;
00259 parseDataHeader(url,hdr);
00260
00261 int size = hdr.url.length();
00262 int data_ofs = qMin(hdr.data_offset,size);
00263
00264 QString url_data = hdr.url.mid(data_ofs);
00265 QByteArray outData;
00266
00267 if (hdr.is_base64) {
00268
00269
00270 outData = QByteArray::fromBase64(url_data.toUtf8());
00271 } else {
00272
00273
00274 QTextCodec *codec = QTextCodec::codecForName(hdr.charset.toLatin1());
00275 if (codec != 0) {
00276 outData = codec->fromUnicode(url_data);
00277 } else {
00278
00279
00280 outData = url_data.toLocal8Bit();
00281 }
00282 }
00283
00284
00285 mimeType(hdr.mime_type);
00286
00287 totalSize(outData.size());
00288
00289
00290 #if defined(TESTKIO) || defined(DATAKIOSLAVE)
00291 MetaData::ConstIterator it;
00292 for (it = hdr.attributes.constBegin(); it != hdr.attributes.constEnd(); ++it) {
00293 setMetaData(it.key(),it.value());
00294 }
00295 #else
00296 setAllMetaData(hdr.attributes);
00297 #endif
00298
00299
00300 sendMetaData();
00301
00302
00303 data(outData);
00304
00305 DISPATCH(data(QByteArray()));
00306
00307 DISPATCH(finished());
00308
00309 deref();
00310 }
00311
00312
00313
00314 void DataProtocol::mimetype(const KUrl &url) {
00315 ref();
00316 DataHeader hdr;
00317 parseDataHeader(url,hdr);
00318 mimeType(hdr.mime_type);
00319 finished();
00320 deref();
00321 }
00322
00323