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;
|
package com.lyndir.masterpassword.impl;
|
||||||
|
|
||||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
|
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.Locale;
|
import java.util.*;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -43,71 +43,161 @@ public final class Native {
|
|||||||
private static final String NATIVES_PATH = "lib";
|
private static final String NATIVES_PATH = "lib";
|
||||||
|
|
||||||
@SuppressWarnings({ "HardcodedFileSeparator", "LoadLibraryWithNonConstantString" })
|
@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 to load the library using the native system.
|
||||||
try {
|
try {
|
||||||
System.loadLibrary( name );
|
System.loadLibrary( name );
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
catch (@SuppressWarnings("ErrorNotRethrown") final UnsatisfiedLinkError ignored) {
|
catch (@SuppressWarnings("ErrorNotRethrown") final UnsatisfiedLinkError ignored) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to find and open a stream to the packaged library resource.
|
// Try to find and open a stream to the packaged library resource.
|
||||||
try {
|
String library = System.mapLibraryName( name );
|
||||||
String library = System.mapLibraryName( name );
|
int libraryDot = library.lastIndexOf( EXTENSION_SEPARATOR );
|
||||||
int libraryDot = library.lastIndexOf( EXTENSION_SEPARATOR );
|
String libraryName = (libraryDot > 0)? library.substring( 0, libraryDot ): library;
|
||||||
String libraryName = (libraryDot > 0)? library.substring( 0, libraryDot ): library;
|
String libraryExtension = (libraryDot > 0)? library.substring( libraryDot ): ".lib";
|
||||||
String libraryExtension = (libraryDot > 0)? library.substring( libraryDot ): ".lib";
|
|
||||||
String libraryResource = getLibraryResource( library );
|
|
||||||
InputStream libraryStream = context.getResourceAsStream( libraryResource );
|
|
||||||
if (libraryStream == null)
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Library: " + name + " (" + libraryResource + "), not found in class loader for: " + context );
|
|
||||||
|
|
||||||
// Write the library resource to a temporary file.
|
@Nullable
|
||||||
File libraryFile = File.createTempFile( libraryName, libraryExtension );
|
File libraryFile = null;
|
||||||
FileOutputStream libraryFileStream = new FileOutputStream( libraryFile );
|
Set<String> libraryResources = getLibraryResources( library );
|
||||||
|
for (final String libraryResource : libraryResources) {
|
||||||
try {
|
try {
|
||||||
libraryFile.deleteOnExit();
|
InputStream libraryStream = context.getResourceAsStream( libraryResource );
|
||||||
ByteStreams.copy( libraryStream, libraryFileStream );
|
if (libraryStream == null) {
|
||||||
}
|
logger.dbg( "No resource for library: %s", libraryResource );
|
||||||
finally {
|
continue;
|
||||||
libraryFileStream.close();
|
}
|
||||||
libraryStream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the library from the temporary file.
|
// Write the library resource to a temporary file.
|
||||||
System.load( libraryFile.getAbsolutePath() );
|
libraryFile = File.createTempFile( libraryName, libraryExtension );
|
||||||
}
|
FileOutputStream libraryFileStream = new FileOutputStream( libraryFile );
|
||||||
catch (final IOException e) {
|
try {
|
||||||
throw new IllegalStateException( "Couldn't extract library: " + name, e );
|
libraryFile.deleteOnExit();
|
||||||
|
ByteStreams.copy( libraryStream, libraryFileStream );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
libraryFileStream.close();
|
||||||
|
libraryStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the library from the temporary file.
|
||||||
|
System.load( libraryFile.getAbsolutePath() );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
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
|
@Nonnull
|
||||||
private static String getLibraryResource(final String library) {
|
private static Set<String> getLibraryResources(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 );
|
|
||||||
|
|
||||||
// Standardize system naming in accordance with masterpassword-core.
|
// Standardize system naming in accordance with masterpassword-core.
|
||||||
if (system.contains( "windows" ))
|
Sys system = Sys.findCurrent();
|
||||||
system = "windows";
|
|
||||||
else if (system.contains( "mac os x" ) || system.contains( "darwin" ) || system.contains( "osx" ))
|
|
||||||
system = "macos";
|
|
||||||
else
|
|
||||||
system = "linux";
|
|
||||||
|
|
||||||
// Standardize architecture naming in accordance with masterpassword-core.
|
// Standardize architecture naming in accordance with masterpassword-core.
|
||||||
if (ImmutableList.of( "arm", "arm-v7", "armv7", "arm32" ).contains( architecture ))
|
Collection<Arch> architectures = new LinkedHashSet<>();
|
||||||
architecture = "arm";
|
architectures.add( Arch.findCurrent() );
|
||||||
else if (architecture.startsWith( "arm" ))
|
architectures.addAll( Arrays.asList( Arch.values() ) );
|
||||||
architecture = "arm64";
|
|
||||||
else if (ImmutableList.of( "x86_64", "amd64", "x64", "x86-64" ).contains( architecture ))
|
|
||||||
architecture = "x86_64";
|
|
||||||
else
|
|
||||||
architecture = "x86";
|
|
||||||
|
|
||||||
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