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 <kmdcodec.h>
00023 #include <kurl.h>
00024 #include <kio/global.h>
00025
00026 #include <qcstring.h>
00027 #include <qstring.h>
00028 #include <qstringlist.h>
00029 #include <qtextcodec.h>
00030
00031 #ifdef DATAKIOSLAVE
00032 # include <kinstance.h>
00033 # include <stdlib.h>
00034 #endif
00035 #ifdef TESTKIO
00036 # include <iostream.h>
00037 #endif
00038
00039 #if !defined(DATAKIOSLAVE) && !defined(TESTKIO)
00040 # define DISPATCH(f) dispatch_##f
00041 #else
00042 # define DISPATCH(f) f
00043 #endif
00044
00045 using namespace KIO;
00046 #ifdef DATAKIOSLAVE
00047 extern "C" {
00048
00049 int kdemain( int argc, char **argv ) {
00050 KInstance instance( "kio_data" );
00051
00052 kdDebug(7101) << "*** Starting kio_data " << endl;
00053
00054 if (argc != 4) {
00055 kdDebug(7101) << "Usage: kio_data protocol domain-socket1 domain-socket2" << endl;
00056 exit(-1);
00057 }
00058
00059 DataProtocol slave(argv[2], argv[3]);
00060 slave.dispatchLoop();
00061
00062 kdDebug(7101) << "*** kio_data Done" << endl;
00063 return 0;
00064 }
00065 }
00066 #endif
00067
00069 struct DataHeader {
00070 QString mime_type;
00071 MetaData attributes;
00072
00073 bool is_base64;
00074 QString url;
00075 int data_offset;
00076
00077
00078 QString *charset;
00079 };
00080
00081
00082 const QChar text_plain_str[] = { 't','e','x','t','/','p','l','a','i','n' };
00083 const QChar charset_str[] = { 'c','h','a','r','s','e','t' };
00084 const QChar us_ascii_str[] = { 'u','s','-','a','s','c','i','i' };
00085 const QChar base64_str[] = { 'b','a','s','e','6','4' };
00086
00095 static int find(const QString &buf, int begin, QChar c1, QChar c2 = '\0',
00096 QChar c3 = '\0') {
00097 int pos = begin;
00098 int size = (int)buf.length();
00099 while (pos < size) {
00100 QChar ch = buf[pos];
00101 if (ch == c1
00102 || (c2 != '\0' && ch == c2)
00103 || (c3 != '\0' && ch == c3))
00104 break;
00105 pos++;
00106 }
00107 return pos;
00108 }
00109
00120 inline QString extract(const QString &buf, int &pos, QChar c1,
00121 QChar c2 = '\0', QChar c3 = '\0') {
00122 int oldpos = pos;
00123 pos = find(buf,oldpos,c1,c2,c3);
00124 return QString(buf.unicode() + oldpos, pos - oldpos);
00125 }
00126
00133 inline void ignoreWS(const QString &buf, int &pos) {
00134 int size = (int)buf.length();
00135 QChar ch = buf[pos];
00136 while (pos < size && (ch == ' ' || ch == '\t' || ch == '\n'
00137 || ch == '\r'))
00138 ch = buf[++pos];
00139 }
00140
00149 static QString parseQuotedString(const QString &buf, int &pos) {
00150 int size = (int)buf.length();
00151 QString res;
00152 pos++;
00153 bool escaped = false;
00154 bool parsing = true;
00155 while (parsing && pos < size) {
00156 QChar ch = buf[pos++];
00157 if (escaped) {
00158 res += ch;
00159 escaped = false;
00160 } else {
00161 switch (ch) {
00162 case '"': parsing = false; break;
00163 case '\\': escaped = true; break;
00164 default: res += ch; break;
00165 }
00166 }
00167 }
00168 return res;
00169 }
00170
00176 static void parseDataHeader(const KURL &url, DataHeader &header_info) {
00177 QConstString text_plain(text_plain_str,sizeof text_plain_str/sizeof text_plain_str[0]);
00178 QConstString charset(charset_str,sizeof charset_str/sizeof charset_str[0]);
00179 QConstString us_ascii(us_ascii_str,sizeof us_ascii_str/sizeof us_ascii_str[0]);
00180 QConstString base64(base64_str,sizeof base64_str/sizeof base64_str[0]);
00181
00182 header_info.mime_type = text_plain.string();
00183 header_info.charset = &header_info.attributes.insert(
00184 charset.string(),us_ascii.string())
00185 .data();
00186 header_info.is_base64 = false;
00187
00188
00189 QString &raw_url = header_info.url = QString::fromLatin1("data:") + url.path();
00190 int raw_url_len = (int)raw_url.length();
00191
00192
00193 header_info.data_offset = raw_url.find(':');
00194 header_info.data_offset++;
00195
00196
00197 if (header_info.data_offset >= raw_url_len) return;
00198 QString mime_type = extract(raw_url,header_info.data_offset,';',',')
00199 .stripWhiteSpace();
00200 if (!mime_type.isEmpty()) header_info.mime_type = mime_type;
00201
00202 if (header_info.data_offset >= raw_url_len) return;
00203
00204 if (raw_url[header_info.data_offset++] == ',') return;
00205
00206
00207 bool data_begin_reached = false;
00208 while (!data_begin_reached && header_info.data_offset < raw_url_len) {
00209
00210 QString attribute = extract(raw_url,header_info.data_offset,'=',';',',')
00211 .stripWhiteSpace();
00212 if (header_info.data_offset >= raw_url_len
00213 || raw_url[header_info.data_offset] != '=') {
00214
00215 if (attribute == base64.string())
00216 header_info.is_base64 = true;
00217 } else {
00218 header_info.data_offset++;
00219
00220
00221 ignoreWS(raw_url,header_info.data_offset);
00222 if (header_info.data_offset >= raw_url_len) return;
00223
00224 QString value;
00225 if (raw_url[header_info.data_offset] == '"') {
00226 value = parseQuotedString(raw_url,header_info.data_offset);
00227 ignoreWS(raw_url,header_info.data_offset);
00228 } else
00229 value = extract(raw_url,header_info.data_offset,';',',')
00230 .stripWhiteSpace();
00231
00232
00233 header_info.attributes[attribute.lower()] = value;
00234
00235 }
00236 if (header_info.data_offset < raw_url_len
00237 && raw_url[header_info.data_offset] == ',')
00238 data_begin_reached = true;
00239 header_info.data_offset++;
00240 }
00241 }
00242
00243 #ifdef DATAKIOSLAVE
00244 DataProtocol::DataProtocol(const QCString &pool_socket, const QCString &app_socket)
00245 : SlaveBase("kio_data", pool_socket, app_socket) {
00246 #else
00247 DataProtocol::DataProtocol() {
00248 #endif
00249 kdDebug() << "DataProtocol::DataProtocol()" << endl;
00250 }
00251
00252
00253
00254 DataProtocol::~DataProtocol() {
00255 kdDebug() << "DataProtocol::~DataProtocol()" << endl;
00256 }
00257
00258
00259
00260 void DataProtocol::get(const KURL& url) {
00261 ref();
00262
00263 kdDebug() << "kio_data@"<<this<<"::get(const KURL& url)" << endl ;
00264
00265 DataHeader hdr;
00266 parseDataHeader(url,hdr);
00267
00268 int size = (int)hdr.url.length();
00269 int data_ofs = QMIN(hdr.data_offset,size);
00270
00271 QString url_data = hdr.url.mid(data_ofs);
00272 QCString outData;
00273
00274 #ifdef TESTKIO
00275
00276 #endif
00277 if (hdr.is_base64) {
00278
00279
00280 KCodecs::base64Decode(url_data.local8Bit(),outData);
00281 } else {
00282
00283
00284 QTextCodec *codec = QTextCodec::codecForName(hdr.charset->latin1());
00285 if (codec != 0) {
00286 outData = codec->fromUnicode(url_data);
00287 } else {
00288
00289
00290 outData = url_data.local8Bit();
00291 }
00292 }
00293
00294
00295
00296 mimeType(hdr.mime_type);
00297
00298
00299 totalSize(outData.size());
00300
00301
00302
00303 #if defined(TESTKIO) || defined(DATAKIOSLAVE)
00304 MetaData::ConstIterator it;
00305 for (it = hdr.attributes.begin(); it != hdr.attributes.end(); ++it) {
00306 setMetaData(it.key(),it.data());
00307 }
00308 #else
00309 setAllMetaData(hdr.attributes);
00310 #endif
00311
00312
00313
00314 sendMetaData();
00315
00316
00317
00318 (data(outData));
00319
00320 DISPATCH(data(QByteArray()));
00321
00322 DISPATCH(finished());
00323
00324 deref();
00325 }
00326
00327
00328
00329 void DataProtocol::mimetype(const KURL &url) {
00330 ref();
00331 DataHeader hdr;
00332 parseDataHeader(url,hdr);
00333 mimeType(hdr.mime_type);
00334 finished();
00335 deref();
00336 }
00337
00338
00339