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.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Mar 3 19:23:37 2005 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003