Browse Source

Add Seven Repacker

HOME 2 months ago
parent
commit
ad489eabeb

+ 145 - 0
SevenRepacker/BridgeStream.cs

@@ -0,0 +1,145 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using SevenZip;
+
+namespace SevenRepacker
+{
+    //SOURCE: https://stackoverflow.com/a/3729877/2430943 With modify
+    public class BridgeStream : Stream
+    {
+        private readonly long? _length;
+        private readonly SevenZipExtractor _inArchive;
+        private readonly int _archiveIndex;
+        private bool _isInit;
+
+        private readonly BlockingCollection<byte[]> _blocks;
+        private byte[] _currentBlock;
+        private int _currentBlockIndex;
+
+        public BridgeStream(int streamWriteCountCache, long? length, SevenZipExtractor inArchive, int archiveIndex)
+        {
+            _length = length;
+            _inArchive = inArchive;
+            _archiveIndex = archiveIndex;
+            _blocks = new BlockingCollection<byte[]>(streamWriteCountCache);
+        }
+
+        public override bool CanTimeout => false;
+        public override bool CanRead => true;
+
+        /// <summary>
+        /// FAKE!
+        /// </summary>
+        public override bool CanSeek => true;
+
+        public override bool CanWrite => true;
+        public override long Length => _length ?? throw new NotSupportedException();
+        public override void Flush() { }
+        public long TotalBytesWritten { get; private set; }
+        public int WriteCount { get; private set; }
+
+        public override long Position
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            ValidateBufferArgs(buffer, offset, count);
+
+            if (!_isInit)
+            {
+                Task.Run(() =>
+                {
+                    _inArchive.ExtractFile(_archiveIndex, this);
+                    CompleteWriting();
+                });
+                _isInit = true;
+            }
+
+            int bytesRead = 0;
+            while (true)
+            {
+                if (_currentBlock != null)
+                {
+                    int copy = Math.Min(count - bytesRead, _currentBlock.Length - _currentBlockIndex);
+                    Array.Copy(_currentBlock, _currentBlockIndex, buffer, offset + bytesRead, copy);
+                    _currentBlockIndex += copy;
+                    bytesRead += copy;
+
+                    if (_currentBlock.Length <= _currentBlockIndex)
+                    {
+                        _currentBlock = null;
+                        _currentBlockIndex = 0;
+                    }
+
+                    if (bytesRead == count)
+                        return bytesRead;
+                }
+
+                if (!_blocks.TryTake(out _currentBlock, Timeout.Infinite))
+                    return bytesRead;
+            }
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            ValidateBufferArgs(buffer, offset, count);
+
+            var newBuf = new byte[count];
+            Array.Copy(buffer, offset, newBuf, 0, count);
+            _blocks.Add(newBuf);
+            TotalBytesWritten += count;
+            WriteCount++;
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            base.Dispose(disposing);
+            if (disposing)
+            {
+                _blocks.Dispose();
+            }
+        }
+
+        public override void Close()
+        {
+            CompleteWriting();
+            base.Close();
+        }
+
+        public void CompleteWriting()
+        {
+            _blocks.CompleteAdding();
+        }
+
+        private static void ValidateBufferArgs(byte[] buffer, int offset, int count)
+        {
+            if (buffer == null)
+                throw new ArgumentNullException("buffer");
+            if (offset < 0)
+                throw new ArgumentOutOfRangeException("offset");
+            if (count < 0)
+                throw new ArgumentOutOfRangeException("count");
+            if (buffer.Length - offset < count)
+                throw new ArgumentException("buffer.Length - offset < count");
+        }
+    }
+}

+ 103 - 0
SevenRepacker/Program.cs

