/* * Copyright (C) 2005-2009 MaNGOS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Common.h" #include "ByteBuffer.h" #include "WorldPacket.h" #include "UpdateData.h" #include "Log.h" #include "Opcodes.h" #include "World.h" #include UpdateData::UpdateData() : m_blockCount(0) { } void UpdateData::AddOutOfRangeGUID(std::set& guids) { m_outOfRangeGUIDs.insert(guids.begin(),guids.end()); } void UpdateData::AddOutOfRangeGUID(const uint64 &guid) { m_outOfRangeGUIDs.insert(guid); } void UpdateData::AddUpdateBlock(const ByteBuffer &block) { m_data.append(block); ++m_blockCount; } void UpdateData::Compress( uint8* dst, uint32 *dst_size, uint8* src, int src_size ) { z_stream c_stream; c_stream.zalloc = (alloc_func)0; c_stream.zfree = (free_func)0; c_stream.opaque = (voidpf)0; // default Z_BEST_SPEED (1) int z_res = deflateInit(&c_stream, sWorld.getConfig(CONFIG_COMPRESSION)); if (z_res != Z_OK) { sLog.outError("Can't compress update packet (zlib: deflateInit) Error code: %i (%s)",z_res,zError(z_res)); *dst_size = 0; return; } c_stream.next_out = (Bytef*)dst; c_stream.avail_out = *dst_size; c_stream.next_in = (Bytef*)src; c_stream.avail_in = (uInt)src_size; z_res = deflate(&c_stream, Z_NO_FLUSH); if (z_res != Z_OK) { sLog.outError("Can't compress update packet (zlib: deflate) Error code: %i (%s)",z_res,zError(z_res)); *dst_size = 0; return; } if (c_stream.avail_in != 0) { sLog.outError("Can't compress update packet (zlib: deflate not greedy)"); *dst_size = 0; return; } z_res = deflate(&c_stream, Z_FINISH); if (z_res != Z_STREAM_END) { sLog.outError("Can't compress update packet (zlib: deflate should report Z_STREAM_END instead %i (%s)",z_res,zError(z_res)); *dst_size = 0; return; } z_res = deflateEnd(&c_stream); if (z_res != Z_OK) { sLog.outError("Can't compress update packet (zlib: deflateEnd) Error code: %i (%s)",z_res,zError(z_res)); *dst_size = 0; return; } *dst_size = c_stream.total_out; } bool UpdateData::BuildPacket(WorldPacket *packet) { ASSERT(packet->empty()); // shouldn't happen ByteBuffer buf(m_outOfRangeGUIDs.empty() ? m_data.size() : 1 + 4 + m_outOfRangeGUIDs.size() * 9 + m_data.size()); // put update blocks count buf << uint32(m_outOfRangeGUIDs.empty() ? m_blockCount : m_blockCount + 1); if(m_outOfRangeGUIDs.empty()) { // put update data buf.append(m_data); } else { // put out of range GUID's buf << uint8(UPDATETYPE_OUT_OF_RANGE_OBJECTS); buf << uint32(m_outOfRangeGUIDs.size()); for(std::set::const_iterator i = m_outOfRangeGUIDs.begin(); i != m_outOfRangeGUIDs.end(); ++i) buf.appendPackGUID(*i); // put update data buf.append(m_data); } size_t pSize = buf.size(); if(pSize > 100) // compress large packets { packet->SetOpcode(SMSG_COMPRESSED_UPDATE_OBJECT); packet->resize(pSize + sizeof(uint32)); packet->put(0, pSize); // original size uint32 destsize = pSize; Compress((uint8*)packet->contents() + sizeof(uint32), &destsize, (uint8*)buf.contents(), pSize); packet->resize(destsize + sizeof(uint32)); // resize packet to compressed size + 4 } else // send small packets without compression { packet->SetOpcode(SMSG_UPDATE_OBJECT); packet->append(buf); } return true; } void UpdateData::Clear() { m_data.clear(); m_outOfRangeGUIDs.clear(); m_blockCount = 0; }