private unsafe void Write(uint id, byte[] rawdata)
        {
            if (!StreamMul.CanWrite || (StreamIdx != null && !StreamIdx.CanWrite))
            {
                throw new AccessViolationException("Can't write data to mul file");
            }
            if (id >= _EntryLength || (IdxTable == null && rawdata != null && rawdata.Length != EntrySize))
            {
                throw new ArgumentOutOfRangeException();
            }

            if (IdxTable == null)
            {
                StreamMul.Seek(_EntryOff + id * EntrySize, SeekOrigin.Begin);
            }
            else
            {
                if (rawdata != null)
                {
                    var length = IdxTable[id].Length;
                    IdxTable[id].Length = (uint)rawdata.Length;
                    if (IdxTable[id].Offset != 0xFFFFFFFF && length != 0xFFFFFFFF && length >= IdxTable[id].Length)
                    {
                        StreamMul.Seek(IdxTable[id].Offset, SeekOrigin.Begin);
                    }
                    else
                    {
                        IdxTable[id].Offset = (uint)StreamMul.Seek(0, SeekOrigin.End);
                    }
                }
                else
                {
                    (this as IDataContainer).Delete(id);
                }
                StreamIdx.Seek((_EntryOff + id) * sizeof(IndexEntry), SeekOrigin.Begin);
                Utils.ArrayWrite <IndexEntry>(StreamIdx, IdxTable, (int)id, 1);
                StreamIdx.Flush();
            }
            if (rawdata != null)
            {
                Utils.ArrayWrite <byte>(StreamMul, rawdata, 0, rawdata.Length);
                StreamMul.Flush();
            }
        }
 T[] IDataContainer.Read <T>(uint fromId, uint offset, uint count)
 {
     if (IdxTable != null)
     {
         if (IdxTable[fromId].Offset == 0xFFFFFFFF || IdxTable[fromId].Length == 0x00000000 || IdxTable[fromId].Length == 0xFFFFFFFF)
         {
             return(new T[0]);
         }
         StreamMul.Seek(IdxTable[fromId].Offset + offset, SeekOrigin.Begin);
         var arr = Utils.ArrayRead <T>(StreamMul, (int)count);
         return(arr);
     }
     else
     {
         StreamMul.Seek(_EntryOff + fromId * EntrySize + offset, SeekOrigin.Begin);
         var arr = Utils.ArrayRead <T>(StreamMul, (int)count);
         return(arr);
     }
 }
 private byte[] Read(uint id)
 {
     if (id >= _EntryLength)
     {
         return(null);
     }
     //throw new ArgumentOutOfRangeException();
     if (IdxTable == null)
     {
         StreamMul.Seek(_EntryOff + id * EntrySize, SeekOrigin.Begin);
         return(Utils.ArrayRead <byte>(StreamMul, (int)EntrySize));
     }
     else
     {
         if (IdxTable[id].Offset == 0xFFFFFFFF || IdxTable[id].Length == 0xFFFFFFFF)
         {
             return(null);
         }
         StreamMul.Seek(IdxTable[id].Offset, SeekOrigin.Begin);
         return(Utils.ArrayRead <byte>(StreamMul, (int)IdxTable[id].Length));
     }
 }
        void IDataContainer.Write <T>(uint id, uint offset, T[] data, uint sfrom, uint count)
        {
            if (!StreamMul.CanWrite || (StreamIdx != null && !StreamIdx.CanWrite))
            {
                throw new AccessViolationException();
            }
            if (id >= _EntryLength || (IdxTable == null && data != null && Marshal.SizeOf(typeof(T)) != (EntrySize - offset) / data.Length))
            {
                throw new ArgumentOutOfRangeException();
            }

            if (IdxTable == null)
            {
                StreamMul.Seek(_EntryOff + id * EntrySize + offset, SeekOrigin.Begin);
            }
            else
            {
                var length = IdxTable[id].Length;
                IdxTable[id].Length = (uint)(offset + data.Length * Marshal.SizeOf(typeof(T)));
                if (IdxTable[id].Offset != 0xFFFFFFFF && length != 0xFFFFFFFF && length >= IdxTable[id].Length)
                {
                    StreamMul.Seek(_EntryOff + IdxTable[id].Offset + offset, SeekOrigin.Begin);
                }
                else
                {
                    StreamMul.Seek(_EntryOff + IdxTable[id].Offset, SeekOrigin.Begin);
                    var rawdata = new byte[offset];
                    StreamMul.Read(rawdata, 0, (int)offset);
                    IdxTable[id].Offset = (uint)StreamMul.Seek(0, SeekOrigin.End);
                    StreamMul.Write(rawdata, 0, (int)offset);
                }
                StreamIdx.Seek(id * Marshal.SizeOf(typeof(IndexEntry)), SeekOrigin.Begin);
                Utils.ArrayWrite <IndexEntry>(StreamIdx, IdxTable, (int)id, 1);
            }

            Utils.ArrayWrite <T>(StreamMul, data, (int)sfrom, (int)count);
        }
        void IDataContainer.Defrag()
        {
            if (StreamIdx == null || IsVirtual)
            {
                throw new MethodAccessException("Only non virtual mul containers with idx tables is possible to defrag.");
            }

            var crc32 = new Crc32();
            var hash1 = new Hashtable();
            var hash2 = new Hashtable();

            uint eidx = 0U, fpos = 0U;
            var  list = IdxTable.Select(e => new IndexEntry {
                Append = eidx++, Offset = e.Offset, Length = e.Length
            }).OrderBy(e => e.Offset).ToList();
            var maxl = IdxTable.Max(e => ((ulong)e.Offset + (ulong)e.Length) < (ulong)StreamMul.Length ? e.Length : 0);
            var bufi = new byte[Math.Min(maxl << 1, StreamMul.Length)];

            StreamMul.Seek(0, SeekOrigin.Begin);
            var back = Utils.ArrayRead <byte>(StreamMul, bufi.Length);


            var curleft = Console.CursorLeft;
            var process = Process.GetCurrentProcess();
            var workset = 0U;
            var lastupd = 0;

            for (int i = 0; i < _EntryLength; ++i)
            {
                if (Environment.TickCount - lastupd > 100)
                {
                    //GC.Collect();
                    workset = (uint)(Environment.WorkingSet >> 20);
                    lastupd = Environment.TickCount;

                    Console.SetCursorPosition(curleft, Console.CursorTop);
                    Console.Write("{0,7} < {1,6:0.00}% > RAM: {2} MiB", i, (100f * i) / _EntryLength, workset);
                }


                eidx = list[i].Append;
                if (IdxTable[eidx].Offset == 0xFFFFFFFF || IdxTable[eidx].Length == 0x00000000 || IdxTable[eidx].Length == 0xFFFFFFFF)
                {
                    continue;
                }

                var hkey = IdxTable[eidx].Offset;
                var hlst = hash1[hkey];
                if (hlst != null)
                {
                    IdxTable[eidx].Offset = IdxTable[(uint)hlst].Offset;
                    continue;
                }
                else
                {
                    hash1.Add(hkey, eidx);
                }

                if ((IdxTable[eidx].Offset + IdxTable[eidx].Length) >= back.Length)
                {
                    StreamMul.Seek(IdxTable[eidx].Offset, SeekOrigin.Begin);
                    Utils.FastRead(StreamMul, bufi, 0, (int)IdxTable[eidx].Length);
                }
                else
                {
                    Array.Copy(back, IdxTable[eidx].Offset, bufi, 0, IdxTable[eidx].Length);
                }

                crc32.Reset();
                crc32.Update(bufi);
                hkey = (uint)crc32.Value;
                hlst = hash2[hkey];
                if (hlst != null)
                {
                    var data = Read((uint)hlst);
                    if (Utils.ArrayIdentical(data, bufi, 0, Math.Max(data.Length, (int)IdxTable[eidx].Length)))
                    {
                        IdxTable[eidx].Offset = IdxTable[(uint)hlst].Offset;
                        continue;
                    }
                }
                else
                {
                    hash2.Add(hkey, eidx);
                }

                IdxTable[eidx].Offset = fpos;
                fpos += IdxTable[eidx].Length;
                StreamMul.Seek(IdxTable[eidx].Offset, SeekOrigin.Begin);
                Utils.ArrayWrite(StreamMul, bufi, 0, (int)IdxTable[eidx].Length);
            }
            StreamMul.SetLength(fpos);
            StreamMul.Flush();
            FlushIdx();
        }