Пример #1
0
        private static Func <bool> CompareInt(Func <int> reader, string value, string spec)
        {
            Func <int, bool> compare;
            int last = 0;

            if (value.Contains(".."))
            {
                int[] range = value.Split(new[] { ".." }, StringSplitOptions.RemoveEmptyEntries).Select(s => (int)Parse(s)).ToArray();
                compare = i => {
                    if (i != last)
                    {
                        DebugLogger.WriteLine($"RuntimeVar {spec} became {i}");
                    }
                    last = i;
                    return(i >= range[0] && i <= range[1]);
                };
            }
            else
            {
                HashSet <int> values = new HashSet <int>(value.Split(',').Select(s => (int)Parse(s)));
                compare = i => {
                    if (i != last)
                    {
                        DebugLogger.WriteLine($"RuntimeVar {spec} became {i}");
                    }
                    last = i;
                    return(values.Contains(i));
                };
            }
            return(() => compare(reader()));
        }
Пример #2
0
        public static List <byte[]> Unchunk(byte[] input)
        {
            var ms  = new System.IO.MemoryStream();
            var min = new System.IO.MemoryStream(input);

            min.Position = 4;
            Lzs.Decode(min, ms);
            DebugLogger.WriteLine($"FF:Unchunk:LZS expanded {input.Length} bytes to {ms.Length} bytes");
            byte[] scratch = new byte[4];
            ms.Position = 2;
            ms.Read(scratch, 0, 4);
            int numsection = BitConverter.ToInt32(scratch, 0);

            DebugLogger.WriteLine($"FF:Unchunk:{numsection} sections");
            List <byte[]> sections = new List <byte[]>();

            foreach (int i in Enumerable.Range(0, numsection))
            {
                ms.Position = 6 + i * 4;
                ms.Read(scratch, 0, 4);
                ms.Position = BitConverter.ToInt32(scratch, 0);
                ms.Read(scratch, 0, 4);
                int    len = BitConverter.ToInt32(scratch, 0);
                byte[] s   = new byte[len];
                ms.Read(s, 0, len);
                sections.Add(s);
            }
            return(sections);
        }
Пример #3
0
        public int SetFilePointer(long offset, Wrap.EMoveMethod method)
        {
            DebugLogger.WriteLine($"VArchive SetFilePointer on {_filename} to {offset} from {method}");
            switch (method)
            {
            case Wrap.EMoveMethod.Begin:
                _position = offset;
                break;

            case Wrap.EMoveMethod.End:
                _position = _size + offset;
                break;

            case Wrap.EMoveMethod.Current:
                _position += offset;
                break;
            }
            if (_position < 0)
            {
                return(-1);
            }
            if (_position > _size)
            {
                return(-1);
            }
            return((int)_position);
        }
Пример #4
0
        private LoadedFile GetLF(string path, string name)
        {
            LoadedFile lf;
            string     file = System.IO.Path.Combine(_base, path, name);

            if (!_files.TryGetValue(file, out lf))
            {
                lf        = new LoadedFile();
                lf.Handle = Wrap.CreateFileW(file.Replace('/', '\\'), System.IO.FileAccess.Read, System.IO.FileShare.Read, IntPtr.Zero, System.IO.FileMode.Open, System.IO.FileAttributes.Normal, IntPtr.Zero);
                if (lf.Handle == IntPtr.Zero || lf.Handle == new IntPtr(-1))
                {
                    lf.Missing = true;
                    lf.Tag     = DateTime.MaxValue;
                    DebugLogger.WriteLine($"Passing through {file}, no override file");
                }
                else
                {
                    DebugLogger.WriteLine($"Overriding data for {file}");
                    //System.Threading.Thread.Sleep(10000);
                    //System.Diagnostics.Debugger.Break();
                }
                _files[file] = lf;
            }
            return(lf);
        }
Пример #5
0
 public void Dump()
 {
     DebugLogger.WriteLine("VFILE:");
     foreach (var range in _ranges)
     {
         DebugLogger.WriteLine($"  Range {range.GetType().Name} starts {range.Start} length {range.Length} [{range.Tag}]");
     }
 }
