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   
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   
00269   QString url_data = hdr.url.mid(data_ofs);
00270   QCString outData;
00271 
00272 #ifdef TESTKIO
00273 
00274 #endif
00275   if (hdr.is_base64) {
00276     
00277     
00278     KCodecs::base64Decode(url_data.local8Bit(),outData);
00279   } else {
00280     
00281     
00282     QTextCodec *codec = QTextCodec::codecForName(hdr.charset->latin1());
00283     if (codec != 0) {
00284       outData = codec->fromUnicode(url_data);
00285     } else {
00286       
00287       
00288       outData = url_data.local8Bit();
00289     }
00290   }
00291 
00292   
00293   
00294   mimeType(hdr.mime_type);
00295   
00296   
00297   totalSize(outData.size());
00298 
00299   
00300   
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   }
00306 #else
00307   setAllMetaData(hdr.attributes);
00308 #endif
00309 
00310   
00311   
00312   sendMetaData();
00313   
00314   
00315   
00316   (data(outData));
00317   
00318   DISPATCH(data(QByteArray()));
00319   
00320   DISPATCH(finished());
00321   
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