public CompressedMessagePackage Encode(byte[] message)
        {
            NoteTemplateUse();

            CompressedMessagePackage cmp = new CompressedMessagePackage();
            cmp.TemplateId = templateId;

            // Encode with the trie compressor -- compress repeated sequences
            byte[] encoded = tc.Encode(message);

            // FIXME: don't currently understand the skip compressor anyways
            //encoded = ct.SkipCompressor.Compress(encoded);
            //sc.AddPattern(encoded);

            // If enabled, and it improves the case, use huffman encoding to replace
            // frequently-used bytes
            byte[] huffed = hc.Encode(encoded);
            if (huffed != null && huffed.Length < encoded.Length)
            {
                cmp.Huffed = true;
                cmp.Message = huffed;

                // Only send the huffman frequency table when actually necessary!
                // After all, we might have a few updates before it's actually received...
                cmp.FrequencyTable = frequencies;
                frequenciesSent = true; // pending updates are scheduled to be sent
            }
            else
            {
                cmp.Huffed = false;
                cmp.Message = encoded;

                // we must reset this flag. Although we may have been scheduled to send the pending
                // frequency updates on a previous call, the update may not have been sent if
                // another template was selected.
                frequenciesSent = false;
            }

            if (cmp.Message.Length < message.Length)
            {
                encodedSavings += message.Length - cmp.Message.Length;
            }

            cmp.Gmced = true;   // FIXME: could check that encoded.Length < message.Length
            if (!templateSent) { cmp.Template = template; }
            cmp.Announcements = dictionaryAdditions;
            return cmp;
        }
Example #2
0
        /// <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>
        /// Decompresses a message using the provided compressors.
        /// </summary>
        /// <param name="cmp">the details of the message to be decompressed</param>
        /// <returns>The decoded (uncompressed) message</returns>
        public byte[] Decode(CompressedMessagePackage cmp)
        {
            List<byte> missingAnnouncements = new List<byte>();

            if (cmp.FrequencyTable != null)
            {
                Debug.Assert(cmp.FrequencyTable.Length == 256);
                hc.SetFrequencies(cmp.FrequencyTable);
                if(log.IsTraceEnabled)
                {
                    log.Trace(String.Format("[tid={0}] received huffman frequencies {1}",
                        templateId, cmp.FrequencyTable));
                }
            }
            if (cmp.Announcements != null)
            {
                foreach (uint longForm in cmp.Announcements.Keys)
                {
                    tc.HandleAnnouncement(longForm, cmp.Announcements[longForm]);
                }
            }

            byte[] message = cmp.Message;
            Debug.Assert(message != null);
            if (cmp.Huffed) { message = hc.Decode(message); }
            Debug.Assert(message != null);
            // if(cmp.Gmced) {
            message = tc.Decode(message);
            // }

            return message;
        }
        /// <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);
        }