• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

dataprotocol.cpp

Go to the documentation of this file.
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 // Copyright (C) 2002, 2003 by Leo Savernik <l.savernik@aon.at>
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 <kcodecs.h>
00023 #include <kurl.h>
00024 #include "global.h"
00025 #include <kglobal.h>
00026 
00027 #include <QtCore/QByteArray>
00028 #include <QtCore/QCharRef>
00029 #include <QtCore/QMutableStringListIterator>
00030 #include <QtCore/QTextCodec>
00031 
00032 #ifdef DATAKIOSLAVE
00033 #  include <kinstance.h>
00034 #  include <stdlib.h>
00035 #endif
00036 
00037 #if !defined(DATAKIOSLAVE) && !defined(TESTKIO)
00038 #  define DISPATCH(f) dispatch_##f
00039 #else
00040 #  define DISPATCH(f) f
00041 #endif
00042 
00043 using namespace KIO;
00044 #ifdef DATAKIOSLAVE
00045 extern "C" {
00046 
00047   int kdemain( int argc, char **argv ) {
00048     KComponentData componentData( "kio_data" );
00049 
00050     kDebug(7101) << "*** Starting kio_data ";
00051 
00052     if (argc != 4) {
00053       kDebug(7101) << "Usage: kio_data  protocol domain-socket1 domain-socket2";
00054       exit(-1);
00055     }
00056 
00057     DataProtocol slave(argv[2], argv[3]);
00058     slave.dispatchLoop();
00059 
00060     kDebug(7101) << "*** kio_data Done";
00061     return 0;
00062   }
00063 }
00064 #endif
00065 
00067 struct DataHeader {
00068   QString mime_type;        // mime type of content (lowercase)
00069   MetaData attributes;      // attribute/value pairs (attribute lowercase,
00070                 //  value unchanged)
00071   bool is_base64;       // true if data is base64 encoded
00072   QString url;          // reference to decoded url
00073   int data_offset;      // zero-indexed position within url
00074                 // where the real data begins. May point beyond
00075                     // the end to indicate that there is no data
00076   QString charset;      // shortcut to charset (it always exists)
00077 };
00078 
00088 static int find(const QString &buf, int begin, QChar c1,
00089         QChar c2 = QLatin1Char('\0'), QChar c3 = QLatin1Char('\0')) {
00090   int pos = begin;
00091   int size = buf.length();
00092   while (pos < size) {
00093     QChar ch = buf[pos];
00094     if (ch == c1
00095         || (c2 != QLatin1Char('\0') && ch == c2)
00096     || (c3 != QLatin1Char('\0') && ch == c3))
00097       break;
00098     pos++;
00099   }/*wend*/
00100   return pos;
00101 }
00102 
00113 inline QString extract(const QString &buf, int &pos, QChar c1,
00114         QChar c2 = QLatin1Char('\0'), QChar c3 = QLatin1Char('\0')) {
00115   int oldpos = pos;
00116   pos = find(buf,oldpos,c1,c2,c3);
00117   return buf.mid(oldpos, pos-oldpos);
00118 }
00119 
00126 inline void ignoreWS(const QString &buf, int &pos) {
00127   int size = buf.length();
00128   QChar ch = buf[pos];
00129   while (pos < size && ch.isSpace())
00130     ch = buf[++pos];
00131 }
00132 
00141 static QString parseQuotedString(const QString &buf, int &pos) {
00142   int size = buf.length();
00143   QString res;
00144   res.reserve(size);    // can't be larger than buf
00145   pos++;        // jump over leading quote
00146   bool escaped = false; // if true means next character is literal
00147   bool parsing = true;  // true as long as end quote not found
00148   while (parsing && pos < size) {
00149     QChar ch = buf[pos++];
00150     if (escaped) {
00151       res += ch;
00152       escaped = false;
00153     } else {
00154       switch (ch.unicode()) {
00155         case '"': parsing = false; break;
00156         case '\\': escaped = true; break;
00157         default: res += ch; break;
00158       }/*end switch*/
00159     }/*end if*/
00160   }/*wend*/
00161   res.squeeze();
00162   return res;
00163 }
00164 
00170 static void parseDataHeader(const KUrl &url, DataHeader &header_info) {
00171   static const QString& text_plain = KGlobal::staticQString("text/plain");
00172   static const QString& charset = KGlobal::staticQString("charset");
00173   static const QString& us_ascii = KGlobal::staticQString("us-ascii");
00174   static const QString& base64 = KGlobal::staticQString("base64");
00175 
00176   // initialize header info members
00177   header_info.mime_type = text_plain;
00178   header_info.charset = header_info.attributes.insert(charset,us_ascii).value();
00179   header_info.is_base64 = false;
00180 
00181   // decode url and save it
00182   QString &raw_url = header_info.url = QUrl::fromPercentEncoding( url.url().toLatin1() );
00183   int raw_url_len = raw_url.length();
00184 
00185   // jump over scheme part (must be "data:", we don't even check that)
00186   header_info.data_offset = raw_url.indexOf(QLatin1Char(':'));
00187   header_info.data_offset++;    // jump over colon or to begin if scheme was missing
00188 
00189   // read mime type
00190   if (header_info.data_offset >= raw_url_len) return;
00191   QString mime_type = extract(raw_url, header_info.data_offset,
00192                   QLatin1Char(';'), QLatin1Char(',')).trimmed();
00193   if (!mime_type.isEmpty()) header_info.mime_type = mime_type;
00194 
00195   if (header_info.data_offset >= raw_url_len) return;
00196   // jump over delimiter token and return if data reached
00197   if (raw_url[header_info.data_offset++] == QLatin1Char(',')) return;
00198 
00199   // read all attributes and store them
00200   bool data_begin_reached = false;
00201   while (!data_begin_reached && header_info.data_offset < raw_url_len) {
00202     // read attribute
00203     QString attribute = extract(raw_url, header_info.data_offset,
00204                     QLatin1Char('='), QLatin1Char(';'),
00205                 QLatin1Char(',')).trimmed();
00206     if (header_info.data_offset >= raw_url_len
00207         || raw_url[header_info.data_offset] != QLatin1Char('=')) {
00208       // no assigment, must be base64 option
00209       if (attribute == base64)
00210         header_info.is_base64 = true;
00211     } else {
00212       header_info.data_offset++; // jump over '=' token
00213 
00214       // read value
00215       ignoreWS(raw_url,header_info.data_offset);
00216       if (header_info.data_offset >= raw_url_len) return;
00217 
00218       QString value;
00219       if (raw_url[header_info.data_offset] == QLatin1Char('"')) {
00220         value = parseQuotedString(raw_url,header_info.data_offset);
00221         ignoreWS(raw_url,header_info.data_offset);
00222       } else
00223         value = extract(raw_url, header_info.data_offset, QLatin1Char(';'),
00224             QLatin1Char(',')).trimmed();
00225 
00226       // add attribute to map
00227       header_info.attributes[attribute.toLower()] = value;
00228 
00229     }/*end if*/
00230     if (header_info.data_offset < raw_url_len
00231     && raw_url[header_info.data_offset] == QLatin1Char(','))
00232       data_begin_reached = true;
00233     header_info.data_offset++; // jump over separator token
00234   }/*wend*/
00235 }
00236 
00237 #ifdef DATAKIOSLAVE
00238 DataProtocol::DataProtocol(const QByteArray &pool_socket, const QByteArray &app_socket)
00239     : SlaveBase("kio_data", pool_socket, app_socket) {
00240 #else
00241 DataProtocol::DataProtocol() {
00242 #endif
00243   kDebug();
00244 }
00245 
00246 /* --------------------------------------------------------------------- */
00247 
00248 DataProtocol::~DataProtocol() {
00249   kDebug();
00250 }
00251 
00252 /* --------------------------------------------------------------------- */
00253 
00254 void DataProtocol::get(const KUrl& url) {
00255   ref();
00256   kDebug() << "kio_data@"<<this<<"::get(const KUrl& url)";
00257 
00258   DataHeader hdr;
00259   parseDataHeader(url,hdr);
00260 
00261   int size = hdr.url.length();
00262   int data_ofs = qMin(hdr.data_offset,size);
00263   // FIXME: string is copied, would be nice if we could have a reference only
00264   QString url_data = hdr.url.mid(data_ofs);
00265   QByteArray outData;
00266 
00267   if (hdr.is_base64) {
00268     // base64 stuff is expected to contain the correct charset, so we just
00269     // decode it and pass it to the receiver
00270     outData = QByteArray::fromBase64(url_data.toUtf8());
00271   } else {
00272     // FIXME: This is all flawed, must be reworked thoroughly
00273     // non encoded data must be converted to the given charset
00274     QTextCodec *codec = QTextCodec::codecForName(hdr.charset.toLatin1());
00275     if (codec != 0) {
00276       outData = codec->fromUnicode(url_data);
00277     } else {
00278       // if there is no approprate codec, just use local encoding. This
00279       // should work for >90% of all cases.
00280       outData = url_data.toLocal8Bit();
00281     }/*end if*/
00282   }/*end if*/
00283 
00284   //kDebug() << "emit mimeType@"<<this;
00285   mimeType(hdr.mime_type);
00286   //kDebug() << "emit totalSize@"<<this;
00287   totalSize(outData.size());
00288 
00289   //kDebug() << "emit setMetaData@"<<this;
00290 #if defined(TESTKIO) || defined(DATAKIOSLAVE)
00291   MetaData::ConstIterator it;
00292   for (it = hdr.attributes.begin(); it != hdr.attributes.end(); ++it) {
00293     setMetaData(it.key(),it.value());
00294   }/*next it*/
00295 #else
00296   setAllMetaData(hdr.attributes);
00297 #endif
00298 
00299   //kDebug() << "emit sendMetaData@"<<this;
00300   sendMetaData();
00301 //   kDebug() << "(1) queue size " << dispatchQueue.size();
00302   // empiric studies have shown that this shouldn't be queued & dispatched
00303   data(outData);
00304 //   kDebug() << "(2) queue size " << dispatchQueue.size();
00305   DISPATCH(data(QByteArray()));
00306 //   kDebug() << "(3) queue size " << dispatchQueue.size();
00307   DISPATCH(finished());
00308 //   kDebug() << "(4) queue size " << dispatchQueue.size();
00309   deref();
00310 }
00311 
00312 /* --------------------------------------------------------------------- */
00313 
00314 void DataProtocol::mimetype(const KUrl &url) {
00315   ref();
00316   DataHeader hdr;
00317   parseDataHeader(url,hdr);
00318   mimeType(hdr.mime_type);
00319   finished();
00320   deref();
00321 }
00322 
00323 /* --------------------------------------------------------------------- */

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal