kio Library API Documentation

dataprotocol.cpp

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 // (C) 2002, 2003 by Leo Savernik 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 <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; // mime type of content (lowercase) 00070 MetaData attributes; // attribute/value pairs (attribute lowercase, 00071 // value unchanged) 00072 bool is_base64; // true if data is base64 encoded 00073 QString url; // reference to decoded url 00074 int data_offset; // zero-indexed position within url 00075 // where the real data begins. May point beyond 00076 // the end to indicate that there is no data 00077 QString *charset; // shortcut to charset (it always exists) 00078 }; 00079 00080 // constant string data 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 }/*wend*/ 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++; // jump over leading quote 00152 bool escaped = false; // if true means next character is literal 00153 bool parsing = true; // true as long as end quote not found 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 }/*end switch*/ 00165 }/*end if*/ 00166 }/*wend*/ 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 // initialize header info members 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 // decode url and save it 00188 QString &raw_url = header_info.url = KURL::decode_string(url.url()); 00189 int raw_url_len = (int)raw_url.length(); 00190 00191 // jump over scheme part (must be "data:", we don't even check that) 00192 header_info.data_offset = raw_url.find(':'); 00193 header_info.data_offset++; // jump over colon or to begin if scheme was missing 00194 00195 // read mime type 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 // jump over delimiter token and return if data reached 00203 if (raw_url[header_info.data_offset++] == ',') return; 00204 00205 // read all attributes and store them 00206 bool data_begin_reached = false; 00207 while (!data_begin_reached && header_info.data_offset < raw_url_len) { 00208 // read attribute 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 // no assigment, must be base64 option 00214 if (attribute == base64.string()) 00215 header_info.is_base64 = true; 00216 } else { 00217 header_info.data_offset++; // jump over '=' token 00218 00219 // read value 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 // add attribute to map 00232 header_info.attributes[attribute.lower()] = value; 00233 00234 }/*end if*/ 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++; // jump over separator token 00239 }/*wend*/ 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 //kdDebug() << "===============================================================================================================================================================================" << endl; 00261 kdDebug() << "kio_data@"<<this<<"::get(const KURL& url)" << endl ; 00262 00263 DataHeader hdr; 00264 parseDataHeader(url,hdr); 00265 00266 int size = (int)hdr.url.length(); 00267 int data_ofs = QMIN(hdr.data_offset,size); 00268 // FIXME: string is copied, would be nice if we could have a reference only 00269 QString url_data = hdr.url.mid(data_ofs); 00270 QCString outData; 00271 00272 #ifdef TESTKIO 00273 // cout << "current charset: \"" << *hdr.charset << "\"" << endl; 00274 #endif 00275 if (hdr.is_base64) { 00276 // base64 stuff is expected to contain the correct charset, so we just 00277 // decode it and pass it to the receiver 00278 KCodecs::base64Decode(url_data.local8Bit(),outData); 00279 } else { 00280 // FIXME: This is all flawed, must be reworked thoroughly 00281 // non encoded data must be converted to the given charset 00282 QTextCodec *codec = QTextCodec::codecForName(hdr.charset->latin1()); 00283 if (codec != 0) { 00284 outData = codec->fromUnicode(url_data); 00285 } else { 00286 // if there is no approprate codec, just use local encoding. This 00287 // should work for >90% of all cases. 00288 outData = url_data.local8Bit(); 00289 }/*end if*/ 00290 }/*end if*/ 00291 00292 //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl; 00293 //kdDebug() << "emit mimeType@"<<this << endl ; 00294 mimeType(hdr.mime_type); 00295 //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl; 00296 //kdDebug() << "emit totalSize@"<<this << endl ; 00297 totalSize(outData.size()); 00298 00299 //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl; 00300 //kdDebug() << "emit setMetaData@"<<this << endl ; 00301 #if defined(TESTKIO) || defined(DATAKIOSLAVE) 00302 MetaData::ConstIterator it; 00303 for (it = hdr.attributes.begin(); it != hdr.attributes.end(); ++it) { 00304 setMetaData(it.key(),it.data()); 00305 }/*next it*/ 00306 #else 00307 setAllMetaData(hdr.attributes); 00308 #endif 00309 00310 //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl; 00311 //kdDebug() << "emit sendMetaData@"<<this << endl ; 00312 sendMetaData(); 00313 //kdDebug() << "^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C" << endl; 00314 //kdDebug() << "queue size " << dispatchQueue.size() << endl; 00315 // empiric studies have shown that this shouldn't be queued & dispatched 00316 /*DISPATCH*/(data(outData)); 00317 //kdDebug() << "queue size " << dispatchQueue.size() << endl; 00318 DISPATCH(data(QByteArray())); 00319 //kdDebug() << "queue size " << dispatchQueue.size() << endl; 00320 DISPATCH(finished()); 00321 //kdDebug() << "queue size " << dispatchQueue.size() << endl; 00322 } 00323 00324 /* --------------------------------------------------------------------- */ 00325 00326 void DataProtocol::mimetype(const KURL &url) { 00327 DataHeader hdr; 00328 parseDataHeader(url,hdr); 00329 mimeType(hdr.mime_type); 00330 finished(); 00331 } 00332 00333 /* --------------------------------------------------------------------- */ 00334
KDE Logo
This file is part of the documentation for kio Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:29:14 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003