Пример #6
0
 public int ReadFile(IntPtr bytes, uint numBytesToRead, ref uint numBytesRead)
 {
     DebugLogger.WriteLine($"VArchive ReadFile on {_filename} from {_position} for {numBytesToRead} bytes");
     _arc.RawRead(_filename, (uint)_position, numBytesToRead, bytes, ref numBytesRead);
     _position += numBytesRead;
     DebugLogger.WriteLine($"...actually read {numBytesRead} bytes");
     return(1);
 }
Пример #7
0
 public override void Cleanup(DateTime cutoff)
 {
     if (_access < cutoff && !(_handle.Equals(IntPtr.Zero)))
     {
         Win32.CloseHandle(_handle);
         _handle = IntPtr.Zero;
         DebugLogger.WriteLine($"Closing handle to {Filename}, idle");
     }
 }
Пример #8
0
 public bool SetFilePointerEx(IntPtr hFile, long liDistanceToMove, IntPtr lpNewFilePointer, uint dwMoveMethod)
 {
     DebugLogger.WriteLine("VArchive SetFilePointerEx");
     SetFilePointer(liDistanceToMove, (Wrap.EMoveMethod)dwMoveMethod);
     if (lpNewFilePointer != IntPtr.Zero)
     {
         System.Runtime.InteropServices.Marshal.WriteInt64(lpNewFilePointer, _position);
     }
     return(true);
 }
Пример #9
0
        private unsafe void Recalculate()
        {
            DebugLogger.WriteLine($"Chunked file {Name} recalculating contents...");
            byte[]           original = new byte[_fbLen];
            Win32.OVERLAPPED ov       = new Win32.OVERLAPPED()
            {
                EventHandle  = IntPtr.Zero,
                Internal     = UIntPtr.Zero,
                InternalHigh = UIntPtr.Zero,
                Offset       = _fbOffset,
                OffsetHigh   = 0
            };

            fixed(byte *bp = &original[0])
            {
                uint bytesRead = 0;

                //TODO should loop...
                Win32.ReadFile(_fbHandle, new IntPtr(bp), (uint)_fbLen, ref bytesRead, ref ov);
            }

            DebugLogger.WriteLine($"Original read {_fbLen} from {_fbOffset} sig {original[0]} {original[1]} {original[2]} {original[3]}");

            var orig = FieldFile.Unchunk(original);

            foreach (int i in Enumerable.Range(0, orig.Count))
            {
                string fn = Name + ".chunk." + (i + 1);
                foreach (var of in _mods.SelectMany(m => m.GetOverrides(fn)))
                {
                    if (of.CFolder == null || of.CFolder.IsActive(of.CName))
                    {
                        if (of.Archive == null)
                        {
                            orig[i] = System.IO.File.ReadAllBytes(of.File);
                        }
                        else
                        {
                            orig[i] = of.Archive.GetBytes(of.File);
                        }
                        break;
                    }
                }
            }

            _calculated = FieldFile.Chunk(orig);
            Bytes.WriteInt(_header, 20, _calculated.Length);
            DebugLogger.WriteLine($"New length of {Name} is {_calculated.Length}");
        }
Пример #10
0
 public static OverrideFile MapFile(string file, RuntimeProfile profile)
 {
     foreach (var item in profile.Mods)
     {
         foreach (var entry in item.GetOverrides(file))
         {
             if (entry.CFolder == null || entry.CFolder.IsActive(file))
             {
                 DebugLogger.WriteLine($"File {file} overridden by {entry.Archive}{entry.File}");
                 return(entry);
             }
         }
     }
     return(null);
 }
Пример #11
0
        public bool TryReadFile(string path, string name, uint offset, uint length, IntPtr data, ref uint numBytesRead)
        {
            LoadedFile lf = GetLF(path, name);

            if (lf.Missing)
            {
                return(false);
            }
            lf.Tag = DateTime.Now;
            Win32.OVERLAPPED ov = new Win32.OVERLAPPED()
            {
                EventHandle  = IntPtr.Zero,
                Internal     = UIntPtr.Zero,
                InternalHigh = UIntPtr.Zero,
                Offset       = offset,
                OffsetHigh   = 0
            };
            DebugLogger.WriteLine($"Attempting to read {length} bytes at offset {offset} from {name}");
            Win32.ReadFile(lf.Handle, data, length, ref numBytesRead, ref ov);
            DebugLogger.WriteLine("# bytes read: " + numBytesRead);
            return(true);
        }
