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