/// <summary> /// Decode a trie-based encoded message. /// </summary> /// <param name="encoded">the encoded bytes</param> /// <returns>the decoded bytes</returns> public byte[] Decode(byte[] encoded) { MemoryStream input = new MemoryStream(encoded); MemoryStream result = new MemoryStream(encoded.Length); IList<byte> missingAnnouncements = new List<byte>(); int b; while ((b = input.ReadByte()) >= 0) { switch(b) { case EscapeSingleCharacter: result.WriteByte((byte)input.ReadByte()); break; case EscapeMultipleCharacterSequence: uint length = ByteUtils.DecodeLength(input); while (length-- > 0 && input.Position < input.Length) { result.WriteByte((byte)input.ReadByte()); } break; //case EscapeDictionaryAnnouncement: // byte shortForm = (byte)input.ReadByte(); // int longForm = ByteUtils.DecodeLength(input); // HandleAnnouncement(longForm, shortForm); // if (inverseShortcuts[shortForm] != 0) // { // byte[] decoded = decodingTable[inverseShortcuts[shortForm]]; // result.Write(decoded, 0, decoded.Length); // } // else // { // missingAnnouncements.Add((byte)shortForm); // } // break; default: if(inverseShortcuts[b] != 0) { byte[] decoded = decodingTable[(int)inverseShortcuts[b]]; result.Write(decoded, 0, decoded.Length); } else { missingAnnouncements.Add((byte)b); } break; } } if (missingAnnouncements.Count > 0) { MissingInformationException mcce = new MissingInformationException(); mcce.Template = templateId; //mcce.UserID = userId; mcce.IDs = missingAnnouncements; mcce.ExceptionType = EnumExceptionType.MissingAnnouncement; throw mcce; } return result.ToArray(); }
/// <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> /// Decode the provided message using the specified template /// </summary> /// <param name="cmp">the message package to be decompressed</param> /// <param name="userId">the user from which the encoded message was received</param> /// <returns>The decoded (uncompressed) message</returns> public byte[] Decode(CompressedMessagePackage cmp, int userId) { if (cmp.Template != null) { AddTemplate(cmp.Template, cmp.TemplateId); } if (cmp.TemplateId < 0 || cmp.TemplateId > compressors.Count) { MissingInformationException mte = new MissingInformationException(); mte.Template = cmp.TemplateId; mte.UserID = userId; mte.ExceptionType = EnumExceptionType.MissingTemplate; throw mte; } return compressors[cmp.TemplateId].Decode(cmp); }