Beispiel #1
0
        private unsafe byte[] DecompressFFXIVMessage(ref FFXIVBundleHeader header, byte[] buffer, int offset, out int ffxivMessageSize)
        {
            ffxivMessageSize = 0;

            if (header.encoding == 0x0000 || header.encoding == 0x0001)
            {
                // uncompressed - copy to output buffer
                ffxivMessageSize = header.length - sizeof(FFXIVBundleHeader);
                for (int i = 0; i < ffxivMessageSize / 4; i++)
                {
                    // todo: use unsafe pointer operations
                    uint value = BitConverter.ToUInt32(buffer, offset + i * 4 + sizeof(FFXIVBundleHeader));
                    Array.Copy(BitConverter.GetBytes(value), 0, _decompressionBuffer, i * 4, 4);
                }

                return(_decompressionBuffer);
            }

            if (header.encoding != 0x0101 && header.encoding != 0x0100)
            {
                if (!_encodingError)
                {
                    Trace.WriteLine("FFXIVBundleDecoder: unknown encoding type: " + header.encoding.ToString("X4"), "DEBUG-MACHINA");
                }
                _encodingError = true;
                return(null);
            }

            try
            {
                // inflate the packet using built-in .net function.  Note that the first two bytes of the data are skipped, since this
                //  appears to be a standard zlib deflated buffer
                System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer, offset + 42, header.length - 42);
                using (DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress))
                {
                    // todo: need more graceful way of determing decompressed size!
                    ffxivMessageSize = ds.Read(_decompressionBuffer, 0, _decompressionBuffer.Length);
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine("FFXIVBundleDecoder: Decompression error: " + ex.ToString(), "DEBUG-MACHINA");
                return(null);
            }

            return(_decompressionBuffer);
        }
Beispiel #2
0
        public unsafe void StoreData(byte[] buffer)
        {
            // append buffer data
            if (_bundleBuffer == null)
            {
                _bundleBuffer = buffer;
                _allocated    = buffer.Length;
            }
            else
            {
                // resize buffer if there is a remaining amount with a different length than the incoming buffer.
                if (_bundleBuffer.Length - _allocated != buffer.Length)
                {
                    Array.Resize(ref _bundleBuffer, buffer.Length + _allocated);
                }

                Array.Copy(buffer, 0, _bundleBuffer, _allocated, buffer.Length);
                _allocated += buffer.Length;
            }

            int offset = 0;

            while (offset < _allocated)
            {
                if (_allocated - offset < sizeof(FFXIVBundleHeader))
                {
                    if (offset > 0)
                    {
                        if (_allocated != offset)
                        {
                            Array.Copy(_bundleBuffer, offset, _bundleBuffer, 0, _allocated - offset);
                        }
                        _allocated -= offset;
                    }
                    return;
                }

                fixed(byte *ptr = _bundleBuffer)
                {
                    FFXIVBundleHeader header = *(FFXIVBundleHeader *)(ptr + offset);

                    if (header.magic0 != 0x41a05252)
                    {
                        if (header.magic0 != 0 && header.magic1 != 0 &&
                            header.magic2 != 0 && header.magic3 != 0)
                        {
                            if (LastMessageTimestamp != DateTime.MinValue)
                            {
                                Trace.WriteLine("FFXIVBundleDecoder: Invalid magic # in header:" + Utility.ByteArrayToHexString(_bundleBuffer, offset, 36), "DEBUG-MACHINA");
                            }

                            offset = ResetStream(offset);
                            continue;
                        }
                    }

                    // Exit if not all of the message is available yet.
                    if (header.length > _bundleBuffer.Length - offset)
                    {
                        if ((offset > 0) && (_allocated != offset))
                        {
                            Array.Copy(_bundleBuffer, offset, _bundleBuffer, 0, _allocated - offset);
                            _allocated -= offset;
                        }
                        return;
                    }
                    int messageBufferSize;

                    byte[] message = DecompressFFXIVMessage(ref header, _bundleBuffer, offset, out messageBufferSize);
                    if (message == null || messageBufferSize <= 0)
                    {
                        offset = ResetStream(offset);
                        continue;
                    }

                    offset += header.length;
                    if (offset == _allocated)
                    {
                        _bundleBuffer = null;
                    }
                    if (messageBufferSize > 0)
                    {
                        int message_offset = 0;

                        fixed(byte *msgPtr = message)
                        {
                            for (int i = 0; i < header.message_count; i++)
                            {
                                ushort message_length = ((ushort *)(msgPtr + message_offset))[0];
                                byte[] data           = new byte[message_length];
                                Array.Copy(message, message_offset, data, 0, data.Length);

                                Messages.Enqueue(new Tuple <long, byte[]>(
                                                     (long)Utility.ntohq(header.epoch), data));

                                message_offset += message_length;
                                if (message_offset > messageBufferSize)
                                {
                                    Trace.WriteLine("FFXIVBundleDecoder: Bad message offset - offset=" + message_offset.ToString() + ", bufferSize=" + messageBufferSize.ToString() +
                                                    ", data: " + Utility.ByteArrayToHexString(data, 0, 50), "DEBUG-MACHINA");

                                    _allocated = 0;
                                    return;
                                }
                            }
                            LastMessageTimestamp = DateTime.UtcNow;
                        }
                    }
                }
            }
        }