@@ -0,0 +1,103 @@
+using SevenZip;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace SevenRepacker
+{
+    internal class Program
+    {
+        private static int Main(string[] args)
+        {
+#if DEBUG
+            SevenZipBase.SetLibraryPath(Environment.Is64BitProcess
+                ? "x64/7z.dll"
+                : "x86/7z.dll");
+#else
+            SevenZipBase.SetLibraryPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "7z.dll"));
+#endif
+            string outDir = null;
+
+            var inputFiles = new List<string>();
+            foreach (var arg in args)
+            {
+                if (arg.StartsWith('/') && arg.Contains(':') && arg[^1] != ':')
+                {
+                    var kv = arg.Substring(1).Split(":", 2);
+                    switch (kv[0].ToLower())
+                    {
+                        case "out-dir":
+                            outDir = kv[1];
+                            if (false == Directory.Exists(outDir))
+                            {
+                                Console.Error.WriteLine($"Arg ERROR. out dir not found: {outDir}");
+                                return -1;
+                            }
+                            break;
+                    }
+                    continue;
+                }
+
+                inputFiles.Add(arg);
+            }
+
+            foreach (var inputFilePath in inputFiles)
+            {
+                Console.WriteLine("Process start");
+
+                if (!File.Exists(inputFilePath))
+                {
+                    Console.WriteLine($"ERR, Input file not found: {inputFilePath}");
+                    continue;
+                }
+
+                var outputFilePath = Path.ChangeExtension(inputFilePath, ".zip");
+                if (outDir != null)
+                {
+                    outputFilePath = Path.Combine(outDir, Path.GetFileName(outputFilePath));
+                }
+
+                if (File.Exists(outputFilePath))
+                {
+                    Console.WriteLine($"SKIP, Output file already exist: {outputFilePath}");
+                    continue;
+                }
+
+                Console.WriteLine($"  In: {inputFilePath}");
+                Console.WriteLine($" Out: {outputFilePath}");
+
+                using var inputArchive = new SevenZipExtractor(inputFilePath);
+                var inputItems = inputArchive.ArchiveFileData.OrderBy(p => p.Index).ToArray();
+
+                var streamDict = new Dictionary<string, Stream>();
+
+                foreach (var item in inputItems)
+                {
+                    if (item.IsDirectory) continue;
+
+                    streamDict.Add(item.FileName, new BridgeStream(1, (long?)item.Size, inputArchive, item.Index));
+                }
+
+                ////////////////////
+
+                var outputArchive = new SevenZipCompressor
+                {
+                    ArchiveFormat = OutArchiveFormat.Zip,
+                    CompressionMethod = CompressionMethod.Copy,
+                    CompressionMode = CompressionMode.Create,
+                };
+
+                outputArchive.FileCompressionStarted += (_, eventArgs) => Console.WriteLine($"EntryStarted:{eventArgs.FileName} ");
+                outputArchive.Compressing += (_, eventArgs) => Console.Write($"{eventArgs.PercentDone}% ");
+                outputArchive.FileCompressionFinished += (_, _) => Console.WriteLine($"EntryFinished");
+
+                outputArchive.CompressStreamDictionary(streamDict, outputFilePath);
+
+                Console.WriteLine("Process Finished");
+            }
+
+            return 0;
+        }
+    }
+}

+ 8 - 0
SevenRepacker/Properties/launchSettings.json

@@ -0,0 +1,8 @@
+{
+  "profiles": {
+    "SevenRepacker": {
+      "commandName": "Project",
+      "commandLineArgs": "\"L:\\Archive\\Anime\\202107-Isekai Cheat Magician 13 [OVA][1080P][MMSUB].7z\" \"L:\\Archive\\Anime\\202107-舍管.7z\" /out-dir:z:/"
+    }
+  }
+}

+ 13 - 0
SevenRepacker/SevenRepacker.csproj

@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net5.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="7z.Libs" Version="21.7.0" />
+    <PackageReference Include="Squid-Box.SevenZipSharp" Version="1.5.0.366" />
+  </ItemGroup>
+
+</Project>

+ 7 - 1
StrangeTools.sln

@@ -32,7 +32,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TcpRedirector", "TcpRedirec
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AudioNTR", "AudioNTR\AudioNTR.csproj", "{A01E5694-1C4D-4E11-A73A-70AEE4D98B2E}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DirEx", "DirEx\DirEx.csproj", "{62A1F458-B9ED-4443-8B94-E24ECF57AC9B}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DirEx", "DirEx\DirEx.csproj", "{62A1F458-B9ED-4443-8B94-E24ECF57AC9B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SevenRepacker", "SevenRepacker\SevenRepacker.csproj", "{9670672F-A051-46D4-AF50-B71E3E9815E2}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -92,6 +94,10 @@ Global
 		{62A1F458-B9ED-4443-8B94-E24ECF57AC9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{62A1F458-B9ED-4443-8B94-E24ECF57AC9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{62A1F458-B9ED-4443-8B94-E24ECF57AC9B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9670672F-A051-46D4-AF50-B71E3E9815E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9670672F-A051-46D4-AF50-B71E3E9815E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9670672F-A051-46D4-AF50-B71E3E9815E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9670672F-A051-46D4-AF50-B71E3E9815E2}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE