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(); } }
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(); }