/// <summary> /// Decode the provided byte array received from the user with unique /// identity <c>userId</c>. /// </summary> /// <param name="userId">the unique identity for the user</param> /// <param name="encodedBytes">the encoded message received</param> /// <returns></returns> public byte[] Decode(int userId, byte[] encodedBytes) { log.Trace("\n>>>> DECODING <<<<<"); Stream input = TryInflating(encodedBytes); CompressedMessagePackage cmp = new CompressedMessagePackage(); cmp.TemplateId = (short)ByteUtils.DecodeLength(input); log.Trace(String.Format("==> Decoding with template {0}", cmp.TemplateId)); int inputValue; while((inputValue = input.ReadByte()) != -1) { switch ((GMCMessageKey)inputValue) { case GMCMessageKey.Huffed: cmp.Huffed = true; break; case GMCMessageKey.NotHuffed: cmp.Huffed = false; break; case GMCMessageKey.Template: cmp.Template = DecodeTemplate(input); if (log.IsTraceEnabled) { log.Trace(String.Format("TID={0}: Decoded template: {1}", cmp.TemplateId, ByteUtils.DumpBytes(cmp.Template))); } break; case GMCMessageKey.HuffmanFrequencyTable: cmp.FrequencyTable = DecodeFrequencies(input); log.Trace(String.Format("TID={0}: Decoded huffman frequencies", cmp.TemplateId)); break; case GMCMessageKey.Announcements: cmp.Announcements = DecodeAnnouncements(input); if (log.IsTraceEnabled) { StringBuilder message = new StringBuilder(); message.Append(String.Format("TID={0}: Decoded {1} dictionary announcements:", cmp.TemplateId, cmp.Announcements.Count)); foreach(KeyValuePair<uint, byte> kvp in cmp.Announcements) { message.Append(' '); message.Append(kvp.Key); message.Append("->"); message.Append(kvp.Value); } log.Trace(message); } break; case GMCMessageKey.Message: uint len = ByteUtils.DecodeLength(input); cmp.Message = new byte[len]; input.Read(cmp.Message, 0, (int)len); if (log.IsTraceEnabled) { log.Trace(String.Format("Decoded message: {0}", ByteUtils.DumpBytes(cmp.Message))); } break; default: log.Trace("Invalid GMC message"); throw new MarshallingException("invalid GMC message"); } } GeneralMessageCompressor handler; if (!decompressors.TryGetValue(userId, out handler)) { if (cmp.Template == null) { //we haven't received any templates whatsoever from this person. MissingInformationException mte = new MissingInformationException(); mte.Template = 0; mte.UserID = userId; mte.ExceptionType = EnumExceptionType.MissingTemplate; throw mte; } handler = decompressors[userId] = new GeneralMessageCompressor(); } return handler.Decode(cmp, userId); }
/// <summary>Creates a new instance of GMC. /// Typically GMC will function as a singleton for each client, /// however, there are cases where the designer may wish to have a variety of GMCS.</summary> /// <param name="subMrshlr">the submarshaller to use for marshalling objects to bytes.</param> public GMCMarshaller(IMarshaller subMrshlr) { log = LogManager.GetLogger(GetType()); subMarshaller = subMrshlr; compressor = new GeneralMessageCompressor(); decompressors = new Dictionary<int, GeneralMessageCompressor>(); }