00001 /* 00002 00003 Copyright (C) 2006-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 "BinaryWriter.h" 00025 #include "Imports.cpp" 00026 00028 BinaryWriter::BinaryWriter (QByteArray *buffer, bool autoGrow) 00029 : BinaryWriterBase (buffer, LittleEndian, autoGrow) 00030 { 00031 } 00032 00034 BinaryWriter::BinaryWriter (bool autoGrow) 00035 : BinaryWriterBase (LittleEndian, autoGrow) 00036 { 00037 } 00038 00040 00047 void BinaryWriter::writeUuid (const QUuid &uuid) 00048 { 00049 setByteOrder (BigEndian); 00050 writeUInt32 (uuid.data1); 00051 writeUInt16 (uuid.data2); 00052 writeUInt16 (uuid.data3); 00053 writeByte (uuid.data4[0]); 00054 writeByte (uuid.data4[1]); 00055 writeByte (uuid.data4[2]); 00056 writeByte (uuid.data4[3]); 00057 writeByte (uuid.data4[4]); 00058 writeByte (uuid.data4[5]); 00059 writeByte (uuid.data4[6]); 00060 writeByte (uuid.data4[7]); 00061 setByteOrder (LittleEndian); 00062 } 00063 00065 00070 void BinaryWriter::writeIPv4Address (const QHostAddress &address) 00071 { 00072 Q_ASSERT (address.protocol() == QAbstractSocket::IPv4Protocol 00073 || address.isNull()); 00074 setByteOrder (BigEndian); 00075 writeUInt32 (address.toIPv4Address()); 00076 setByteOrder (LittleEndian); 00077 } 00078 00080 00087 void BinaryWriter::writeGgepBlock (const GgepBlock &block) 00088 { 00089 using Extensions::Ggep; 00090 if (block.extensions().count() == 0) 00091 return; 00092 00093 writeByte (GgepBlock::MagicByte); 00094 const Ggep *lastExtension = block.extensions().last(); 00095 foreach (const Ggep* extension, block.extensions()) { 00096 writeGgepBlockExtensionHeader (extension, lastExtension); 00097 00098 QByteArray rawData (extension->rawData()); 00099 writeGgepBlockDataLength (rawData.length()); 00100 00101 writeBytes (rawData); 00102 } 00103 } 00104 00106 00109 void BinaryWriter::writeGgepBlockExtensionHeader (const Ggep *extension, 00110 const Ggep *lastExtension) 00111 { 00112 uchar flags = 0x00; 00113 if (extension->isFlagSet (Ggep::Compression)) 00114 flags |= Ggep::Compression; 00115 if (extension->isFlagSet (Ggep::Encoding)) 00116 flags |= Ggep::Encoding; 00117 if (extension == lastExtension) 00118 flags |= Ggep::LastExtension; 00119 flags |= extension->id().size(); 00120 00121 writeByte (static_cast <uchar> (flags)); // flags 00122 writeBytes (extension->id()); // ID 00123 } 00124 00126 00130 void BinaryWriter::writeGgepBlockDataLength (int length) 00131 { 00132 do { 00133 uchar byte = length & 0x3F; 00134 length >>= 6; 00135 byte |= (length > 0) ? 0x80 : 0x40; 00136 writeByte (byte); // length byte 00137 } while (length > 0); 00138 } 00139 00141 00144 void BinaryWriter::writeQueryData (const QueryData &data) 00145 { 00146 writeHugeGemBlock (data); 00147 } 00148 00150 00154 void BinaryWriter::writeMinSpeed (const MinSpeed &speed) 00155 { 00156 uchar flags = 0x80; 00157 00158 if(speed.isFirewalled) 00159 flags |= 0x40; 00160 if(speed.wantXmlMetadata) 00161 flags |= 0x20; 00162 if(speed.isLeafGuidedDynamicQuery) 00163 flags |= 0x10; 00164 if(speed.isAllowedGgepH) 00165 flags |= 0x08; 00166 if(speed.isOutOfBoundQuery) 00167 flags |= 0x04; 00168 00169 writeByte (flags); 00170 writeByte (speed.maxQueryHits); 00171 } 00172 00174 00177 void BinaryWriter::writeVendorCode (const VendorCode &code) 00178 { 00179 writeBytes (code.toBytes()); 00180 } 00181 00183 00190 void BinaryWriter::writeHugeGemBlock (const HugeGemBlock &block) 00191 { 00192 QList <QByteArray> extensions; 00193 00194 extensions += block.urnList; 00195 extensions += block.unknownList; 00196 extensions += block.xmlList; 00197 00198 if(block.ggepBlock.extensions().size() > 0) { 00199 BinaryWriter writer; 00200 writer.writeGgepBlock (block.ggepBlock); 00201 extensions += writer.buffer(); 00202 } 00203 00204 // Write the first extension and remove it from the list: 00205 if (!extensions.isEmpty()) 00206 writeBytes (extensions.takeFirst()); 00207 // Write further extensions, if any: 00208 foreach (const QByteArray extension, extensions) { 00209 writeByte ('\x1c'); 00210 writeBytes (extension); 00211 } 00212 } 00213 00215 00218 void BinaryWriter::writeQueryHitsData (const QueryHitsData &hitsData) 00219 { 00220 writeVendorCode (hitsData.vendorCode); 00221 00222 if(hitsData.xmlData.size() > 0) 00223 writeByte ('\x04'); 00224 else 00225 writeByte ('\x02'); 00226 00227 // Prepare the OpenAreaFlags: 00228 uchar flags1 = 0x3C; // Enable all known flags (except push): 00111100 00229 uchar flags2 = 0x01; // Enable the push flag here: 00000001 00230 // Set the corresponfing the bits if the field is set: 00231 if(hitsData.ggepBlock.extensions().count() > 0) flags2 |= 0x20; 00232 if(hitsData.flagUploadSpeed) flags2 |= 0x10; 00233 if(hitsData.flagHaveUploaded) flags2 |= 0x08; 00234 if(hitsData.flagBusy) flags2 |= 0x04; 00235 if(hitsData.flagPush) flags1 |= 0x01; 00236 // Write the flags: 00237 writeByte (flags1); 00238 writeByte (flags2); 00239 00240 // Write the xmlData length + 1 (for the ending zero byte): 00241 if(hitsData.xmlData.size() > 0) 00242 writeUInt16 (static_cast <quint16> (hitsData.xmlData.size() + 1)); 00243 00244 // Write any aditional private data: 00245 writeBytes (hitsData.privateVendor); 00246 00247 // Write the GGEP block: 00248 writeGgepBlock (hitsData.ggepBlock); 00249 00250 // Write the xmlData itself followed by a zero byte: 00251 if(hitsData.xmlData.size() > 0) { 00252 writeBytes (hitsData.xmlData); 00253 writeByte('\0'); 00254 } 00255 00256 // Finally write the serventId: 00257 writeUuid (hitsData.serventId); 00258 } 00259 00261 00264 void BinaryWriter::writeQueryHitsResultSet (const ResultSet &resultSet) 00265 { 00266 foreach(const Result result, resultSet) { 00267 writeUInt32 (result.fileIndex); 00268 writeUInt32 (result.fileSize); 00269 writeString (result.fullFileName.toUtf8()); 00270 writeHugeGemBlock (result.resultData); 00271 writeByte ('\0'); 00272 } 00273 }