Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Xamarin.Android.sln
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "apksigner", "src\apksigner\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "java-source-utils", "external\Java.Interop\tools\java-source-utils\java-source-utils.csproj", "{37FCD325-1077-4603-98E7-4509CAD648D6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "decompress-assemblies", "tools\decompress-assemblies\decompress-assemblies.csproj", "{88B746FF-8D6E-464D-9D66-FF2ECCF148E0}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Xamarin.Android.NamingCustomAttributes\Xamarin.Android.NamingCustomAttributes.projitems*{3f1f2f50-af1a-4a5a-bedb-193372f068d7}*SharedItemsImports = 4
Expand Down Expand Up @@ -395,6 +397,10 @@ Global
{37FCD325-1077-4603-98E7-4509CAD648D6}.Debug|AnyCPU.Build.0 = Debug|Any CPU
{37FCD325-1077-4603-98E7-4509CAD648D6}.Release|AnyCPU.ActiveCfg = Release|Any CPU
{37FCD325-1077-4603-98E7-4509CAD648D6}.Release|AnyCPU.Build.0 = Release|Any CPU
{88B746FF-8D6E-464D-9D66-FF2ECCF148E0}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
{88B746FF-8D6E-464D-9D66-FF2ECCF148E0}.Debug|AnyCPU.Build.0 = Debug|Any CPU
{88B746FF-8D6E-464D-9D66-FF2ECCF148E0}.Release|AnyCPU.ActiveCfg = Release|Any CPU
{88B746FF-8D6E-464D-9D66-FF2ECCF148E0}.Release|AnyCPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -461,6 +467,7 @@ Global
{86A8DEFE-7ABB-4097-9389-C249581E243D} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{9A9EF774-6EA6-414F-9D2F-DCD66C56B92A} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{37FCD325-1077-4603-98E7-4509CAD648D6} = {864062D3-A415-4A6F-9324-5820237BA058}
{88B746FF-8D6E-464D-9D66-FF2ECCF148E0} = {864062D3-A415-4A6F-9324-5820237BA058}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {53A1F287-EFB2-4D97-A4BB-4A5E145613F6}
Expand Down
30 changes: 30 additions & 0 deletions tools/decompress-assemblies/decompress-assemblies.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Company>Microsoft Corporation</Company>
<Copyright>2021 Microsoft Corporation</Copyright>
<Version>0.0.1</Version>
<TargetFramework>net472</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RootNamespace>Xamarin.Android.Tools.DecompressAssemblies</RootNamespace>
<AssemblyName>decompress-assemblies</AssemblyName>
<OutputPath>../../bin/$(Configuration)/bin</OutputPath>
<OutputType>Exe</OutputType>
<LibZipSharpBundleAllNativeLibraries>true</LibZipSharpBundleAllNativeLibraries>
<Nullable>enable</Nullable>
</PropertyGroup>

<Import Project="..\..\Configuration.props" />

<ItemGroup>
<PackageReference Include="Xamarin.LibZipSharp" Version="$(LibZipSharpVersion)" />
<PackageReference Include="K4os.Compression.LZ4" Version="$(LZ4PackageVersion)" />
</ItemGroup>

<ItemGroup>
<Content Include="..\scripts\decompress-assemblies">
<Link>decompress-assemblies</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
139 changes: 139 additions & 0 deletions tools/decompress-assemblies/main.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using System;
using System.Buffers;
using System.IO;

using K4os.Compression.LZ4;
using Xamarin.Tools.Zip;

namespace Xamarin.Android.Tools.DecompressAssemblies
{
class App
{
const uint CompressedDataMagic = 0x5A4C4158; // 'XALZ', little-endian

static readonly ArrayPool<byte> bytePool = ArrayPool<byte>.Shared;

static int Usage ()
{
Console.WriteLine ("Usage: decompress-assemblies {file.{dll,apk,aab}} [{file.{dll,apk,aab} ...]");
Console.WriteLine ();
Console.WriteLine ("DLL files passed on command are uncompressed to the current directory with the `uncompressed-` prefix added to their name.");
Console.WriteLine ("DLL files from AAB/APK archives are uncompressed to a subdirectory of the current directory named after the archive with extension removed");
return 1;
}

static bool UncompressDLL (Stream inputStream, string fileName, string filePath, string prefix)
{
string outputFile = $"{prefix}{Path.GetFileName (filePath)}";
bool retVal = true;

Console.WriteLine ($"Processing {fileName}");
//
// LZ4 compressed assembly header format:
// uint magic; // 0x5A4C4158; 'XALZ', little-endian
// uint descriptor_index; // Index into an internal assembly descriptor table
// uint uncompressed_length; // Size of assembly, uncompressed
//
using (var reader = new BinaryReader (inputStream)) {
uint magic = reader.ReadUInt32 ();
if (magic == CompressedDataMagic) {
reader.ReadUInt32 (); // descriptor index, ignore
uint decompressedLength = reader.ReadUInt32 ();

int inputLength = (int)(inputStream.Length - 12);
byte[] sourceBytes = bytePool.Rent (inputLength);
reader.Read (sourceBytes, 0, inputLength);

byte[] assemblyBytes = bytePool.Rent ((int)decompressedLength);
int decoded = LZ4Codec.Decode (sourceBytes, 0, inputLength, assemblyBytes, 0, (int)decompressedLength);
if (decoded != (int)decompressedLength) {
Console.Error.WriteLine ($" Failed to decompress LZ4 data of {fileName} (decoded: {decoded})");
retVal = false;
} else {
string outputDir = Path.GetDirectoryName (outputFile);
if (!String.IsNullOrEmpty (outputDir)) {
Directory.CreateDirectory (outputDir);
}
using (var fs = File.Open (outputFile, FileMode.Create, FileAccess.Write)) {
fs.Write (assemblyBytes, 0, assemblyBytes.Length);
fs.Flush ();
}
Console.WriteLine ($" uncompressed to: {outputFile}");
}

bytePool.Return (sourceBytes);
bytePool.Return (assemblyBytes);
} else {
Console.WriteLine ($" assembly is not compressed");
}
}

return retVal;
}

static bool UncompressDLL (string filePath, string prefix)
{
using (var fs = File.Open (filePath, FileMode.Open, FileAccess.Read)) {
return UncompressDLL (fs, filePath, filePath, prefix);
}
}

static bool UncompressFromAPK (string filePath, string assembliesPath)
{
string prefix = $"uncompressed-{Path.GetFileNameWithoutExtension (filePath)}{Path.DirectorySeparatorChar}";
using (ZipArchive apk = ZipArchive.Open (filePath, FileMode.Open)) {
foreach (ZipEntry entry in apk) {
if (!entry.FullName.StartsWith (assembliesPath, StringComparison.Ordinal)) {
continue;
}

if (!entry.FullName.EndsWith (".dll", StringComparison.Ordinal)) {
continue;
}

using (var stream = new MemoryStream ()) {
entry.Extract (stream);
stream.Seek (0, SeekOrigin.Begin);
UncompressDLL (stream, $"{filePath}!{entry.FullName}", entry.FullName, prefix);
}
}
}

return true;
}

static int Main (string[] args)
{
if (args.Length == 0) {
return Usage ();
}

bool haveErrors = false;
foreach (string file in args) {
string ext = Path.GetExtension (file);
if (String.Compare (".dll", ext, StringComparison.OrdinalIgnoreCase) == 0) {
if (!UncompressDLL (file, "uncompressed-")) {
haveErrors = true;
}
continue;
}

if (String.Compare (".apk", ext, StringComparison.OrdinalIgnoreCase) == 0) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be handy to extend to handle .aab files as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Support for AAB added :)

if (!UncompressFromAPK (file, "assemblies/")) {
haveErrors = true;
}
continue;
}

if (String.Compare (".aab", ext, StringComparison.OrdinalIgnoreCase) == 0) {
if (!UncompressFromAPK (file, "base/root/assemblies/")) {
haveErrors = true;
}
continue;
}
}

return haveErrors ? 1 : 0;
}
}
}
3 changes: 3 additions & 0 deletions tools/scripts/decompress-assemblies
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
truepath=$(readlink "$0" || echo "$0")
exec mono --debug "${truepath}.exe" "$@"