diff --git a/Tools/ApkUncompress2/AssemblyStore/Utils.cs b/Tools/ApkUncompress2/AssemblyStore/Utils.cs index aa8361a63..1dfb54479 100644 --- a/Tools/ApkUncompress2/AssemblyStore/Utils.cs +++ b/Tools/ApkUncompress2/AssemblyStore/Utils.cs @@ -164,6 +164,7 @@ static bool HasAllEntries (ZipFile zf, string[] entries) { foreach (string entry in entries) { + bool found = false; foreach (ZipEntry zipEntry in zf) { if (!zipEntry.IsFile) @@ -171,11 +172,17 @@ static bool HasAllEntries (ZipFile zf, string[] entries) continue; // Ignore directories } - if (string.Compare(zipEntry.Name, entry, StringComparison.OrdinalIgnoreCase) != 0) + if (string.Compare(zipEntry.Name, entry, StringComparison.OrdinalIgnoreCase) == 0) { - return false; + found = true; + break; } } + + if (!found) + { + return false; + } } return true; diff --git a/Tools/ApkUncompress2/Program.cs b/Tools/ApkUncompress2/Program.cs index 22253bc62..15756e8ac 100644 --- a/Tools/ApkUncompress2/Program.cs +++ b/Tools/ApkUncompress2/Program.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.IO; +using Xamarin.Android.AssemblyStore; namespace ApkUncompress2 { @@ -7,7 +9,7 @@ internal class App { static int Usage() { - Console.WriteLine("Usage: decompress-assemblies {file.{dll,apk,aab}} [{file.{dll,apk,aab} ...]"); + Console.WriteLine("Usage: decompress-assemblies {file.{apk,aab}} [{file.{apk,aab} ...]"); Console.WriteLine(); Console.WriteLine("DLL files passed on command line are uncompressed to the file directory with the `uncompressed-` prefix added to their name."); Console.WriteLine("DLL files from AAB/APK archives are uncompressed to a subdirectory of the file directory named after the archive with extension removed"); @@ -22,20 +24,65 @@ static int Main(string[] args) } bool haveErrors = false; - foreach (string file in args) + foreach (string inputFile in args) { - string ext = Path.GetExtension(file); - string fullPath = Path.GetFullPath(file); - if (string.IsNullOrEmpty(fullPath)) + (FileFormat format, FileInfo? info) = Utils.DetectFileFormat(inputFile); + if (info == null) { + Console.WriteLine($"File '{inputFile}' does not exist."); + haveErrors = true; continue; } - string? outputPath = Path.GetDirectoryName(fullPath); - if (string.IsNullOrEmpty(outputPath)) + (IList? explorers, string? errorMessage) = AssemblyStoreExplorer.Open(inputFile); + if (explorers == null) { + Console.WriteLine(errorMessage ?? "Unknown error"); + haveErrors = true; continue; } + + string baseFileName = Path.GetFileNameWithoutExtension(inputFile); + string? srcDir = Path.GetDirectoryName(inputFile); + if (string.IsNullOrEmpty(srcDir)) + { + Console.WriteLine("Invalid directory"); + haveErrors = true; + continue; + } + + foreach (AssemblyStoreExplorer store in explorers) + { + if (store.Assemblies != null) + { + foreach (AssemblyStoreItem storeItem in store.Assemblies) + { + Stream? stream = store.ReadImageData(storeItem); + if (stream == null) + { + Console.WriteLine($"Failed to read image data for {storeItem.Name}"); + continue; + } + + string archName = store.TargetArch.HasValue ? store.TargetArch.Value.ToString().ToLowerInvariant() : "unknown"; + string outFile = Path.Combine(srcDir, baseFileName, archName, storeItem.Name); + string? outDir = Path.GetDirectoryName(outFile); + if (string.IsNullOrEmpty(outDir)) + { + continue; + } + + Directory.CreateDirectory(outDir); + using (var fileStream = File.Create(outFile)) + { + stream.Seek(0, SeekOrigin.Begin); + stream.CopyTo(fileStream); + } + stream.Dispose(); + } + } + } + } return haveErrors ? 1 : 0; diff --git a/Tools/ApkUncompress2/Properties/.gitignore b/Tools/ApkUncompress2/Properties/.gitignore new file mode 100644 index 000000000..3674a6e08 --- /dev/null +++ b/Tools/ApkUncompress2/Properties/.gitignore @@ -0,0 +1 @@ +/launchSettings.json