/// <summary> /// Create an encoder with the target initial buffer size. /// </summary> /// <param name="compress">True to compress collated data.</param> /// <param name="initialBufferSize">The initial buffer size (bytes).</param> public CollatedPacketEncoder(bool compress, int initialBufferSize = 64 * 1024) { CollatedBytes = 0; _collationStream = _dataStream = new CompressionBuffer(initialBufferSize); _packet = new PacketBuffer(); // Prime the output stream, writing the initial header. PacketHeader header = PacketHeader.Create((ushort)RoutingID.CollatedPacket, 0); CollatedPacketMessage msg = new CollatedPacketMessage(); msg.Flags = (ushort)((compress) ? CollatedPacketFlag.GZipCompressed : 0u); msg.Reserved = 0; msg.UncompressedBytes = 0; NetworkWriter writer = new NetworkWriter(_dataStream); header.Write(writer); msg.Write(writer); _resetPosition = (int)_dataStream.Position; CompressionEnabled = compress; if (compress) { _collationStream = new GZipStream(_dataStream, CompressionMode.Compress, CompressionLevel.BestCompression); } }
/// <summary> /// Sets the packet to decode. /// </summary> /// <param name="packet"></param> /// <remarks> /// The <paramref name="packet"/> need not be a collated packet, in which case it will be /// immediately returned on calling <see cref="Next()"/>, followed by <code>null</code> /// </remarks> public bool SetPacket(PacketBuffer packet) { _packet = packet; _packetStream = null; _streamReader = null; // Check for a collated packet. if (_packet != null && _packet.Header.RoutingID == (ushort)RoutingID.CollatedPacket) { _packetStream = _packet.CreateReadStream(true); CollatedPacketMessage msg = new CollatedPacketMessage(); _streamReader = new NetworkReader(_packetStream); if (!msg.Read(_streamReader)) { return(false); } _targetBytes = msg.UncompressedBytes; _decodedBytes = 0; if ((msg.Flags & (ushort)CollatedPacketFlag.GZipCompressed) != 0) { _packetStream = new GZipStream(_packetStream, CompressionMode.Decompress); if (_packetStream != null) { _streamReader = new NetworkReader(_packetStream); } } } return(true); }
/// <summary> /// Finalise the collated packet before sending. /// </summary> /// <returns>True on successful finalisation, false if already finalised</returns> public bool FinaliseEncoding() { if (_finalised) { return(false); } bool compressionSuccess = false; if (CompressionEnabled) { // Compress the raw buffer into the compression buffer then validate it's smaller. _finalisedBuffer.Position = 0; // First write the standard header for this buffer. // Prime the output stream, writing the initial header. PacketHeader header = PacketHeader.Create((ushort)RoutingID.CollatedPacket, 0); CollatedPacketMessage msg = new CollatedPacketMessage(); msg.Flags = (ushort)CollatedPacketFlag.GZipCompressed; msg.Reserved = 0; msg.UncompressedBytes = 0; NetworkWriter writer = new NetworkWriter(_finalisedBuffer); header.Write(writer); msg.Write(writer); int overhead = (int)_finalisedBuffer.Position; // Now compress the collated packets. GZipStream compressionStream = new GZipStream(_finalisedBuffer, CompressionLevel.Fastest); compressionStream.Write(_collationBuffer.GetBuffer(), 0, (int)_collationBuffer.Position); compressionStream.Close(); if (_finalisedBuffer.Position < _collationBuffer.Position + overhead) { // The compressed data are smaller, so we accept it. SetPayloadSize((ushort)(Count - PacketHeader.Size)); // Update the payload and uncompressed sizes. SetUncompressedBytesSize((ushort)CollatedBytes); compressionSuccess = true; } } if (!compressionSuccess) { // No compression or compression failed to reduce the data size. Write header then copy wrap packets. PacketHeader header = PacketHeader.Create((ushort)RoutingID.CollatedPacket, 0); _finalisedBuffer.Position = 0; CollatedPacketMessage msg = new CollatedPacketMessage(); msg.Flags = 0; msg.Reserved = 0; msg.UncompressedBytes = 0; NetworkWriter writer = new NetworkWriter(_finalisedBuffer); header.Write(writer); msg.Write(writer); _finalisedBuffer.Write(_collationBuffer.GetBuffer(), 0, (int)_collationBuffer.Position); // The compressed data are smaller, so we accept it. SetPayloadSize((ushort)(Count - PacketHeader.Size)); // Update the payload and uncompressed sizes. SetUncompressedBytesSize((ushort)CollatedBytes); } // Calculate the CRC ushort crc = Crc16.Crc.Calculate(_finalisedBuffer.GetBuffer(), (uint)_finalisedBuffer.Position); new NetworkWriter(_finalisedBuffer).Write(crc); _finalised = true; return(true); }
public void Run() { int infoSearchPacketLimit = 10; // Don't look for info packets beyond this packet count. Should be first up. PacketBuffer packetBuffer = new PacketBuffer(4 * 1024); PacketStreamReader packetStream = new PacketStreamReader(new FileStream(TargetFile, FileMode.Open, FileAccess.Read)); Console.CancelKeyPress += new ConsoleCancelEventHandler(ControlCHandler); Console.WriteLine(string.Format("Reading {0}", TargetFile)); PacketBuffer packet = null; long bytesRead = 0; bool foundFrameCount = false; bool foundServerInfo = false; while (!Quit && !packetStream.EndOfStream) { Log.Flush(); packet = packetStream.NextPacket(ref bytesRead); if (packet == null) { if (!packetStream.EndOfStream) { Console.Error.WriteLine(string.Format("Null packet at {0}:{1}", _actualFrameCount, _packetCount)); } continue; } if (packet.Status == PacketBufferStatus.Complete) { ++_packetCount; //Console.WriteLine("Msg: {0} {1}", completedPacket.Header.RoutingID, completedPacket.Header.MessageID); switch (packet.Header.RoutingID) { case (ushort)RoutingID.Control: switch (packet.Header.MessageID) { case (ushort)ControlMessageID.EndFrame: ++_actualFrameCount; break; case (ushort)ControlMessageID.FrameCount: if (foundFrameCount) { Console.Error.WriteLine(string.Format("Found additional FrameCount message at frame {0}:{1}", _actualFrameCount, _packetCount)); } else { _frameCountPacketNumber = _packetCount; } HandleFrameCount(packet); foundFrameCount = true; break; } break; case (ushort)RoutingID.ServerInfo: if (foundServerInfo) { Console.Error.WriteLine(string.Format("Found additional ServerInfo message at frame {0}:{1}", _actualFrameCount, _packetCount)); } else { _serverInfoPacket = _packetCount; } HandleServerInfo(packet); foundServerInfo = true; break; } } else { Console.Error.WriteLine(string.Format("Invalid packet static at {0}:{1}", _actualFrameCount, _packetCount)); Console.Error.WriteLine(string.Format("Invalid packet status is {0} ({1})", packet.Status.ToString(), (int)packet.Status));; if (packet.Header.RoutingID == (ushort)RoutingID.CollatedPacket && packet.Header.PayloadSize > 0) { NetworkReader packetReader = new NetworkReader(packet.CreateReadStream(true)); CollatedPacketMessage msg = new CollatedPacketMessage(); if (msg.Read(packetReader)) { Console.WriteLine(string.Format("Failed collated packet message:")); Console.WriteLine(string.Format(" Flags: {0}", msg.Flags)); Console.WriteLine(string.Format(" Reserved: {0}", msg.Reserved)); Console.WriteLine(string.Format(" UncompressedBytes: {0}", msg.UncompressedBytes)); Console.WriteLine(string.Format(" PacketSize: {0}", packet.Header.PacketSize)); } } } } if (!Decode) { if (foundServerInfo && foundFrameCount) { Quit = true; } } if (_packetCount >= infoSearchPacketLimit) { if (!foundServerInfo) { Quit = true; Console.Error.WriteLine(string.Format("Failed to locate ServerInfo packet within {0} packets.", infoSearchPacketLimit)); } if (!foundFrameCount) { Quit = true; Console.Error.WriteLine(string.Format("Failed to locate FrameCount packet within {0} packets.", infoSearchPacketLimit)); } } Console.WriteLine(string.Format("Processed {0} packets{1}\n", _packetCount, Decode ? "" : " (info only)")); if (Decode) { if (_reportedFrameCount != _actualFrameCount) { Console.Error.WriteLine(string.Format("Frame count mismatch. Expected {0}, processed {1}", _reportedFrameCount, _actualFrameCount)); } } }