• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.9.5 API Reference
  • KDE Home
  • 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 <kurl.h>
00023 #include "global.h"
00024 #include <kglobal.h>
00025 
00026 #include <QtCore/QByteArray>
00027 #include <QtCore/QCharRef>
00028 #include <QtCore/QMutableStringListIterator>
00029 #include <QtCore/QTextCodec>
00030 
00031 #ifdef DATAKIOSLAVE
00032 #  include <kinstance.h>
00033 #  include <stdlib.h>
00034 #endif
00035 
00036 #if !defined(DATAKIOSLAVE)
00037 #  define DISPATCH(f) dispatch_##f
00038 #else
00039 #  define DISPATCH(f) f
00040 #endif
00041 
00042 using namespace KIO;
00043 #ifdef DATAKIOSLAVE
00044 extern "C" {
00045 
00046   int kdemain( int argc, char **argv ) {
00047     KComponentData componentData( "kio_data" );
00048 
00049     kDebug(7101) << "*** Starting kio_data ";
00050 
00051     if (argc != 4) {
00052       kDebug(7101) << "Usage: kio_data  protocol domain-socket1 domain-socket2";
00053       exit(-1);
00054     }
00055 
00056     DataProtocol slave(argv[2], argv[3]);
00057     slave.dispatchLoop();
00058 
00059     kDebug(7101) << "*** kio_data Done";
00060     return 0;
00061   }
00062 }
00063 #endif
00064 
00066 struct DataHeader {
00067   QString mime_type;        // mime type of content (lowercase)
00068   MetaData attributes;      // attribute/value pairs (attribute lowercase,
00069                 //  value unchanged)
00070   bool is_base64;       // true if data is base64 encoded
00071   QByteArray url;       // reference to decoded url
00072   int data_offset;      // zero-indexed position within url
00073                 // where the real data begins. May point beyond
00074                     // the end to indicate that there is no data
00075 };
00076 
00085 static int find(const QByteArray &buf, int begin, const char c1)
00086 {
00087   static const char comma = ',';
00088   static const char semicolon = ';';
00089   int pos = begin;
00090   int size = buf.length();
00091   while (pos < size) {
00092     const char ch = buf[pos];
00093     if (ch == comma || ch == semicolon || (c1 != '\0' && ch == c1))
00094       break;
00095     pos++;
00096   }/*wend*/
00097   return pos;
00098 }
00099 
00108 static inline QString extract(const QByteArray &buf, int &pos,
00109                               const char c1 = '\0')
00110 {
00111   int oldpos = pos;
00112   pos = find(buf, oldpos, c1);
00113   return buf.mid(oldpos, pos-oldpos);
00114 }
00115 
00122 static inline void ignoreWS(const QString &buf, int &pos)
00123 {
00124   int size = buf.length();
00125   while (pos < size && buf[pos].isSpace())
00126     ++pos;
00127 }
00128 
00137 static QString parseQuotedString(const QString &buf, int &pos) {
00138   int size = buf.length();
00139   QString res;
00140   res.reserve(size);    // can't be larger than buf
00141   pos++;        // jump over leading quote
00142   bool escaped = false; // if true means next character is literal
00143   bool parsing = true;  // true as long as end quote not found
00144   while (parsing && pos < size) {
00145     const QChar ch = buf[pos++];
00146     if (escaped) {
00147       res += ch;
00148       escaped = false;
00149     } else {
00150       switch (ch.unicode()) {
00151         case '"': parsing = false; break;
00152         case '\\': escaped = true; break;
00153         default: res += ch; break;
00154       }/*end switch*/
00155     }/*end if*/
00156   }/*wend*/
00157   res.squeeze();
00158   return res;
00159 }
00160 
00166 static DataHeader parseDataHeader(const KUrl &url, const bool mimeOnly)
00167 {
00168   static const QString& text_plain = KGlobal::staticQString("text/plain");
00169   static const QString& charset = KGlobal::staticQString("charset");
00170   static const QString& us_ascii = KGlobal::staticQString("us-ascii");
00171   static const QString& base64 = KGlobal::staticQString("base64");
00172 
00173   DataHeader header_info;
00174 
00175   // initialize header info members
00176   header_info.mime_type = text_plain;
00177   header_info.attributes.insert(charset, us_ascii);
00178   header_info.is_base64 = false;
00179 
00180   // decode url and save it
00181   const QByteArray &raw_url = header_info.url = QByteArray::fromPercentEncoding( url.encodedPath() );
00182   const int raw_url_len = raw_url.length();
00183 
00184   header_info.data_offset = 0;
00185 
00186   // read mime type
00187   if (raw_url_len == 0)
00188     return header_info;
00189   const QString mime_type = extract(raw_url, header_info.data_offset).trimmed();
00190   if (!mime_type.isEmpty()) header_info.mime_type = mime_type;
00191   if (mimeOnly)
00192       return header_info;
00193 
00194   if (header_info.data_offset >= raw_url_len)
00195       return header_info;
00196   // jump over delimiter token and return if data reached
00197   if (raw_url[header_info.data_offset++] == QLatin1Char(','))
00198       return header_info;
00199 
00200   // read all attributes and store them
00201   bool data_begin_reached = false;
00202   while (!data_begin_reached && header_info.data_offset < raw_url_len) {
00203     // read attribute
00204     const QString attribute = extract(raw_url, header_info.data_offset, '=').trimmed();
00205     if (header_info.data_offset >= raw_url_len
00206         || raw_url[header_info.data_offset] != QLatin1Char('=')) {
00207       // no assigment, must be base64 option
00208       if (attribute == base64)
00209         header_info.is_base64 = true;
00210     } else {
00211       header_info.data_offset++; // jump over '=' token
00212 
00213       // read value
00214       ignoreWS(raw_url,header_info.data_offset);
00215       if (header_info.data_offset >= raw_url_len)
00216           return header_info;
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).trimmed();
00224 
00225       // add attribute to map
00226       header_info.attributes[attribute.toLower()] = value;
00227 
00228     }/*end if*/
00229     if (header_info.data_offset < raw_url_len
00230     && raw_url[header_info.data_offset] == QLatin1Char(','))
00231       data_begin_reached = true;
00232     header_info.data_offset++; // jump over separator token
00233   }/*wend*/
00234 
00235   return header_info;
00236 }
00237 
00238 #ifdef DATAKIOSLAVE
00239 DataProtocol::DataProtocol(const QByteArray &pool_socket, const QByteArray &app_socket)
00240     : SlaveBase("kio_data", pool_socket, app_socket) {
00241 #else
00242 DataProtocol::DataProtocol() {
00243 #endif
00244   kDebug();
00245 }
00246 
00247 /* --------------------------------------------------------------------- */
00248 
00249 DataProtocol::~DataProtocol() {
00250   kDebug();
00251 }
00252 
00253 /* --------------------------------------------------------------------- */
00254 
00255 void DataProtocol::get(const KUrl& url) {
00256   ref();
00257   kDebug() << "kio_data@"<<this<<"::get(const KUrl& url)";
00258 
00259   const DataHeader hdr = parseDataHeader(url, false);
00260 
00261   const int size = hdr.url.length();
00262   const int data_ofs = qMin(hdr.data_offset, size);
00263   // FIXME: string is copied, would be nice if we could have a reference only
00264   const QByteArray 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);
00271   } else {
00272     QTextCodec *codec = QTextCodec::codecForName(hdr.attributes["charset"].toLatin1());
00273     if (codec != 0) {
00274       outData = codec->toUnicode(url_data).toUtf8();
00275     } else {
00276       outData = url_data;
00277     }/*end if*/
00278   }/*end if*/
00279 
00280   //kDebug() << "emit mimeType@"<<this;
00281   mimeType(hdr.mime_type);
00282   //kDebug() << "emit totalSize@"<<this;
00283   totalSize(outData.size());
00284 
00285   //kDebug() << "emit setMetaData@"<<this;
00286 #if defined(DATAKIOSLAVE)
00287   MetaData::ConstIterator it;
00288   for (it = hdr.attributes.constBegin(); it != hdr.attributes.constEnd(); ++it) {
00289     setMetaData(it.key(),it.value());
00290   }/*next it*/
00291 #else
00292   setAllMetaData(hdr.attributes);
00293 #endif
00294 
00295   //kDebug() << "emit sendMetaData@"<<this;
00296   sendMetaData();
00297 //   kDebug() << "(1) queue size " << dispatchQueue.size();
00298   // empiric studies have shown that this shouldn't be queued & dispatched
00299   data(outData);
00300 //   kDebug() << "(2) queue size " << dispatchQueue.size();
00301   DISPATCH(data(QByteArray()));
00302 //   kDebug() << "(3) queue size " << dispatchQueue.size();
00303   DISPATCH(finished());
00304 //   kDebug() << "(4) queue size " << dispatchQueue.size();
00305   deref();
00306 }
00307 
00308 /* --------------------------------------------------------------------- */
00309 
00310 void DataProtocol::mimetype(const KUrl &url) {
00311   ref();
00312   mimeType(parseDataHeader(url, true).mime_type);
00313   finished();
00314   deref();
00315 }
00316 
00317 /* --------------------------------------------------------------------- */
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:34:57 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

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

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal