Refactor Native to try and load other architectures.
This commit is contained in:
parent
d5551c8c8c
commit
3cbb063926
@ -18,14 +18,14 @@
|
||||
|
||||
package com.lyndir.masterpassword.impl;
|
||||
|
||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.io.*;
|
||||
import java.util.Locale;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -43,30 +43,35 @@ public final class Native {
|
||||
private static final String NATIVES_PATH = "lib";
|
||||
|
||||
@SuppressWarnings({ "HardcodedFileSeparator", "LoadLibraryWithNonConstantString" })
|
||||
public static void load(final Class<?> context, final String name) {
|
||||
public static boolean load(final Class<?> context, final String name) {
|
||||
|
||||
// Try to load the library using the native system.
|
||||
try {
|
||||
System.loadLibrary( name );
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
catch (@SuppressWarnings("ErrorNotRethrown") final UnsatisfiedLinkError ignored) {
|
||||
}
|
||||
|
||||
// Try to find and open a stream to the packaged library resource.
|
||||
try {
|
||||
String library = System.mapLibraryName( name );
|
||||
int libraryDot = library.lastIndexOf( EXTENSION_SEPARATOR );
|
||||
String libraryName = (libraryDot > 0)? library.substring( 0, libraryDot ): library;
|
||||
String libraryExtension = (libraryDot > 0)? library.substring( libraryDot ): ".lib";
|
||||
String libraryResource = getLibraryResource( library );
|
||||
|
||||
@Nullable
|
||||
File libraryFile = null;
|
||||
Set<String> libraryResources = getLibraryResources( library );
|
||||
for (final String libraryResource : libraryResources) {
|
||||
try {
|
||||
InputStream libraryStream = context.getResourceAsStream( libraryResource );
|
||||
if (libraryStream == null)
|
||||
throw new IllegalStateException(
|
||||
"Library: " + name + " (" + libraryResource + "), not found in class loader for: " + context );
|
||||
if (libraryStream == null) {
|
||||
logger.dbg( "No resource for library: %s", libraryResource );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Write the library resource to a temporary file.
|
||||
File libraryFile = File.createTempFile( libraryName, libraryExtension );
|
||||
libraryFile = File.createTempFile( libraryName, libraryExtension );
|
||||
FileOutputStream libraryFileStream = new FileOutputStream( libraryFile );
|
||||
try {
|
||||
libraryFile.deleteOnExit();
|
||||
@ -79,35 +84,120 @@ public final class Native {
|
||||
|
||||
// Load the library from the temporary file.
|
||||
System.load( libraryFile.getAbsolutePath() );
|
||||
return true;
|
||||
}
|
||||
catch (final IOException e) {
|
||||
throw new IllegalStateException( "Couldn't extract library: " + name, e );
|
||||
catch (@SuppressWarnings("ErrorNotRethrown") final IOException | UnsatisfiedLinkError e) {
|
||||
logger.dbg( e, "Couldn't load library: %s", libraryResource );
|
||||
|
||||
if (libraryFile != null)
|
||||
if (libraryFile.exists() && !libraryFile.delete())
|
||||
logger.wrn( "Couldn't clean up library file: %s", libraryFile );
|
||||
libraryFile = null;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static String getLibraryResource(final String library) {
|
||||
String system = ifNotNullElse( System.getProperty( "os.name" ), "linux" ).toLowerCase( Locale.ROOT );
|
||||
String architecture = ifNotNullElse( System.getProperty( "os.arch" ), "x86" ).toLowerCase( Locale.ROOT );
|
||||
|
||||
private static Set<String> getLibraryResources(final String library) {
|
||||
// Standardize system naming in accordance with masterpassword-core.
|
||||
if (system.contains( "windows" ))
|
||||
system = "windows";
|
||||
else if (system.contains( "mac os x" ) || system.contains( "darwin" ) || system.contains( "osx" ))
|
||||
system = "macos";
|
||||
else
|
||||
system = "linux";
|
||||
Sys system = Sys.findCurrent();
|
||||
|
||||
// Standardize architecture naming in accordance with masterpassword-core.
|
||||
if (ImmutableList.of( "arm", "arm-v7", "armv7", "arm32" ).contains( architecture ))
|
||||
architecture = "arm";
|
||||
else if (architecture.startsWith( "arm" ))
|
||||
architecture = "arm64";
|
||||
else if (ImmutableList.of( "x86_64", "amd64", "x64", "x86-64" ).contains( architecture ))
|
||||
architecture = "x86_64";
|
||||
else
|
||||
architecture = "x86";
|
||||
Collection<Arch> architectures = new LinkedHashSet<>();
|
||||
architectures.add( Arch.findCurrent() );
|
||||
architectures.addAll( Arrays.asList( Arch.values() ) );
|
||||
|
||||
return Joiner.on( RESOURCE_SEPARATOR ).join( "", NATIVES_PATH, system, architecture, library );
|
||||
ImmutableSet.Builder<String> resources = ImmutableSet.builder();
|
||||
for (final Arch arch : architectures)
|
||||
resources.add( Joiner.on( RESOURCE_SEPARATOR ).join( "", NATIVES_PATH, system, arch, library ) );
|
||||
|
||||
return resources.build();
|
||||
}
|
||||
|
||||
private enum Sys implements Predicate<String> {
|
||||
windows {
|
||||
@Override
|
||||
public boolean test(final String system) {
|
||||
return system.contains( "windows" );
|
||||
}
|
||||
},
|
||||
macos {
|
||||
@Override
|
||||
public boolean test(final String system) {
|
||||
return system.contains( "mac os x" ) || system.contains( "darwin" ) || system.contains( "osx" );
|
||||
}
|
||||
},
|
||||
linux {
|
||||
@Override
|
||||
public boolean test(final String system) {
|
||||
return system.contains( "linux" );
|
||||
}
|
||||
};
|
||||
|
||||
@Nonnull
|
||||
public static Sys findCurrent() {
|
||||
return find( System.getProperty( "os.name" ) );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Sys find(@Nullable String name) {
|
||||
if (name != null) {
|
||||
name = name.toLowerCase( Locale.ROOT );
|
||||
|
||||
for (final Sys sys : values())
|
||||
if (sys.test( name ))
|
||||
return sys;
|
||||
}
|
||||
|
||||
return linux;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private enum Arch implements Predicate<String> {
|
||||
arm {
|
||||
@Override
|
||||
public boolean test(final String architecture) {
|
||||
return ImmutableList.of( "arm", "arm-v7", "armv7", "arm32" ).contains( architecture );
|
||||
}
|
||||
},
|
||||
arm64 {
|
||||
@Override
|
||||
public boolean test(final String architecture) {
|
||||
return architecture.startsWith( "arm" ) && !arm.test( architecture );
|
||||
}
|
||||
},
|
||||
x86_64 {
|
||||
@Override
|
||||
public boolean test(final String architecture) {
|
||||
return ImmutableList.of( "x86_64", "amd64", "x64", "x86-64" ).contains( architecture );
|
||||
}
|
||||
},
|
||||
x86 {
|
||||
@Override
|
||||
public boolean test(final String architecture) {
|
||||
return ImmutableList.of( "x86", "i386", "i686" ).contains( architecture );
|
||||
}
|
||||
};
|
||||
|
||||
@Nonnull
|
||||
public static Arch findCurrent() {
|
||||
return find( System.getProperty( "os.arch" ) );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Arch find(@Nullable String name) {
|
||||
if (name != null) {
|
||||
name = name.toLowerCase( Locale.ROOT );
|
||||
|
||||
for (final Arch arch : values())
|
||||
if (arch.test( name ))
|
||||
return arch;
|
||||
}
|
||||
|
||||
return x86;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user