Пример #1
0
        /// <summary>
        /// Encodes a byte array
        /// </summary>
        /// <param name="data"></param>
        /// <param name="encodingMap"></param>
        /// <param name="rootName">Root filename</param>
        /// <returns></returns>
        public static CASRecord Encode(byte[] data, EMap encodingMap, string rootName = null)
        {
            using var bt = new BlockTableStreamWriter(encodingMap);
            bt.Write(data);

            var record = bt.Finalise();

            record.FileName = rootName;
            return(record);
        }
Пример #2
0
        /// <summary>
        /// Encodes a stream
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="encodingMap"></param>
        /// <param name="rootName">Root filename</param>
        /// <returns></returns>
        public static CASRecord Encode(Stream stream, EMap encodingMap, string rootName = null)
        {
            using var bt    = new BlockTableStreamWriter(encodingMap);
            stream.Position = 0;
            stream.CopyTo(bt);

            var record = bt.Finalise();

            record.FileName = rootName;
            return(record);
        }
Пример #3
0
        /// <summary>
        /// Adds a new block to the stream. This finalises the previous block preventing access
        /// </summary>
        /// <param name="blockencoding"></param>
        /// <param name="blockindex"></param>
        public void AddBlock(EMap blockencoding, int blockindex = -1)
        {
            // lock the previous substream
            if (_blocks.Count > 0)
            {
                _blocks[_curIndex].Lock();
            }

            // compute the new index
            if (blockindex == -1)
            {
                blockindex = _blocks.Count;
            }

            _blocks.Add(blockindex, new BlockTableSubStream(memStream, blockencoding));
            _curIndex = blockindex;
        }
Пример #4
0
        /// <summary>
        /// Encodes a byte array and saves the result to disk
        /// </summary>
        /// <param name="data"></param>
        /// <param name="encodingMap"></param>
        /// <param name="directory"></param>
        /// <param name="rootName">Root filename</param>
        /// <returns></returns>
        public static CASRecord EncodeAndExport(byte[] data, EMap encodingMap, string directory, string rootName = null)
        {
            using var bt = new BlockTableStreamWriter(encodingMap);
            bt.Write(data);
            var record = bt.Finalise();

            string saveLocation = Path.Combine(directory, record.EKey.ToString());

            using (var fs = Helpers.Create(saveLocation))
            {
                bt.WriteTo(fs);
                record.BLTEPath = saveLocation;
                record.FileName = rootName;
            }

            return(record);
        }
Пример #5
0
        /// <summary>
        /// Encodes a stream using Blizzard-esque rules and saves the result to disk
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="encodingMap"></param>
        /// <param name="directory"></param>
        /// <param name="rootName">Root filename</param>
        /// <returns></returns>
        public static CASRecord EncodeAndExport(Stream stream, EMap encodingMap, string directory, string rootName = null)
        {
            using (var bt = new BlockTableStreamWriter(encodingMap))
            {
                stream.Position = 0;
                stream.CopyTo(bt);
                var record = bt.Finalise();

                string saveLocation = Helpers.GetCDNPath(record.EKey.ToString(), "data", directory, true);
                using (var fs = Helpers.Create(saveLocation))
                {
                    bt.WriteTo(fs);
                    record.BLTEPath = saveLocation;
                    record.FileName = rootName;
                }

                return(record);
            }
        }
Пример #6
0
        /// <summary>
        /// Finalises and encodes the stream's contents
        /// </summary>
        /// <returns></returns>
        public CASRecord Finalise()
        {
            if (Finalised)
            {
                return(Result);
            }

            // lock the final block
            _blocks[_blocks.Count - 1].Lock();

            MD5Hash EKey, CKey = ComputeCKey();
            EMap    encoding         = _blocks.Count == 1 ? _blocks[0].EncodingMap : new EMap(EType.ZLib, 9);
            uint    decompressedSize = 0;
            string  eSpec;

            using (var md5 = MD5.Create())
                using (var ms = new MemoryStream((int)memStream.Length + 0x100))
                    using (var bw = new BinaryWriter(ms))
                    {
                        // replace the stream contents with the BLTE structure
                        uint headerSize = (uint)(_blocks.Count == 1 ? 0 : 0x18 * _blocks.Count + 0xC);

                        // Header
                        bw.Write(BlockTableStreamReader.BLTE_MAGIC);
                        bw.WriteUInt32BE(headerSize);

                        // Frame
                        if (headerSize > 0)
                        {
                            bw.Write((byte)0xF);                   // flag
                            bw.WriteUInt24BE((uint)_blocks.Count); // chunkCount

                            // EBlock meta
                            foreach (var block in _blocks.Values)
                            {
                                block.Finalise(); // apply encoding byte and any compression
                                block.Position = 0;

                                bw.WriteUInt32BE(block.CompressedSize);
                                bw.WriteUInt32BE(block.DecompressedSize);
                                bw.Write(md5.ComputeHash(block));
                                decompressedSize += block.DecompressedSize;
                            }
                        }
                        else
                        {
                            var block = _blocks[0];
                            block.Finalise(); // apply encoding byte and any compression
                            decompressedSize = block.DecompressedSize;
                        }

                        foreach (var block in _blocks.Values)
                        {
                            block.Position = 0;
                            block.CopyTo(ms);
                        }

                        // calculate the EKey
                        if (headerSize == 0)
                        {
                            ms.Position = 0;
                            EKey        = new MD5Hash(md5.ComputeHash(ms));
                        }
                        else
                        {
                            EKey = ms.HashSlice(md5, 0, headerSize);
                        }

                        // set ESpec
                        eSpec = string.Join(",", _blocks.Values);

                        // merge the streams
                        memStream.Position = 0;
                        memStream.SetLength(ms.Length);
                        memStream.Capacity = (int)ms.Length;
                        ms.WriteTo(memStream);

                        // cleanup
                        _blocks.Clear();
                        Finalised = true;
                    }

            // store for repeat finalisation
            return(Result = new CASRecord()
            {
                CKey = CKey,
                EBlock = new EBlock()
                {
                    DecompressedSize = decompressedSize,
                    CompressedSize = (uint)memStream.Length,
                    EKey = EKey,
                    EncodingMap = encoding
                },
                ESpec = "b:{" + eSpec + "}"
            });
        }
Пример #7
0
 public BlockTableStreamWriter(EMap blockencoding, int blockindex = -1)
 {
     memStream = new MemoryStream();
     _blocks   = new SortedList <int, BlockTableSubStream>();
     AddBlock(blockencoding, blockindex);
 }
Пример #8
0
 public BlockTableSubStream(MemoryStream inner, EMap map)
 {
     _innerStream = inner;
     _startPos    = inner.Position;
     EncodingMap  = map;
 }
Пример #9
0
 public EBlock()
 {
     EncodingMap = default;
 }