Пример #12
0
        public override void Read(uint offset, uint length, IntPtr dest, ref uint bytesRead)
        {
            DebugLogger.WriteLine($"Chunked {Name} reading from OS {offset} L {length}");

            bool header = (offset < 24);
            bool init   = (offset == 24);

            if ((!_lastHeader && header) || (init && !_lastInit) || _calculated == null)   //re-evaluate
            {
                Recalculate();
                _lastInit = true; //we're ready to read file headers
            }
            else
            {
                _lastInit = init;
            }
            _lastHeader = header;

            if (offset < 24)
            {
                length = Math.Min(length, 24 - offset);
                System.Runtime.InteropServices.Marshal.Copy(_header, (int)offset, dest, (int)length);
                bytesRead = length;
                DebugLogger.WriteLine($"Chunked {Name} reading from cheader - {bytesRead} bytes read [current size is {BitConverter.ToInt32(_header, 20)}]");
                return;
            }
            else
            {
                offset -= 24;
                if (offset >= _calculated.Length)
                {
                    bytesRead = length; return; //leave with garbage...
                }
                int len = Math.Min((int)length, _calculated.Length - (int)offset);
                System.Runtime.InteropServices.Marshal.Copy(_calculated, (int)offset, dest, len);
                bytesRead = (uint)len;
            }
        }
