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 }