Esempio n. 1
0
        private static void ExtractAllWithBSA(string source, string dest)
        {
            try
            {
                using (var arch = BSADispatch.OpenRead(source))
                {
                    arch.Files.PMap(f =>
                    {
                        var path = f.Path;
                        if (f.Path.StartsWith("\\"))
                        {
                            path = f.Path.Substring(1);
                        }
                        Utils.Status($"Extracting {path}");
                        var out_path = Path.Combine(dest, path);
                        var parent   = Path.GetDirectoryName(out_path);

                        if (!Directory.Exists(parent))
                        {
                            Directory.CreateDirectory(parent);
                        }

                        using (var fs = File.OpenWrite(out_path))
                        {
                            f.CopyDataTo(fs);
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                Utils.Log($"While Extracting {source}");
                throw ex;
            }
        }
Esempio n. 2
0
        private static async Task ExtractAllWithBSA(WorkQueue queue, string source, string dest)
        {
            try
            {
                using (var arch = BSADispatch.OpenRead(source))
                {
                    await arch.Files
                    .PMap(queue, f =>
                    {
                        var path = f.Path;
                        if (f.Path.StartsWith("\\"))
                        {
                            path = f.Path.Substring(1);
                        }
                        Utils.Status($"Extracting {path}");
                        var outPath = Path.Combine(dest, path);
                        var parent  = Path.GetDirectoryName(outPath);

                        if (!Directory.Exists(parent))
                        {
                            Directory.CreateDirectory(parent);
                        }

                        using (var fs = File.Open(outPath, System.IO.FileMode.Create))
                        {
                            f.CopyDataTo(fs);
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                Utils.ErrorThrow(ex, $"While Extracting {source}");
            }
        }
Esempio n. 3
0
 public static async Task <ExtractedFiles> ExtractAll(WorkQueue queue, AbsolutePath source, IEnumerable <RelativePath> OnlyFiles = null)
 {
     try
     {
         if (BSADispatch.MightBeBSA(source))
         {
             return(await ExtractAllWithBSA(queue, source));
         }
         else if (source.Extension == Consts.OMOD)
         {
             return(await ExtractAllWithOMOD(source));
         }
         else if (source.Extension == Consts.EXE)
         {
             return(await ExtractAllExe(source));
         }
         else
         {
             return(await ExtractAllWith7Zip(source, OnlyFiles));
         }
     }
     catch (Exception ex)
     {
         Utils.ErrorThrow(ex, $"Error while extracting {source}");
         throw new Exception();
     }
 }
Esempio n. 4
0
        private static async Task ExtractAllWithBSA(WorkQueue queue, AbsolutePath source, AbsolutePath dest)
        {
            try
            {
                using var arch = BSADispatch.OpenRead(source);
                await arch.Files
                .PMap(queue, f =>
                {
                    Utils.Status($"Extracting {(string)f.Path}");
                    var outPath = f.Path.RelativeTo(dest);
                    var parent  = outPath.Parent;

                    if (!parent.IsDirectory)
                    {
                        parent.CreateDirectory();
                    }

                    using var fs = outPath.Create();
                    f.CopyDataTo(fs);
                });
            }
            catch (Exception ex)
            {
                Utils.ErrorThrow(ex, $"While Extracting {source}");
            }
        }
Esempio n. 5
0
        protected override async Task <ExitCode> Run()
        {
            var bsa = await BSADispatch.OpenRead(Input.RelativeTo(AbsolutePath.GetCurrentDirectory()));

            bsa.Dump(Console.WriteLine);
            return(ExitCode.Ok);
        }
Esempio n. 6
0
        public override Directive Run(RawSourceFile source)
        {
            if (!Consts.SupportedBSAs.Contains(Path.GetExtension(source.Path).ToLower()))
            {
                return(null);
            }

            var defaultInclude = false;

            if (source.Path.StartsWith("mods"))
            {
                if (_include_directly.Any(path => source.Path.StartsWith(path)))
                {
                    defaultInclude = true;
                }
            }

            var source_files = source.File.FileInArchive;

            var stack = defaultInclude ? _microstackWithInclude : _microstack;

            var id = Guid.NewGuid().ToString();

            var matches = source_files.PMap(e => Compiler.RunStack(stack, new RawSourceFile(e)
            {
                Path = Path.Combine(Consts.BSACreationDir, id, e.Paths.Last())
            }));


            foreach (var match in matches)
            {
                if (match is IgnoredDirectly)
                {
                    Utils.Error($"File required for BSA {source.Path} creation doesn't exist: {match.To}");
                }
                _compiler.ExtraFiles.Add(match);
            }

            CreateBSA directive;

            using (var bsa = BSADispatch.OpenRead(source.AbsolutePath))
            {
                directive = new CreateBSA
                {
                    To         = source.Path,
                    TempID     = id,
                    State      = bsa.State,
                    FileStates = bsa.Files.Select(f => f.State).ToList()
                };
            }

            return(directive);
        }
Esempio n. 7
0
 private static async Task <ExtractedFiles> ExtractAllWithBSA(WorkQueue queue, AbsolutePath source)
 {
     try
     {
         await using var arch = BSADispatch.OpenRead(source);
         var files = arch.Files.ToDictionary(f => f.Path, f => (IExtractedFile) new ExtractedBSAFile(f));
         return(new ExtractedFiles(files, arch));
     }
     catch (Exception ex)
     {
         Utils.ErrorThrow(ex, $"While Extracting {source}");
         throw new Exception();
     }
 }
Esempio n. 8
0
        public override async ValueTask <Directive?> Run(RawSourceFile source)
        {
            if (!Consts.SupportedBSAs.Contains(source.Path.Extension))
            {
                return(null);
            }

            var defaultInclude = false;

            if (source.Path.RelativeTo(_mo2Compiler.MO2Folder).InFolder(_mo2Compiler.MO2Folder.Combine(Consts.MO2ModFolderName)))
            {
                if (_includeDirectly.Any(path => source.Path.StartsWith(path)))
                {
                    defaultInclude = true;
                }
            }

            var sourceFiles = source.File.Children;

            var stack = defaultInclude ? _microstackWithInclude(source.File) : _microstack(source.File);

            var id = Guid.NewGuid().ToString();

            var matches = await sourceFiles.PMap(_mo2Compiler.Queue, e => _mo2Compiler.RunStack(stack, new RawSourceFile(e, Consts.BSACreationDir.Combine((RelativePath)id, e.Name.FileName))));


            foreach (var match in matches)
            {
                if (match is IgnoredDirectly)
                {
                    Utils.ErrorThrow(new UnconvertedError($"File required for BSA {source.Path} creation doesn't exist: {match.To}"));
                }
                _mo2Compiler.ExtraFiles.Add(match);
            }

            CreateBSA directive;

            using (var bsa = BSADispatch.OpenRead(source.AbsolutePath))
            {
                directive = new CreateBSA(
                    state: bsa.State,
                    items: bsa.Files.Select(f => f.State).ToList())
                {
                    To     = source.Path,
                    TempID = (RelativePath)id,
                };
            }

            return(directive);
        }
Esempio n. 9
0
        protected override async Task <ExitCode> Run()
        {
            Console.WriteLine($"Extracting {InputFile} to {OutputFolder}");
            var bsa = await BSADispatch.OpenRead((AbsolutePath)InputFile);

            foreach (var file in bsa.Files)
            {
                Console.WriteLine($"Extracting {file.Path}");
                var ofile = file.Path.RelativeTo((AbsolutePath)OutputFolder);
                ofile.Parent.CreateDirectory();
                await using var ostream = await ofile.Create();

                await file.CopyDataTo(ostream);
            }

            return(ExitCode.Ok);
        }
Esempio n. 10
0
        private static async Task <Dictionary <RelativePath, T> > GatheringExtractWithBSA <T>(IStreamFactory sFn, Definitions.FileType sig, Predicate <RelativePath> shouldExtract, Func <RelativePath, IStreamFactory, ValueTask <T> > mapfn)
        {
            var archive = await BSADispatch.OpenRead(sFn, sig);

            var results = new Dictionary <RelativePath, T>();

            foreach (var entry in archive.Files)
            {
                if (!shouldExtract(entry.Path))
                {
                    continue;
                }

                var result = await mapfn(entry.Path, await entry.GetStreamFactory());

                results.Add(entry.Path, result);
            }

            return(results);
        }
Esempio n. 11
0
        public async Task CanRecompressAndResizeDDSImages()
        {
            var profile = utils.AddProfile();
            var mod     = await utils.AddMod();

            var nativeFile = await utils.AddModFile(mod, @"native\whitestagbody.dds", 0);

            var recompressedFile = await utils.AddModFile(mod, @"recompressed\whitestagbody.dds", 0);

            var resizedFile = await utils.AddModFile(mod, @"resized\whitestagbody.dds", 0);

            var gameBSA = Game.SkyrimSpecialEdition.MetaData().GameLocation().Combine(@"Data\Skyrim - Textures1.bsa");
            var bsa     = await BSADispatch.OpenRead(gameBSA);

            var ddsExtension = new Extension(".dds");
            var firstFile    = bsa.Files.First(f => f.Path.Extension == ddsExtension);

            await using (var nf = await nativeFile.OpenWrite())
            {
                await firstFile.CopyDataTo(nf);
            }

            {
                var originalDDS = await ImageState.GetState(nativeFile);

                await ImageState.ConvertImage(nativeFile, recompressedFile.Parent, originalDDS.Width, originalDDS.Height, DXGI_FORMAT.BC7_UNORM, recompressedFile.Extension);

                await ImageState.ConvertImage(nativeFile, resizedFile.Parent, 128, 128, DXGI_FORMAT.BC7_UNORM, resizedFile.Extension);
            }

            await utils.Configure();

            await CompileAndInstall(profile, true);

            await utils.VerifyInstalledFile(mod, @"native\whitestagbody.dds");

            Assert.True(0.99f <= (await ImageState.GetState(recompressedFile)).PerceptualHash.Similarity(await ImageState.GetPHash(utils.InstalledPath(mod, @"recompressed\whitestagbody.dds"))));
            Assert.True(0.98f <= (await ImageState.GetState(resizedFile)).PerceptualHash.Similarity(await ImageState.GetPHash(utils.InstalledPath(mod, @"resized\whitestagbody.dds"))));
        }
Esempio n. 12
0
        public override async ValueTask <Directive?> Run(RawSourceFile source)
        {
            if (!Consts.SupportedBSAs.Contains(source.Path.Extension))
            {
                return(null);
            }

            var defaultInclude = false;

            if (source.Path.RelativeTo(_mo2Compiler.SourcePath).InFolder(_mo2Compiler.SourcePath.Combine(Consts.MO2ModFolderName)))
            {
                if (_includeDirectly.Any(path => source.Path.StartsWith(path)))
                {
                    defaultInclude = true;
                }
            }

            if (source.AbsolutePath.Size >= (long)2 << 31)
            {
                var bsaTest = await BSADispatch.OpenRead(source.AbsolutePath);

                if (bsaTest.State is BSAStateObject)
                {
                    Utils.Error(
                        $"BSA {source.AbsolutePath.FileName} is over 2GB in size, very few programs (Including Wabbajack) can create BSA files this large without causing CTD issues." +
                        $"Please re-compress this BSA into a more manageable size.");
                }
            }

            var sourceFiles = source.File.Children;

            var stack = defaultInclude ? _microstackWithInclude(source.File) : _microstack(source.File);

            var id = Guid.NewGuid().ToString();


            Func <Task>?_cleanup = null;

            if (defaultInclude)
            {
                //_cleanup = await source.File.Context.Stage(source.File.Children);
            }

            var matches = await sourceFiles.PMap(_mo2Compiler.Queue, e => _mo2Compiler.RunStack(stack, new RawSourceFile(e, Consts.BSACreationDir.Combine((RelativePath)id, (RelativePath)e.Name))));


            foreach (var match in matches)
            {
                if (match is IgnoredDirectly)
                {
                    Utils.ErrorThrow(new UnconvertedError($"File required for BSA {source.Path} creation doesn't exist: {match.To}"));
                }
                _mo2Compiler.ExtraFiles.Add(match);
            }

            CreateBSA directive;
            var       bsa = await BSADispatch.OpenRead(source.AbsolutePath);

            directive = new CreateBSA(
                state: bsa.State,
                items: bsa.Files.Select(f => f.State).ToList())
            {
                To     = source.Path,
                TempID = (RelativePath)id,
            };

            if (_cleanup != null)
            {
                await _cleanup();
            }
            return(directive);
        }
Esempio n. 13
0
        [InlineData(Game.Fallout4, 43474)]             // EM 2 Rifle
        public async Task BSACompressionRecompression(Game game, int modid)
        {
            var filename = await DownloadMod(game, modid);

            var folder = _bsaFolder.Combine(game.ToString(), modid.ToString());
            await folder.DeleteDirectory();

            folder.CreateDirectory();
            await using var files = await FileExtractor.ExtractAll(Queue, filename);

            await files.MoveAllTo(folder);

            foreach (var bsa in folder.EnumerateFiles().Where(f => Consts.SupportedBSAs.Contains(f.Extension)))
            {
                TestContext.WriteLine($"From {bsa}");
                TestContext.WriteLine("Cleaning Output Dir");
                await _tempDir.DeleteDirectory();

                _tempDir.CreateDirectory();

                TestContext.WriteLine($"Reading {bsa}");
                var tempFile = ((RelativePath)"tmp.bsa").RelativeToEntryPoint();
                var size     = bsa.Size;

                await using var a = BSADispatch.OpenRead(bsa);
                await a.Files.PMap(Queue, file =>
                {
                    var absName = _tempDir.Combine(file.Path);
                    ViaJson(file.State);

                    absName.Parent.CreateDirectory();
                    using (var fs = absName.Create())
                    {
                        file.CopyDataTo(fs);
                    }

                    Assert.Equal(file.Size, absName.Size);
                });


                // Check Files should be case insensitive
                Assert.Equal(a.Files.Count(), a.Files.Select(f => f.Path).ToHashSet().Count);
                Assert.Equal(a.Files.Count(), a.Files.Select(f => f.Path.ToString().ToLowerInvariant()).ToHashSet().Count);

                TestContext.WriteLine($"Building {bsa}");

                await using (var w = ViaJson(a.State).MakeBuilder(size))
                {
                    var streams = await a.Files.PMap(Queue, async file =>
                    {
                        var absPath = _tempDir.Combine(file.Path);
                        var str     = absPath.OpenRead();
                        await w.AddFile(ViaJson(file.State), str);
                        return(str);
                    });

                    await w.Build(tempFile);

                    streams.Do(s => s.Dispose());
                }

                TestContext.WriteLine($"Verifying {bsa}");
                await using var b = BSADispatch.OpenRead(tempFile);
                TestContext.WriteLine($"Performing A/B tests on {bsa}");
                Assert.Equal(a.State.ToJson(), b.State.ToJson());

                // Check same number of files
                Assert.Equal(a.Files.Count(), b.Files.Count());


                await a.Files.Zip(b.Files, (ai, bi) => (ai, bi))
                .PMap(Queue, pair =>
                {
                    Assert.Equal(pair.ai.State.ToJson(), pair.bi.State.ToJson());
                    //Console.WriteLine($"   - {pair.ai.Path}");
                    Assert.Equal(pair.ai.Path, pair.bi.Path);
                    //Equal(pair.ai.Compressed, pair.bi.Compressed);
                    Assert.Equal(pair.ai.Size, pair.bi.Size);
                    Assert.Equal(GetData(pair.ai), GetData(pair.bi));
                });
            }
        }
Esempio n. 14
0
        //private const string Archive2Location = @"D:\Steam\steamapps\common\Fallout 4\Tools\Archive2\Archive2.exe";

        private static void Main(string[] args)
        {
            foreach (var bsa in Directory.EnumerateFiles(TestDir, "*.ba2", SearchOption.AllDirectories)
                     //.Concat(Directory.EnumerateFiles(TestDir, "*.bsa", SearchOption.AllDirectories))
                     )
            {
                Console.WriteLine($"From {bsa}");
                Console.WriteLine("Cleaning Output Dir");
                if (Directory.Exists(TempDir))
                {
                    Directory.Delete(TempDir, true);
                }
                if (Directory.Exists(ArchiveTempDir))
                {
                    Directory.Delete(ArchiveTempDir, true);
                }
                Directory.CreateDirectory(TempDir);

                Console.WriteLine($"Reading {bsa}");
                using (var a = BSADispatch.OpenRead(bsa))
                {
                    Parallel.ForEach(a.Files, file =>
                    {
                        var abs_name = Path.Combine(TempDir, file.Path);
                        ViaJson(file.State);

                        if (!Directory.Exists(Path.GetDirectoryName(abs_name)))
                        {
                            Directory.CreateDirectory(Path.GetDirectoryName(abs_name));
                        }


                        using (var fs = File.OpenWrite(abs_name))
                        {
                            file.CopyDataTo(fs);
                        }


                        Equal(file.Size, new FileInfo(abs_name).Length);
                    });

                    /*
                     * Console.WriteLine("Extracting via Archive.exe");
                     * if (bsa.ToLower().EndsWith(".ba2"))
                     * {
                     *  var p = Process.Start(Archive2Location, $"\"{bsa}\" -e=\"{ArchiveTempDir}\"");
                     *  p.WaitForExit();
                     *
                     *  foreach (var file in a.Files)
                     *  {
                     *      var a_path = Path.Combine(TempDir, file.Path);
                     *      var b_path = Path.Combine(ArchiveTempDir, file.Path);
                     *      Equal(new FileInfo(a_path).Length, new FileInfo(b_path).Length);
                     *      Equal(File.ReadAllBytes(a_path), File.ReadAllBytes(b_path));
                     *  }
                     * }*/


                    Console.WriteLine($"Building {bsa}");

                    using (var w = ViaJson(a.State).MakeBuilder())
                    {
                        Parallel.ForEach(a.Files, file =>
                        {
                            var abs_path = Path.Combine(TempDir, file.Path);
                            using (var str = File.OpenRead(abs_path))
                            {
                                w.AddFile(ViaJson(file.State), str);
                            }
                        });

                        w.Build("c:\\tmp\\tmp.bsa");
                    }

                    Console.WriteLine($"Verifying {bsa}");
                    using (var b = BSADispatch.OpenRead("c:\\tmp\\tmp.bsa"))
                    {
                        Console.WriteLine($"Performing A/B tests on {bsa}");
                        Equal(JsonConvert.SerializeObject(a.State), JsonConvert.SerializeObject(b.State));

                        //Equal((uint) a.ArchiveFlags, (uint) b.ArchiveFlags);
                        //Equal((uint) a.FileFlags, (uint) b.FileFlags);

                        // Check same number of files
                        Equal(a.Files.Count(), b.Files.Count());
                        var idx = 0;
                        foreach (var pair in a.Files.Zip(b.Files, (ai, bi) => (ai, bi)))
                        {
                            idx++;
                            Equal(JsonConvert.SerializeObject(pair.ai.State),
                                  JsonConvert.SerializeObject(pair.bi.State));
                            //Console.WriteLine($"   - {pair.ai.Path}");
                            Equal(pair.ai.Path, pair.bi.Path);
                            //Equal(pair.ai.Compressed, pair.bi.Compressed);
                            Equal(pair.ai.Size, pair.bi.Size);
                            Equal(GetData(pair.ai), GetData(pair.bi));
                        }
                    }
                }
            }
        }