Пример #13
0
        public void Run(RemoteHooking.IContext context, RuntimeParams parms)
        {
            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US", false);
            try {
                RuntimeProfile profile;
                using (var fs = new FileStream(parms.ProfileFile, FileMode.Open))
                {
                    profile = Iros._7th.Util.DeserializeBinary <RuntimeProfile>(fs);
                }

                File.Delete(parms.ProfileFile);

                if (!String.IsNullOrWhiteSpace(profile.LogFile))
                {
                    try {
                        try { File.Delete(profile.LogFile); } catch { } // ensure old log is deleted since new run

                        DebugLogger.Init(profile.LogFile);
                        DebugLogger.IsDetailedLogging = profile.Options.HasFlag(RuntimeOptions.DetailedLog);

                        DebugLogger.WriteLine("Logging debug output to " + profile.LogFile);
                    } catch (Exception ex) {
                        DebugLogger.WriteLine("Failed to log debug output: " + ex.ToString());
                    }
                }

                DebugLogger.WriteLine($"Wrap run... Host: {context.HostPID}  PID: {RemoteHooking.GetCurrentProcessId()}  TID: {RemoteHooking.GetCurrentThreadId()}   Path: {profile.ModPath}  Capture: {String.Join(", ", profile.MonitorPaths)}");
                //_overrides = new Overrides(basepath);
                _profile = profile;
                for (int i = _profile.MonitorPaths.Count - 1; i >= 0; i--)
                {
                    if (!_profile.MonitorPaths[i].EndsWith(System.IO.Path.DirectorySeparatorChar.ToString()))
                    {
                        _profile.MonitorPaths[i] += System.IO.Path.DirectorySeparatorChar;
                    }
                    if (String.IsNullOrWhiteSpace(_profile.MonitorPaths[i]))
                    {
                        _profile.MonitorPaths.RemoveAt(i);
                    }
                }

                foreach (var item in profile.Mods)
                {
                    DebugLogger.WriteLine($"  Mod: {item.BaseFolder} has {item.Conditionals.Count} conditionals");
                    DebugLogger.WriteLine("     Additional paths: " + String.Join(", ", item.ExtraFolders));
                    item.Startup();
                }

                _hCreateFileW = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "CreateFileW"), new DCreateFile(HCreateFileW), this);
                _hCreateFileW.ThreadACL.SetExclusiveACL(new[] { 0 });

                //_hCreateFileA = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "CreateFileA"), new DCreateFileA(HCreateFileA), this);
                //_hCreateFileA.ThreadACL.SetExclusiveACL(new[] { 0 });

                //int init = Init7W();
                //_hReadFile = LocalHook.CreateUnmanaged(LocalHook.GetProcAddress("kernel32.dll", "ReadFile"), LocalHook.GetProcAddress("7thWrapperNLib.dll", "ReadFile7W"), IntPtr.Zero);
                _hReadFile = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "ReadFile"), new DReadFile(HReadFile), this);
                _hReadFile.ThreadACL.SetExclusiveACL(new[] { 0 });

                _hWriteFile = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "WriteFile"), new DWriteFile(HWriteFile), this);
                _hWriteFile.ThreadACL.SetExclusiveACL(new[] { 0 });

                _hFindFirstFile = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "FindFirstFileW"), new DFindFirstFileW(HFindFirstFile), this);
                _hFindFirstFile.ThreadACL.SetExclusiveACL(new[] { 0 });

                //_hFindFirstFileA = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "FindFirstFileA"), new DFindFirstFileA(HFindFirstFileA), this);
                //_hFindFirstFile.ThreadACL.SetExclusiveACL(new[] { 0 });

                _hSetFilePointer = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "SetFilePointer"), new DSetFilePointer(HSetFilePointer), this);
                _hSetFilePointer.ThreadACL.SetExclusiveACL(new[] { 0 });

                _hSetFilePointerEx = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "SetFilePointerEx"), new DSetFilePointerEx(HSetFilePointerEx), this);
                _hSetFilePointerEx.ThreadACL.SetExclusiveACL(new[] { 0 });

                _hCloseHandle = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "CloseHandle"), new DCloseHandle(HCloseHandle), this);
                _hCloseHandle.ThreadACL.SetExclusiveACL(new[] { 0 });

                _hGetFileType = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "GetFileType"), new DGetFileType(HGetFileType), this);
                _hGetFileType.ThreadACL.SetExclusiveACL(new[] { 0 });

                _hGetFileInformationByHandle = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "GetFileInformationByHandle"), new DGetFileInformationByHandle(HGetFileInformationByHandle), this);
                _hGetFileInformationByHandle.ThreadACL.SetExclusiveACL(new[] { 0 });

                //_hReadFileEx = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "ReadFileEx"), new DReadFileEx(HReadFileEx), this);
                //_hReadFileEx.ThreadACL.SetExclusiveACL(new[] { 0 });

                _hDuplicateHandle = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "DuplicateHandle"), new DDuplicateHandle(HDuplicateHandle), this);
                _hDuplicateHandle.ThreadACL.SetExclusiveACL(new[] { 0 });

                _hCreateProcessW = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "CreateProcessW"), new DCreateProcessW(HCreateProcessW), this);
                _hCreateProcessW.ThreadACL.SetExclusiveACL(new[] { 0 });

                _hGetFileSize = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "GetFileSize"), new DGetFileSize(HGetFileSize), this);
                _hGetFileSize.ThreadACL.SetExclusiveACL(new[] { 0 });

                _hGetFileSizeEx = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "GetFileSizeEx"), new DGetFileSizeEx(HGetFileSizeEx), this);
                _hGetFileSizeEx.ThreadACL.SetExclusiveACL(new[] { 0 });

                if (profile.MonitorVars != null)
                {
                    new System.Threading.Thread(MonitorThread)
                    {
                        IsBackground = true
                    }
                }
                .Start(profile);
                //System.Threading.Thread.Sleep(10000);
                RemoteHooking.WakeUpProcess();

                System.Threading.Thread.Sleep(1000);
                foreach (string LL in profile.Mods.SelectMany(m => m.GetLoadLibraries()))
                {
                    DebugLogger.WriteLine($"Loading library DLL {LL}");
                    LoadLibrary(LL);
                }
                foreach (var mod in profile.Mods)
                {
                    foreach (string LA in mod.GetLoadAssemblies())
                    {
                        DebugLogger.WriteLine($"Loading assembly DLL {LA}");
                        var asm = System.Reflection.Assembly.LoadFrom(LA);
                        try {
                            string path = mod.BaseFolder;
                            asm.GetType("_7thHeaven.Main")
                            .GetMethod("Init", new[] { typeof(RuntimeMod) })
                            .Invoke(null, new object[] { mod });
                        } catch { }
                    }
                }

                foreach (var mod in profile.Mods)
                {
                    foreach (string file in mod.GetPathOverrideNames("hext"))
                    {
                        foreach (var of in mod.GetOverrides("hext\\" + file))
                        {
                            System.IO.Stream s;
                            if (of.Archive == null)
                            {
                                s = new System.IO.FileStream(of.File, FileMode.Open, FileAccess.Read);
                            }
                            else
                            {
                                s = of.Archive.GetData(of.File);
                            }
                            DebugLogger.WriteLine($"Applying hext patch {file} from mod {mod.BaseFolder}");
                            try {
                                HexPatch.Apply(s);
                            } catch (Exception ex) {
                                DebugLogger.WriteLine("Error applying patch: " + ex.Message);
                            }
                        }
                    }
                }
            } catch (Exception e) {
Пример #14
0
 public Wrap(RemoteHooking.IContext context, RuntimeParams parms)
 {
     DebugLogger.WriteLine("Wrap created");
 }
Пример #15
0
        public static Func <bool> MakeRuntimeVar(string spec, string value)
        {
            VarType type;
            int     size = 0;

            string[] parts = spec.Split(':');
            Enum.TryParse <VarType>(parts[0], true, out type);
            if (parts.Length > 2)
            {
                size = (int)Parse(parts[2]);
            }

            switch (type)
            {
            case VarType.Sys:
                return(GetSys(parts[1], size, value, spec));

            case VarType.Counter:
                return(CompareInt(() => {
                    int c;
                    _counters.TryGetValue(parts[1], out c);
                    return c % size;
                }, value, spec));

            case VarType.CounterAdv:
                return(CompareInt(() => {
                    int c;
                    _counters.TryGetValue(parts[1], out c);
                    c++;
                    _counters[parts[1]] = c;
                    return c % size;
                }, value, spec));

            case VarType.CounterRnd:
                return(CompareInt(() => {
                    int c = _r.Next(size);
                    _counters[parts[1]] = c;
                    return c;
                }, value, spec));

            case VarType.Random:
                return(CompareInt(() => _r.Next(size), value, spec));
            }

            if (type == VarType.FFString)
            {
                byte[]           data   = new byte[size];
                HashSet <string> values = new HashSet <string>(value.Split('|'), StringComparer.InvariantCultureIgnoreCase);
                string           last   = String.Empty;
                IntPtr           address;
                address = new IntPtr(Parse(parts[1]));
                return(() => {
                    System.Runtime.InteropServices.Marshal.Copy(address, data, 0, size);
                    string s = FFText.Translate(data);
                    if (!s.Equals(last))
                    {
                        DebugLogger.WriteLine($"RuntimeVar {spec} became {s}");
                    }
                    last = s;
                    return values.Contains(s.Trim());
                });
            }
            else
            {
                IntPtr address;
                address = new IntPtr(Parse(parts[1]));
                if (size == 0)
                {
                    size = -1;
                }
                switch (type)
                {
                case VarType.Int:
                    return(CompareInt(() => System.Runtime.InteropServices.Marshal.ReadInt32(address) & size, value, spec));

                case VarType.Byte:
                    return(CompareInt(() => System.Runtime.InteropServices.Marshal.ReadByte(address) & size, value, spec));

                case VarType.Short:
                    return(CompareInt(() => System.Runtime.InteropServices.Marshal.ReadInt16(address) & size, value, spec));
                }
            }
            throw new Exception("Bad RunTimeVar specification");
        }
Пример #16
0
 public uint GetFileSize(IntPtr lpFileSizeHigh)
 {
     DebugLogger.WriteLine($"VArchive GetFileSize on {_filename} = {_size}");
     if (lpFileSizeHigh != IntPtr.Zero)
         System.Runtime.InteropServices.Marshal.WriteInt32(lpFileSizeHigh, (int)(_size >> 32)); }
Пример #17
0
        public override void Read(uint offset, uint length, IntPtr dest, ref uint bytesRead)
        {
            //DebugLogger.WriteLine("Conditional {2} reading from OS {0} L {1}", offset, length, Name);

            bool header = (offset < 24);
            bool init   = (offset == 24);

            if ((!_lastHeader && header) || (init && !_lastInit))   //re-evaluate
            {
                _current = null;
                if (!_handle.Equals(IntPtr.Zero))
                {
                    Win32.CloseHandle(_handle);
                }
                _handle = IntPtr.Zero;

                foreach (var of in _files)
                {
                    if (of.CFolder == null || of.CFolder.IsActive(of.CName))
                    {
                        DebugLogger.WriteLine($"Conditional {Name} switching to {of.File}");
                        _current = of;
                        Bytes.WriteInt(_header, 20, of.Size);
                        break;
                    }
                }
                if (_current == null)
                {
                    DebugLogger.WriteLine($"Conditional {Name} switching to fallback");
                }
                _lastInit = true; //we're ready to read file headers
            }
            else
            {
                _lastInit = init;
            }
            if (_current != null && _handle.Equals(IntPtr.Zero) && _current.Archive == null)
            {
                _handle = Wrap.CreateFileW(_current.File, System.IO.FileAccess.Read, System.IO.FileShare.Read, IntPtr.Zero, System.IO.FileMode.Open, System.IO.FileAttributes.Normal, IntPtr.Zero);
            }
            _lastHeader = header;
            _access     = DateTime.Now;

            if (_current == null)   //read from fallback
            //DebugLogger.WriteLine("Conditional reading from fallback handle {0} with extra offset {1}", _fallbackHandle, _fallbackOffset);
            {
                Win32.OVERLAPPED ov = new Win32.OVERLAPPED()
                {
                    EventHandle  = IntPtr.Zero,
                    Internal     = UIntPtr.Zero,
                    InternalHigh = UIntPtr.Zero,
                    Offset       = _fallbackOffset + offset,
                    OffsetHigh   = 0
                };
                Win32.ReadFile(_fallbackHandle, dest, length, ref bytesRead, ref ov);
                //DebugLogger.WriteLine("Conditional {1} reading from fallback - {0} bytes read", bytesRead, Name);
            }
            else
            {
                if (offset < 24)
                {
                    length = Math.Min(length, 24 - offset);
                    System.Runtime.InteropServices.Marshal.Copy(_header, (int)offset, dest, (int)length);
                    bytesRead = length;
                    //DebugLogger.WriteLine("Conditional {2} reading from cheader - {0} bytes read [current size is {1}]", bytesRead, BitConverter.ToInt32(_header, 20), Name);
                    return;
                }
                else
                {
                    offset -= 24;
                    if (_current.Archive == null)
                    {
                        Wrap.SetFilePointer(_handle, (int)offset, IntPtr.Zero, Wrap.EMoveMethod.Begin);
                        Win32.ReadFile(_handle, dest, length, ref bytesRead, IntPtr.Zero);
                        //DebugLogger.WriteLine("Conditional {1} reading from cfile - {0} bytes read", bytesRead, Name);
                    }
                    else
                    {
                        _current.Archive.RawRead(_current.File, offset, length, dest, ref bytesRead);
                        //DebugLogger.WriteLine("Conditional {1} reading from cfile archive offset {2} length {3} - {0} bytes read", bytesRead, Name, offset, length);
                    }
                }
            }
        }
Пример #18
0
        public LGPWrapper(IntPtr handle, string name, RuntimeProfile profile)
        {
            if (!AnyOverridesFor(name, profile))
            {
                DebugLogger.WriteLine($"LGPWrapper: no overrides for {name}, early out");
                return; //optimisation, don't run anything else, if no override files
            }
            IsActive = true;

            DebugLogger.WriteLine("   LGPWrapper: Parsing");
            var fs = new System.IO.FileStream(new Microsoft.Win32.SafeHandles.SafeFileHandle(handle, false), FileAccess.Read);

            ProcMonParser.DataFile df = ProcMonParser.FF7Files.LoadLGP(fs, name);
            fs.Position = 0;

            Dictionary <string, int>  sortKeys     = df.Items.ToDictionary(i => i.Name, i => i.Index, StringComparer.InvariantCulture);
            Dictionary <string, long> dataKeys     = df.Items.ToDictionary(i => i.Name, i => i.Start, StringComparer.InvariantCulture);
            Dictionary <string, int>  filesSizes   = new Dictionary <string, int>(StringComparer.InvariantCultureIgnoreCase);
            Dictionary <string, int>  filesOptions = new Dictionary <string, int>(StringComparer.InvariantCultureIgnoreCase);
            Dictionary <string, ProcMonParser.DataItem> lgpItems = df.Items.ToDictionary(i => i.Name, i => i, StringComparer.InvariantCulture);

            foreach (var item in df.Items)
            {
                filesOptions[item.Name] = 0;
                filesSizes[item.Name]   = item.Length - 24;
                DebugLogger.DetailedWriteLine($"Checking chunk support for {name}~{item.Name}~");
                if (profile.Mods.Any(m => m.SupportsChunks(System.IO.Path.Combine(name, item.Name))))
                {
                    filesSizes[item.Name]    = Math.Max(filesSizes[item.Name], 1024 * 1024 * 2); //This is a horrible hack. TODO.
                    filesOptions[item.Name] |= 0x1;
                }
            }
            DebugLogger.WriteLine("   LGPWrapper: Prepared structures");
            List <string> names = profile.Mods.SelectMany(m => m.GetPathOverrideNames(name)).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList();

            foreach (string fname in names)
            {
                if (fname.IndexOf(".chunk.", StringComparison.InvariantCultureIgnoreCase) >= 0)
                {
                    continue;
                }
                if (!filesSizes.ContainsKey(fname))
                {
                    filesSizes[fname] = 0;
                    DebugLogger.WriteLine($"Added LGP file {name} {fname}");
                }
                var overrides = profile.Mods.SelectMany(m => m.GetOverrides(System.IO.Path.Combine(name, fname)));
                foreach (var over in overrides)
                {
                    filesSizes[fname] = Math.Max(filesSizes[fname], over.Size);
                    if (over.CFolder == null)
                    {
                        break;
                    }
                }
            }
            List <LGPEntry>         entries = filesSizes.Select(kv => new LGPEntry(kv.Key, kv.Value)).ToList();
            List <LGP.LGPEntryMade> newentries;

            DebugLogger.WriteLine("   LGPWrapper: creating new headers");
            byte[] headers = LGP.CalculateHeaders(entries,
                                                  s => {
                int index;
                sortKeys.TryGetValue(s, out index);
                return(index);
            },
                                                  s => {
                long index;
                dataKeys.TryGetValue(s, out index);
                return((uint)index);
            },
                                                  out newentries
                                                  );
            int datastart = headers.Length;

            DebugLogger.WriteLine($"   LGPWrapper: Calculated new LGP headers for {name} with {entries.Count} file entries");

            /*
             * int datastart = df.Items[0].Start;
             * byte[] headers = new byte[datastart];
             * fs.Read(headers, 0, datastart);
             * fs.Position = 0;
             */

            uint offset = (uint)datastart;

            VFile = new VFile();
            try {
                VFile.Add(new VRangeInline()
                {
                    Start = 0, Length = offset, Data = headers, Tag = "Headers"
                });
                int count = 0;
                foreach (var item in newentries.OrderBy(em => em.DataIndex))
                {
                    DebugLogger.DetailedWriteLine($"LGPWrapper calculate {item.Entry.Name}");
                    //Bytes.WriteUInt(headers, 16 + 20 + 27 * item.Index, offset);
                    string fn        = System.IO.Path.Combine(name, item.Entry.Name);
                    var    overrides = profile.Mods.SelectMany(m => m.GetOverrides(fn));

                    int fOptions;
                    filesOptions.TryGetValue(item.Entry.Name, out fOptions);
                    bool chunked = (fOptions & 0x1) != 0;
                    //var overrides = Enumerable.Empty<OverrideFile>();
                    //DebugLogger.WriteLine("Virtualizing LGP entry {0} at offset {1}", item.Entry.Name, offset);
                    if (item.DataOffset != offset)
                    {
                        throw new Exception("LGPWrapper mismatch on offset for " + item.Entry.Name + " offset=" + offset + " hoffset=" + item.DataOffset);
                    }

                    if (chunked)
                    {
                        long pos = lgpItems[item.Entry.Name].Start + 24;
                        int  len = lgpItems[item.Entry.Name].Length - 24;
                        VFile.Add(new VRangeChunked(item.Entry.Name, profile.Mods, handle, (uint)pos, len)
                        {
                            Start  = offset,
                            Length = (uint)(item.Entry.MaxSize + 24),
                            Name   = fn,
                            Tag    = "Chunked"
                        });
                        //DebugLogger.WriteLine("File {0} initialized with chunks", item.Entry.Name, 0);
                        offset += (uint)item.Entry.MaxSize + 24;
                    }
                    else if (!overrides.Any())     //take from original LGP
                    {
                        long pos = lgpItems[item.Entry.Name].Start;
                        VFile.Add(new VRangeHandle()
                        {
                            Start = offset, Length = (uint)(item.Entry.MaxSize + 24), Handle = handle, Offset = (uint)pos, Tag = item.Entry.Name
                        });
                        offset += (uint)item.Entry.MaxSize + 24;
                        //DebugLogger.WriteLine("--VRangeHandle");
                    }
                    else if (overrides.First().CFolder == null)     //only one override, replace directly
                    {
                        var ov = overrides.First();

                        byte[] fheader = new byte[24];
                        System.Text.Encoding.ASCII.GetBytes(item.Entry.Name, 0, item.Entry.Name.Length, fheader, 0);
                        Bytes.WriteUInt(fheader, 20, (uint)ov.Size);
                        VFile.Add(new VRangeInline()
                        {
                            Start = offset, Length = 24, Data = fheader, Tag = item.Entry.Name + "%header"
                        });
                        offset += 24;
                        VRange vr;
                        if (ov.Archive == null)
                        {
                            var vf = new VRangeFile()
                            {
                                Start = offset, Length = (uint)ov.Size, Filename = ov.File, Tag = ov.File
                            };
                            VFile.Add(vf);
                            _wFiles.Add(vf);
                            vr = vf;
                            //DebugLogger.WriteLine("LGP entry {0} coming from file {1}", item.Entry.Name, ov.File);
                        }
                        else
                        {
                            vr = new VRangeArchive()
                            {
                                Start = offset, Length = (uint)ov.Size, File = ov.File, Archive = ov.Archive, Tag = ov.File
                            };
                            VFile.Add(vr);
                            //DebugLogger.WriteLine("LGP entry {0} coming from archive file {1} with size {2}", item.Entry.Name, ov.File, ov.Size);
                        }
                        //if (vr.Length != item.Entry.MaxSize)
                        //DebugLogger.WriteLine("Entry {0} size difference {1} vs {2}", item.Entry.Name, vr.Length, item.Entry.MaxSize);
                        if (vr.Length < item.Entry.MaxSize)
                        {
                            uint diff = (uint)item.Entry.MaxSize - vr.Length;
                            VFile.Add(new VRangeNull()
                            {
                                Length = diff, Start = vr.Start + vr.Length, Tag = "Padding"
                            });
                        }
                        offset += (uint)item.Entry.MaxSize;
                        //DebugLogger.WriteLine("--VRangeFile");
                    }
                    else     //multiple overrides; tricky!
                    //DebugLogger.WriteLine("Add VRangeConditional for " + item.Entry.Name);
                    {
                        ProcMonParser.DataItem di;
                        lgpItems.TryGetValue(item.Entry.Name, out di);
                        uint fbOffset = (di == null) ? 0 : (uint)di.Start;

                        var vcond = new VRangeConditional(item.Entry.Name, overrides.ToList(), handle, fbOffset)
                        {
                            Length = (uint)item.Entry.MaxSize + 24, Start = offset, Name = item.Entry.Name, Tag = item.Entry.Name
                        };
                        VFile.Add(vcond);
                        _wFiles.Add(vcond);
                        offset += (uint)item.Entry.MaxSize + 24;
                        //DebugLogger.WriteLine("--VRangeConditional");
                    }
                    count++;

                    /*
                     * string file = MapFile(System.IO.Path.Combine(name, item.Name), profile);
                     * if (file != null) {
                     *  uint length = (uint)new System.IO.FileInfo(file).Length;
                     *  byte[] fheader = new byte[24];
                     *  System.Text.Encoding.ASCII.GetBytes(item.Name, 0, item.Name.Length, fheader, 0);
                     *  Bytes.WriteUInt(fheader, 20, length);
                     *  VFile.Add(new VRangeInline() { Start = offset, Length = 24, Data = fheader });
                     *  offset += 24;
                     *  var vf = new VRangeFile() { Start = offset, Length = length, Filename = file };
                     *  VFile.Add(vf);
                     *  _wFiles.Add(vf);
                     *  offset += length;
                     * } else {
                     *  VFile.Add(new VRangeHandle() { Start = offset, Length = (uint)(item.Length), Handle = handle, Offset = (uint)item.Start });
                     *  offset += (uint)item.Length;
                     * }*/
                }
                byte[] footer = System.Text.Encoding.ASCII.GetBytes("FINAL FANTASY7");
                VFile.Add(new VRangeInline()
                {
                    Start = offset, Length = (uint)footer.Length, Data = footer, Tag = "footer"
                });
                DebugLogger.WriteLine("Created: " + VFile.ToString());
            } catch {
                VFile.Dump();
                throw;
            }
        }