# kio Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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 <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;        // mime type of content (lowercase)
    00071   MetaData attributes;      // attribute/value pairs (attribute lowercase,
    00072                 //  value unchanged)
    00073   bool is_base64;       // true if data is base64 encoded
    00074   QString url;          // reference to decoded url
    00075   int data_offset;      // zero-indexed position within url
    00076                 // where the real data begins. May point beyond
    00077                     // the end to indicate that there is no data
    00078   QString *charset;     // shortcut to charset (it always exists)
    00079 };
    00080
    00081 // constant string data
    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   }/*wend*/
    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++;        // jump over leading quote
    00153   bool escaped = false; // if true means next character is literal
    00154   bool parsing = true;  // true as long as end quote not found
    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       }/*end switch*/
    00166     }/*end if*/
    00167   }/*wend*/
    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   // initialize header info members
    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   // decode url and save it
    00189   QString &raw_url = header_info.url = KURL::decode_string(url.url());
    00190   int raw_url_len = (int)raw_url.length();
    00191
    00192   // jump over scheme part (must be "data:", we don't even check that)
    00193   header_info.data_offset = raw_url.find(':');
    00194   header_info.data_offset++;    // jump over colon or to begin if scheme was missing
    00195
    00196   // read mime type
    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   // jump over delimiter token and return if data reached
    00204   if (raw_url[header_info.data_offset++] == ',') return;
    00205
    00206   // read all attributes and store them
    00207   bool data_begin_reached = false;
    00208   while (!data_begin_reached && header_info.data_offset < raw_url_len) {
    00209     // read attribute
    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       // no assigment, must be base64 option
    00215       if (attribute == base64.string())
    00216         header_info.is_base64 = true;
    00217     } else {
    00218       header_info.data_offset++; // jump over '=' token
    00219
    00220       // read value
    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       // add attribute to map
    00233       header_info.attributes[attribute.lower()] = value;
    00234
    00235     }/*end if*/
    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++; // jump over separator token
    00240   }/*wend*/
    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   //kdDebug() << "===============================================================================================================================================================================" << endl;
    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   // FIXME: string is copied, would be nice if we could have a reference only
    00271   QString url_data = hdr.url.mid(data_ofs);
    00272   QCString outData;
    00273
    00274 #ifdef TESTKIO
    00275 //  cout << "current charset: \"" << *hdr.charset << "\"" << endl;
    00276 #endif
    00277   if (hdr.is_base64) {
    00278     // base64 stuff is expected to contain the correct charset, so we just
    00279     // decode it and pass it to the receiver
    00280     KCodecs::base64Decode(url_data.local8Bit(),outData);
    00281   } else {
    00282     // FIXME: This is all flawed, must be reworked thoroughly
    00283     // non encoded data must be converted to the given charset
    00284     QTextCodec *codec = QTextCodec::codecForName(hdr.charset->latin1());
    00285     if (codec != 0) {
    00286       outData = codec->fromUnicode(url_data);
    00287     } else {
    00288       // if there is no approprate codec, just use local encoding. This
    00289       // should work for >90% of all cases.
    00290       outData = url_data.local8Bit();
    00291     }/*end if*/
    00292   }/*end if*/
    00293
    00294   //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
    00295   //kdDebug() << "emit mimeType@"<<this << endl ;
    00296   mimeType(hdr.mime_type);
    00297   //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
    00298   //kdDebug() << "emit totalSize@"<<this << endl ;
    00299   totalSize(outData.size());
    00300
    00301   //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
    00302   //kdDebug() << "emit setMetaData@"<<this << endl ;
    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   }/*next it*/
    00308 #else
    00309   setAllMetaData(hdr.attributes);
    00310 #endif
    00311
    00312   //kdDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
    00313   //kdDebug() << "emit sendMetaData@"<<this << endl ;
    00314   sendMetaData();
    00315   //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;
    00316 //   kdDebug() << "(1) queue size " << dispatchQueue.size() << endl;
    00317   // empiric studies have shown that this shouldn't be queued & dispatched
    00318   /*DISPATCH*/(data(outData));
    00319 //   kdDebug() << "(2) queue size " << dispatchQueue.size() << endl;
    00320   DISPATCH(data(QByteArray()));
    00321 //   kdDebug() << "(3) queue size " << dispatchQueue.size() << endl;
    00322   DISPATCH(finished());
    00323 //   kdDebug() << "(4) queue size " << dispatchQueue.size() << endl;
    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

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:23:52 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003