ExtensionBlock.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2005-2007 by Peter Dimov.
00004 
00005 This file is part of Calitko (http://www.calitko.org).
00006 
00007 Calitko is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 Calitko is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Calitko; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 */
00022 
00023 #include "Qt.h"
00024 #include "ExtensionBlock.h"
00025 #include "Extension.h"
00026 #include "GgepBlock.h"
00027 #include "Xml.h"
00028 #include "Urn.h"
00029 #include "UnknownExtension.h"
00030 
00031 using namespace Gnutella::Packets::Extensions;
00032 
00033 ExtensionBlock::ExtensionBlock()
00034 {
00035 }
00036 
00037 ExtensionBlock::ExtensionBlock (const ExtensionBlock &block)
00038 {
00039     foreach (const Extension *extension, block.extensions_)
00040         addExtension (*extension);
00041 }
00042 
00043 ExtensionBlock& ExtensionBlock::operator= (const ExtensionBlock &block)
00044 {
00045     if (this == &block)
00046         return *this;
00047 
00048     foreach (const Extension *extension, extensions_)
00049         delete extension;
00050 
00051     extensions_.clear();
00052     foreach (const Extension *extension, block.extensions_)
00053         addExtension (*extension);
00054 
00055     return *this;
00056 }
00057 
00058 ExtensionBlock::~ExtensionBlock()
00059 {
00060     deleteExtensions();
00061 }
00062 
00063 void ExtensionBlock::deleteExtensions()
00064 {
00065     foreach (const Extension *extension, extensions_)
00066         delete extension;
00067     extensions_.clear();
00068 }
00069 
00070 void ExtensionBlock::addExtension (const Extension &extension)
00071 {
00072     extensions_.append (extension.copy());
00073 }
00074 
00075 ExtensionBlock::Extensions ExtensionBlock::extensions() const
00076 {
00077     return extensions_;
00078 }
00079 
00081 
00106 bool ExtensionBlock::prepareRead (const QByteArray &rawData)
00107 {
00108     deleteExtensions();
00109 
00110     if (rawData.size() == 0)
00111         return true;
00112 
00113     int rawDataLength = rawData.length();
00114     int currentPos = 0;
00115     while (currentPos < rawDataLength) {
00116         QByteArray rawExtensionData = QByteArray::fromRawData (rawData.data() + currentPos, rawDataLength - currentPos);
00117         Extension *extension = 0;
00118 
00119         switch (rawData[currentPos])
00120         {
00121         case Xml::StartByte:
00122             extension = new Xml;
00123             break;
00124         case Urn::StartByte:
00125             extension = new Urn;
00126             break;
00127         case GgepBlock::MagicByte:
00128             extension = new GgepBlock;
00129             break;
00130         default:
00131             extension = new UnknownExtension;
00132         }
00133         int extensionLength = extension->prepareRead (rawExtensionData);
00134         /*  There is no way to recover if we fail to parse an extension, so
00135             just treat the rest as an unknown extension. The same is true when
00136             we do not find the ExtensionSeparator after the last read extension.
00137         */
00138         if (extensionLength == 0
00139             || (currentPos + extensionLength < rawDataLength
00140                 && rawData[currentPos + extensionLength] != ExtensionSeparator)) {
00141             delete extension;
00142             extension = new UnknownExtension();
00143             extensionLength = extension->prepareRead (rawExtensionData);
00144         }
00145         extensions_.append (extension);
00146         currentPos += extensionLength;
00147         if (currentPos < rawDataLength)
00148             currentPos++; // ExtensionSeparator is only there BETWEEN extensions. Never at the end.
00149     }
00150     return true;
00151 }
00152 
00153 void ExtensionBlock::read (QDataStream &stream)
00154 {
00155     bool isFirst = true;
00156     foreach (const Extension *extension, extensions_) {
00157         uchar tmp;
00158         if (isFirst)
00159             isFirst = false;
00160         else
00161             stream >> tmp; // Read out the ExtensionSeparator
00162         const_cast <Extension *> (extension)->read (stream);
00163     }
00164 }
00165 
00166 int ExtensionBlock::prepareWrite() const
00167 {
00168     int totalLength = 0;
00169     foreach (const Extension *extension, extensions_)
00170         totalLength += extension->prepareWrite() + 1; // Extension followed by ExtensionSeparator.
00171 
00172     // There is no ExtensionSeparator after the last extension.
00173     if (totalLength > 0)
00174         totalLength--;
00175 
00176     return totalLength;
00177 }
00178 
00179 void ExtensionBlock::write (QDataStream &stream) const
00180 {
00181     bool isFirst = true;
00182     foreach (const Extension *extension, extensions_) {
00183         if (isFirst)
00184             isFirst = false;
00185         else
00186             stream << static_cast <uchar> (ExtensionSeparator);
00187         extension->write (stream);
00188     }
00189 }