Merged utilities from common + bootstrap into single project.

This commit is contained in:
nathan 2017-02-10 13:59:05 +01:00
parent ffa0304f9e
commit a7548cad84
15 changed files with 2700 additions and 0 deletions

View File

@ -21,5 +21,6 @@
<orderEntry type="library" name="bouncyCastle bcpkix-jdk15on" level="application" />
<orderEntry type="library" name="reflectasm" level="application" />
<orderEntry type="library" name="lz4_xxhash" level="application" />
<orderEntry type="library" name="lzma-java" level="application" />
</component>
</module>

364
src/dorkbox/exit/Exit.java Normal file
View File

@ -0,0 +1,364 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.exit;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import dorkbox.util.OS;
/**
* The EXIT system uses ERRORS to exit the application. We must make sure NOT to swallow them higher up! -- so don't catch "throwable"!
*/
public final class Exit {
/**
* Used to set the data that will be
* 1) used for relaunch,
* 2) used to display an error message on exit
*/
private static native void setExitError(String data);
private static native boolean isNative0();
/**
* Check to see if we are native.
* Used for determining how exit's are handled.
*/
public static final boolean isNative() {
try {
return isNative0();
} catch (Throwable t) {
return false;
}
}
// MIN/MAX values are -128 - 127, because of parent process limitations (anything over 127 will be converted to negative)
private static int UNDEFINED = -1; // must match C source (also anything < 0)
private static int NORMAL = 0; // must match C source
private static int FAILED_CONFIG = 1; // when we are trying to configure something, and it fails. Generally this is for required configurations
private static int FAILED_INIT = 2;
private static int FAILED_SECURITY = 3;
// must match C source!!
private static int RESERVED = 100; // must match C source
private static List<Integer> RESERVED_LIST = new ArrayList<Integer>(2);
private static int SAVED_IN_LOG_FILE = 101; // must match C source
private static int RESTART = 102; // must match C source
private static int UPGRADE_EXECUTABLE = 103; // must match C source
static {
RESERVED_LIST.add(new Integer(SAVED_IN_LOG_FILE));
RESERVED_LIST.add(new Integer(RESTART));
RESERVED_LIST.add(new Integer(UPGRADE_EXECUTABLE));
}
// so, it is important to observe, that WHILE the application is starting (Launcher.java),
// throwing exceptions is ACCEPTABLE. Afterwards, we MUST rely on the blocking structure to notify
// the main thread, so it can return normally.
private static AtomicInteger exitValue = new AtomicInteger(NORMAL);
private static ExitBase exitError = null;
private Exit() {}
// This is what tells us that we are DONE launching, and have moved onto the bootstrap.
public static int getExitValue() {
_setExitData(exitError);
int exit = exitValue.get();
if (exit > RESERVED) {
if (RESERVED_LIST.contains(exitError)) {
return exit;
} else {
setExitError("You cannot use any number greater than 99");
return RESERVED;
}
} else {
return exit;
}
}
/**
* Only used on the inside of a thrown exception by the main thread
*
* <p>
* sets the exit data (ONLY IF there isn't already an error set in the system) then gets the return code
*/
public static int getExitDuringException(ExitBase exitError) {
if (Exit.exitError != null) {
_setExitData(Exit.exitError);
} else {
_setExitData(exitError);
}
// just in case.
int exit = exitValue.get();
if (exit > RESERVED) {
if (RESERVED_LIST.contains(exitError)) {
return exit;
} else {
setExitError("You cannot use any number greater than 99");
return RESERVED;
}
} else {
return exit;
}
}
/**
* Writes a message to the log file
*/
public static void writeToLogFile(String title, String message) {
try {
Writer output = new BufferedWriter(new FileWriter("error.log", true));
try {
if (message != null) {
// FileWriter always assumes default encoding is OK
if (title != null) {
output.write(title);
output.write(OS.LINE_SEPARATOR + " ");
}
output.write(new java.util.Date() + OS.LINE_SEPARATOR + " ");
output.write(message);
output.write(OS.LINE_SEPARATOR);
} else {
output.write("Execption thrown! Unknown error.");
}
output.write(OS.LINE_SEPARATOR);
} finally {
output.close();
}
} catch (IOException e) {
}
}
/**
* called by the uncaught exception hander.
*/
public static void handleUncaughtException(Throwable error) {
// only manage this if it's not on purpose!
if (!(error instanceof ExitBase)) {
// Not always undefined, although sometimes it is.
String message = error.getMessage();
if (message == null) {
message = Exit.getStackStrace(error);
}
Exit.writeToLogFile("Uncaught Exception: " + error.getClass(), message);
// if we are launching, then throw the error. If we FINISHED launching, trip the block
// if we are closing (happens with a LEGIT error), then do nothing, since we are already
// handling it.
_throwIfLaunching(new ExitError(Exit.UNDEFINED,
"Abnormal termination from an uncaught exception! See log file.)"));
}
}
/**
* Undefined/unknown exit, and the info has been written to the log file.
* @param string
* @return
*/
public static int Undefined(Throwable e) {
// Not always undefined, although sometimes it is.
String message = e.getMessage();
if (message == null) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(8196);
PrintStream printStream = new PrintStream(byteArrayOutputStream);
e.printStackTrace(printStream);
message = byteArrayOutputStream.toString();
printStream.close();
}
message = e.getClass().toString() + " : " + message;
// undefined exit! The launcher will restart the JVM in this case
Exit.writeToLogFile("Error", message);
// will actually return the ACTUAL exit error, if there is one.
return Generic(Exit.UNDEFINED, "Undefined exception! Saved in log file.", message);
}
/**
* Exit normally (from the launcher).
*/
public static int Normal() {
return Generic(Exit.NORMAL, "Normal exit called.");
}
/**
* when we are trying to configure something, and it fails. Generally this is for required configurations
*/
public static int FailedConfiguration(String errorMessage, Throwable throwable) {
return Generic(Exit.FAILED_CONFIG, "FailedConfiguration called: " + errorMessage, throwable);
}
/**
* when we are trying to configure something, and it fails. Generally this is for required configurations
*/
public static int FailedInitialization(Throwable throwable) {
return Generic(Exit.FAILED_INIT, "FailedInitialization called: " + throwable.getMessage(), throwable);
}
public static int FailedConfiguration(String errorMessage) {
return Generic(Exit.FAILED_CONFIG, "FailedConfiguration called: " + errorMessage);
}
public static int FailedInitialization(String errorMessage, Throwable throwable) {
return Generic(Exit.FAILED_INIT, "FailedInitialization called: " + errorMessage, throwable);
}
public static int FailedInitialization(String errorMessage) {
return Generic(Exit.FAILED_INIT, "FailedInitialization called: " + errorMessage);
}
public static int FailedSecurity(Throwable throwable) {
return Generic(Exit.FAILED_SECURITY, "FailedSecurity called: " + throwable.getMessage(), throwable);
}
public static int FailedSecurity(String errorMessage, Throwable throwable) {
return Generic(Exit.FAILED_SECURITY, "FailedSecurity called: " + errorMessage, throwable);
}
public static int FailedSecurity(String errorMessage) {
return Generic(Exit.FAILED_SECURITY, "FailedSecurity called: " + errorMessage);
}
public static int Generic(int exitCode, String errorMessage, Throwable throwable) {
return Generic(exitCode, errorMessage + OS.LINE_SEPARATOR + throwable.getClass() + OS.LINE_SEPARATOR + throwable.getMessage());
}
public static int Generic(int exitCode, String errorMessage) {
// if we are launching, then throw the error. If we FINISHED launching, trip the block
_throwIfLaunching(new ExitError(exitCode, errorMessage));
return exitCode;
}
public static int Generic(int exitCode, String errorTitle, String errorMessage) {
// if we are launching, then throw the error. If we FINISHED launching, trip the block
_throwIfLaunching(new ExitError(exitCode, errorTitle, errorMessage));
return exitCode;
}
/**
* restart the application with the current arguments.
* If we need to modify launch args, use the ini file. (or create a new one)
*/
public static void Restart() {
_throwIfLaunching(new ExitRestart(Exit.RESTART));
}
/**
* Specify that we want to upgrade the launcher executable. Other types of upgrade should use
* restart, where the launcher will automatically detect and upgrade the components in place.
*/
public static void UpgradeExectuable() {
_throwIfLaunching(new ExitRestart(Exit.UPGRADE_EXECUTABLE));
}
static void _setExitData(ExitBase e) {
if (e == null) {
return;
}
exitValue.set(e.getExitCode());
// exitData is passed to the launcher.
if (e.getMessage() != null) {
String message = e.getMessage();
if (isNative()) {
if (e.getTitle() != null) {
// can set the title if we want to. Normally it's just the program name.
setExitError("<title>" + e.getTitle() + "</title>" + OS.LINE_SEPARATOR + message);
} else {
setExitError(message);
}
}
}
}
static void _setExitCode(int exitCode) {
exitValue.set(exitCode);
}
// throw error if we are still launcher, otherwise set and notify the block
static void _throwIfLaunching(ExitBase exitError) {
// save the error. It's not always passed up the chain.
if (exitError != null && Exit.exitError == null) {
Exit.exitError = exitError;
}
// throw the error. This makes sure we exit/quit the thread we are currently in.
// we will end up in our "uncaught exception handler"!!
if (exitError != null) {
throw exitError;
} else {
throw new ExitError(Exit.FAILED_INIT, "Unable to have a null errorMessage!");
}
}
/**
* Utility method to get the stack trace from an exception, and convert it to a string.
*/
public static String getStackStrace(Throwable throwable) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(8196);
PrintStream printStream = new PrintStream(byteArrayOutputStream);
throwable.printStackTrace(printStream);
String message = byteArrayOutputStream.toString();
printStream.flush();
printStream.close();
return message;
}
@Override
public final Object clone() throws java.lang.CloneNotSupportedException {
throw new java.lang.CloneNotSupportedException();
}
public final void writeObject(ObjectOutputStream out) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
public final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.exit;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
//package scope, as we don't want to accidentally let someone "catch" this error.
class ExitBase extends Error {
private static final long serialVersionUID = 546657685093303326L;
private final String message;
private final int exitCode;
private final String title;
ExitBase(int exitCode) {
this(exitCode, null, null);
}
ExitBase(int exitCode, String message) {
this(exitCode, null, message);
}
ExitBase(int exitCode, String title, String message) {
this.exitCode = exitCode;
this.title = title;
this.message = message;
}
public final String getTitle() {
return this.title;
}
@Override
public final String getMessage() {
return this.message;
}
public final int getExitCode() {
return this.exitCode;
}
@Override
public final Object clone() throws java.lang.CloneNotSupportedException {
throw new java.lang.CloneNotSupportedException();
}
public final void writeObject(ObjectOutputStream out) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
public final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.exit;
public final class ExitError extends ExitBase {
private static final long serialVersionUID = 4291020084877555138L;
public ExitError(int exitCode) {
super(exitCode);
}
public ExitError(int exitCode, String message) {
super(exitCode, message);
}
public ExitError(int exitCode, String title, String message) {
super(exitCode, title, message);
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.exit;
public final class ExitRestart extends ExitBase {
private static final long serialVersionUID = -3569173102400803538L;
public ExitRestart(int exitCode) {
super(exitCode);
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.urlHandler;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
public
class BoxHandler extends URLStreamHandler {
//
// This is also in the (ClassLoader project) Node!!!, but I didn't want to force a dependency just because of this.
//
//
// The following must ALL be valid URI symbols, defined by RFC 3986: http://tools.ietf.org/html/rfc3986#section-2
//
// ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=.
//
// Any other character needs to be encoded with the percent-encoding (%hh). Each part of the URI has further restrictions about
// what characters need to be represented by an percent-encoded word.
/** This is exclusively used to identify if a resource we are requesting is inside of a jar that was already parsed */
static final char jarUrlSeperator = '*';
static final char jarPathToken = '/';
static final char packageToken = '.';
static final String protocol = "box";
static final String protocolFull = protocol + ":/";
static final int protocolLength = protocolFull.length();
public BoxHandler() {
}
@Override
protected URLConnection openConnection(URL url) throws IOException {
return new BoxURLConnection(url);
}
/**
* Makes sure that when creating paths, etc, from this URL, that we also make sure to add a token, so
* our classloader knows where to find the resource.
*
* This absolutely MUST not end in special characters. it must be the letters/numbers or a "/". NOTHING ELSE.
*/
@Override
protected String toExternalForm(URL url) {
// ONLY append jarUrlSeperator if we haven't already done so!
String externalForm = super.toExternalForm(url);
char jarurlseperator = jarUrlSeperator;
if (externalForm.indexOf(jarurlseperator) == -1) {
int length = externalForm.length();
StringBuilder stringBuilder = new StringBuilder(length + 1);
stringBuilder.append(externalForm);
if (length > 1 && externalForm.charAt(length-1) == jarPathToken) {
stringBuilder.insert(length, jarurlseperator);
} else {
stringBuilder.append(jarurlseperator);
}
return stringBuilder.toString();
} else {
// we've already modified it, don't do it again.
return externalForm;
}
}
@Override
public final Object clone() throws java.lang.CloneNotSupportedException {
throw new java.lang.CloneNotSupportedException();
}
public final void writeObject(ObjectOutputStream out) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
public final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.urlHandler;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
public
class BoxHandlerFactory implements URLStreamHandlerFactory {
private final BoxHandler transparentJar;
public
BoxHandlerFactory(BoxHandler transparentJar) {
this.transparentJar = transparentJar;
}
@Override
public
URLStreamHandler createURLStreamHandler(String protocol) {
// transparent jar handler.
if (BoxHandler.protocol.equals(protocol)) {
return this.transparentJar;
}
else {
// use the default URLStreamHandlers
return null;
}
}
@Override
public final
Object clone() throws java.lang.CloneNotSupportedException {
throw new java.lang.CloneNotSupportedException();
}
public final
void writeObject(ObjectOutputStream out) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
public final
void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
}

View File

@ -0,0 +1,153 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.urlHandler;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.net.URLConnection;
/**
* A 'Box' URL is nothing like a JAR/ZIP, HOWEVER, it appears as though it is a jar/zip file.
*/
public
class BoxURLConnection extends URLConnection {
public
BoxURLConnection(URL url) {
super(url);
}
/**
* @return the base name of the url. This will be the internal container (inside the main jar file) that actually contains our resource.
* This will be empty for class files.
*/
public
String getContainerName() {
String spec = this.url.getPath();
int separator = spec.indexOf(BoxHandler.jarUrlSeperator);
int length = spec.length();
if (separator > 0 && separator != length) {
if (spec.charAt(0) == '/') {
if (spec.charAt(separator - 1) == '/') {
String substring = spec.substring(1, separator - 1);
return substring;
}
else {
String substring = spec.substring(1, separator);
return substring;
}
}
else {
if (spec.charAt(separator - 1) == '/') {
String substring = spec.substring(0, separator - 1);
return substring;
}
else {
String substring = spec.substring(0, separator);
return substring;
}
}
}
else {
return "";
}
}
/**
* @return the name of the entry that is nested inside an internal resource. This would be the name of a file, where the base URL would
* be the internal resource container.
*/
public
String getResourceName() {
String spec = this.url.getPath();
int separator = spec.indexOf(BoxHandler.jarUrlSeperator);
if (separator > -1 && separator != spec.length()) {
if (spec.charAt(separator + 1) == '/') {
return spec.substring(separator + 2);
}
else {
return spec.substring(separator + 1);
}
}
else {
return "";
}
}
@Override
public
void connect() throws IOException {
this.connected = true;
}
@Override
public
int getContentLength() {
// if we are inside our box file, this will return -1, so inputstreams will be used (which they have to be...)
// if we return anything other than -1, then our box resource will try to be opened like a file (which we don't want)
return -1;
}
@Override
public
long getLastModified() {
return 0;
}
/**
* Loads the resources stream, if applicable. You cannot load classes using this method
*/
@Override
public
InputStream getInputStream() throws IOException {
String path = this.url.getPath();
int length = BoxHandler.protocolLength;
StringBuilder stringBuilder = new StringBuilder(path.length() + length);
stringBuilder.append(BoxHandler.protocolFull);
if (path.charAt(0) == '/') {
stringBuilder.deleteCharAt(length - 1);
}
stringBuilder.append(path);
InputStream is = getClass().getClassLoader()
.getResourceAsStream(stringBuilder.toString());
return is;
}
@Override
public final
Object clone() throws java.lang.CloneNotSupportedException {
throw new java.lang.CloneNotSupportedException();
}
public final
void writeObject(ObjectOutputStream out) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
public final
void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
}

View File

@ -0,0 +1,660 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util;
import java.util.Arrays;
/** A very fast and memory efficient class to encode and decode to and from BASE64 in full accordance
* with RFC 2045.<br><br>
* On Windows XP sp1 with 1.4.2_04 and later ;), this encoder and decoder is about 10 times faster
* on small arrays (10 - 1000 bytes) and 2-3 times as fast on larger arrays (10000 - 1000000 bytes)
* compared to <code>sun.misc.Encoder()/Decoder()</code>.<br><br>
*
* On byte arrays the encoder is about 20% faster than Jakarta Commons Base64 Codec for encode and
* about 50% faster for decoding large arrays. This implementation is about twice as fast on very small
* arrays (&lt 30 bytes). If source/destination is a <code>String</code> this
* version is about three times as fast due to the fact that the Commons Codec result has to be recoded
* to a <code>String</code> from <code>byte[]</code>, which is very expensive.<br><br>
*
* This encode/decode algorithm doesn't create any temporary arrays as many other codecs do, it only
* allocates the resulting array. This produces less garbage and it is possible to handle arrays twice
* as large as algorithms that create a temporary array. (E.g. Jakarta Commons Codec). It is unknown
* whether Sun's <code>sun.misc.Encoder()/Decoder()</code> produce temporary arrays but since performance
* is quite low it probably does.<br><br>
*
* The encoder produces the same output as the Sun one except that the Sun's encoder appends
* a trailing line separator if the last character isn't a pad. Unclear why but it only adds to the
* length and is probably a side effect. Both are in conformance with RFC 2045 though.<br>
* Commons codec seem to always add a trailing line separator.<br><br>
*
* <b>Note!</b>
* The encode/decode method pairs (types) come in three versions with the <b>exact</b> same algorithm and
* thus a lot of code redundancy. This is to not create any temporary arrays for transcoding to/from different
* format types. The methods not used can simply be commented out.<br><br>
*
* There is also a "fast" version of all decode methods that works the same way as the normal ones, but
* has a few demands on the decoded input. Normally though, these fast versions should be used if the source if
* the input is known and it hasn't bee tampered with.<br><br>
*
* If you find the code useful or you find a bug, please send me a note at base64 @ miginfocom . com.
*
* License (BSD):
* ==============
*
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* @version 2.2
* @author Mikael Grev
* Date: 2004-aug-02
* Time: 11:31:11
*/
public class Base64Fast
{
private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
private static final int[] IA = new int[256];
static {
Arrays.fill(IA, -1);
for (int i = 0, iS = CA.length; i < iS; i++) {
IA[CA[i]] = i;
}
IA['='] = 0;
}
// ****************************************************************************************
// * char[] version
// ****************************************************************************************
/** Encodes a raw byte array into a BASE64 <code>char[]</code> representation in accordance with RFC 2045.
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
* little faster.
* @return A BASE64 encoded array. Never <code>null</code>.
*/
public final static char[] encodeToChar(byte[] sArr, boolean lineSep)
{
sArr = sArr != null ? sArr : new byte[0];
// Check special case
int sLen = sArr.length;
if (sLen == 0) {
return new char[0];
}
int eLen = sLen / 3 * 3; // Length of even 24-bits.
int cCnt = (sLen - 1) / 3 + 1 << 2; // Returned character count
int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
char[] dArr = new char[dLen];
// Encode even 24-bits
for (int s = 0, d = 0, cc = 0; s < eLen;) {
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | sArr[s++] & 0xff;
// Encode the int into four chars
dArr[d++] = CA[i >>> 18 & 0x3f];
dArr[d++] = CA[i >>> 12 & 0x3f];
dArr[d++] = CA[i >>> 6 & 0x3f];
dArr[d++] = CA[i & 0x3f];
// Add optional line separator
if (lineSep && ++cc == 19 && d < dLen - 2) {
dArr[d++] = '\r';
dArr[d++] = '\n';
cc = 0;
}
}
// Pad and encode last bits if source isn't even 24 bits.
int left = sLen - eLen; // 0 - 2.
if (left > 0) {
// Prepare the int
int i = (sArr[eLen] & 0xff) << 10 | (left == 2 ? (sArr[sLen - 1] & 0xff) << 2 : 0);
// Set last four chars
dArr[dLen - 4] = CA[i >> 12];
dArr[dLen - 3] = CA[i >>> 6 & 0x3f];
dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '=';
dArr[dLen - 1] = '=';
}
return dArr;
}
/** Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with
* and without line separators.
* @param sArr The source array. <code>null</code> or length 0 will return an empty array.
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
*/
public final static byte[] decode(char[] sArr)
{
sArr = sArr != null ? sArr : new char[0];
// Check special case
int sLen = sArr.length;
if (sLen == 0) {
return new byte[0];
}
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
// so we don't have to reallocate & copy it later.
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
for (int i = 0; i < sLen; i++) {
if (IA[sArr[i]] < 0) {
sepCnt++;
}
}
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
if ((sLen - sepCnt) % 4 != 0) {
return null;
}
int pad = 0;
for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0;) {
if (sArr[i] == '=') {
pad++;
}
}
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
for (int s = 0, d = 0; d < len;) {
// Assemble three bytes into an int from four "valid" characters.
int i = 0;
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
int c = IA[sArr[s++]];
if (c >= 0) {
i |= c << 18 - j * 6;
} else {
j--;
}
}
// Add the bytes
dArr[d++] = (byte) (i >> 16);
if (d < len) {
dArr[d++]= (byte) (i >> 8);
if (d < len) {
dArr[d++] = (byte) i;
}
}
}
return dArr;
}
/** Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as
* fast as {@link #decode(char[])}. The preconditions are:<br>
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
* + Line separator must be "\r\n", as specified in RFC 2045
* + The array must not contain illegal characters within the encoded string<br>
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0.
*/
public final static byte[] decodeFast(char[] sArr)
{
// Check special case
int sLen = sArr.length;
if (sLen == 0) {
return new byte[0];
}
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
// Trim illegal chars from start
while (sIx < eIx && IA[sArr[sIx]] < 0) {
sIx++;
}
// Trim illegal chars from end
while (eIx > 0 && IA[sArr[eIx]] < 0) {
eIx--;
}
// get the padding count (=) (0, 1 or 2)
int pad = sArr[eIx] == '=' ? sArr[eIx - 1] == '=' ? 2 : 1 : 0; // Count '=' at end.
int cCnt = eIx - sIx + 1; // Content count including possible separators
int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
// Decode all but the last 0 - 2 bytes.
int d = 0;
for (int cc = 0, eLen = len / 3 * 3; d < eLen;) {
// Assemble three bytes into an int from four "valid" characters.
int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
// Add the bytes
dArr[d++] = (byte) (i >> 16);
dArr[d++] = (byte) (i >> 8);
dArr[d++] = (byte) i;
// If line separator, jump over it.
if (sepCnt > 0 && ++cc == 19) {
sIx += 2;
cc = 0;
}
}
if (d < len) {
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
int i = 0;
for (int j = 0; sIx <= eIx - pad; j++) {
i |= IA[sArr[sIx++]] << 18 - j * 6;
}
for (int r = 16; d < len; r -= 8) {
dArr[d++] = (byte) (i >> r);
}
}
return dArr;
}
// ****************************************************************************************
// * byte[] version
// ****************************************************************************************
/** Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045.
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
* little faster.
* @return A BASE64 encoded array. Never <code>null</code>.
*/
public final static byte[] encodeToByte(byte[] sArr, boolean lineSep)
{
return encodeToByte(sArr, 0, sArr != null ? sArr.length : 0, lineSep);
}
/** Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045.
* @param sArr The bytes to convert. If <code>null</code> an empty array will be returned.
* @param sOff The starting position in the bytes to convert.
* @param sLen The number of bytes to convert. If 0 an empty array will be returned.
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
* little faster.
* @return A BASE64 encoded array. Never <code>null</code>.
*/
public final static byte[] encodeToByte(byte[] sArr, int sOff, int sLen, boolean lineSep)
{
// Check special case
if (sArr == null || sLen == 0) {
return new byte[0];
}
int eLen = sLen / 3 * 3; // Length of even 24-bits.
int cCnt = (sLen - 1) / 3 + 1 << 2; // Returned character count
int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
byte[] dArr = new byte[dLen];
// Encode even 24-bits
for (int s = sOff, d = 0, cc = 0; s < sOff + eLen;) {
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | sArr[s++] & 0xff;
// Encode the int into four chars
dArr[d++] = (byte) CA[i >>> 18 & 0x3f];
dArr[d++] = (byte) CA[i >>> 12 & 0x3f];
dArr[d++] = (byte) CA[i >>> 6 & 0x3f];
dArr[d++] = (byte) CA[i & 0x3f];
// Add optional line separator
if (lineSep && ++cc == 19 && d < dLen - 2) {
dArr[d++] = '\r';
dArr[d++] = '\n';
cc = 0;
}
}
// Pad and encode last bits if source isn't an even 24 bits.
int left = sLen - eLen; // 0 - 2.
if (left > 0) {
// Prepare the int
int i = (sArr[sOff + eLen] & 0xff) << 10 | (left == 2 ? (sArr[sOff + sLen - 1] & 0xff) << 2 : 0);
// Set last four chars
dArr[dLen - 4] = (byte) CA[i >> 12];
dArr[dLen - 3] = (byte) CA[i >>> 6 & 0x3f];
dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '=';
dArr[dLen - 1] = '=';
}
return dArr;
}
/** Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
* and without line separators.
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
*/
public final static byte[] decode(byte[] sArr)
{
return decode(sArr, 0, sArr.length);
}
/** Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
* and without line separators.
* @param sArr The source array. <code>null</code> will throw an exception.
* @param sOff The starting position in the source array.
* @param sLen The number of bytes to decode from the source array. Length 0 will return an empty array.
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
*/
public final static byte[] decode(byte[] sArr, int sOff, int sLen)
{
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
// so we don't have to reallocate & copy it later.
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
for (int i = 0; i < sLen; i++) {
if (IA[sArr[sOff + i] & 0xff] < 0) {
sepCnt++;
}
}
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
if ((sLen - sepCnt) % 4 != 0) {
return null;
}
int pad = 0;
for (int i = sLen; i > 1 && IA[sArr[sOff + --i] & 0xff] <= 0;) {
if (sArr[sOff + i] == '=') {
pad++;
}
}
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
for (int s = 0, d = 0; d < len;) {
// Assemble three bytes into an int from four "valid" characters.
int i = 0;
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
int c = IA[sArr[sOff + s++] & 0xff];
if (c >= 0) {
i |= c << 18 - j * 6;
} else {
j--;
}
}
// Add the bytes
dArr[d++] = (byte) (i >> 16);
if (d < len) {
dArr[d++]= (byte) (i >> 8);
if (d < len) {
dArr[d++] = (byte) i;
}
}
}
return dArr;
}
/** Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as
* fast as {@link #decode(byte[])}. The preconditions are:<br>
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
* + Line separator must be "\r\n", as specified in RFC 2045
* + The array must not contain illegal characters within the encoded string<br>
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0.
*/
public final static byte[] decodeFast(byte[] sArr)
{
// Check special case
int sLen = sArr.length;
if (sLen == 0) {
return new byte[0];
}
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
// Trim illegal chars from start
while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0) {
sIx++;
}
// Trim illegal chars from end
while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0) {
eIx--;
}
// get the padding count (=) (0, 1 or 2)
int pad = sArr[eIx] == '=' ? sArr[eIx - 1] == '=' ? 2 : 1 : 0; // Count '=' at end.
int cCnt = eIx - sIx + 1; // Content count including possible separators
int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
// Decode all but the last 0 - 2 bytes.
int d = 0;
for (int cc = 0, eLen = len / 3 * 3; d < eLen;) {
// Assemble three bytes into an int from four "valid" characters.
int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
// Add the bytes
dArr[d++] = (byte) (i >> 16);
dArr[d++] = (byte) (i >> 8);
dArr[d++] = (byte) i;
// If line separator, jump over it.
if (sepCnt > 0 && ++cc == 19) {
sIx += 2;
cc = 0;
}
}
if (d < len) {
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
int i = 0;
for (int j = 0; sIx <= eIx - pad; j++) {
i |= IA[sArr[sIx++]] << 18 - j * 6;
}
for (int r = 16; d < len; r -= 8) {
dArr[d++] = (byte) (i >> r);
}
}
return dArr;
}
// ****************************************************************************************
// * String version
// ****************************************************************************************
/** Encodes a raw byte array into a BASE64 <code>String</code> representation i accordance with RFC 2045.
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
* little faster.
* @return A BASE64 encoded array. Never <code>null</code>.
*/
public final static String encodeToString(byte[] sArr, boolean lineSep)
{
// Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower.
return new String(encodeToChar(sArr, lineSep));
}
/** Decodes a BASE64 encoded <code>String</code>. All illegal characters will be ignored and can handle both strings with
* and without line separators.<br>
* <b>Note!</b> It can be up to about 2x the speed to call <code>decode(str.toCharArray())</code> instead. That
* will create a temporary array though. This version will use <code>str.charAt(i)</code> to iterate the string.
* @param str The source string. <code>null</code> or length 0 will return an empty array.
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
*/
public final static byte[] decode(String str)
{
str = str != null ? str : "";
// Check special case
int sLen = str.length();
if (sLen == 0) {
return new byte[0];
}
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
// so we don't have to reallocate & copy it later.
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
for (int i = 0; i < sLen; i++) {
if (IA[str.charAt(i)] < 0) {
sepCnt++;
}
}
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
if ((sLen - sepCnt) % 4 != 0) {
return null;
}
// Count '=' at end
int pad = 0;
for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;) {
if (str.charAt(i) == '=') {
pad++;
}
}
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
for (int s = 0, d = 0; d < len;) {
// Assemble three bytes into an int from four "valid" characters.
int i = 0;
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
int c = IA[str.charAt(s++)];
if (c >= 0) {
i |= c << 18 - j * 6;
} else {
j--;
}
}
// Add the bytes
dArr[d++] = (byte) (i >> 16);
if (d < len) {
dArr[d++]= (byte) (i >> 8);
if (d < len) {
dArr[d++] = (byte) i;
}
}
}
return dArr;
}
/** Decodes a BASE64 encoded string that is known to be reasonably well formatted. The method is about twice as
* fast as {@link #decode(String)}. The preconditions are:<br>
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
* + Line separator must be "\r\n", as specified in RFC 2045
* + The array must not contain illegal characters within the encoded string<br>
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
* @param s The source string. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0.
*/
public final static byte[] decodeFast(String s)
{
// Check special case
int sLen = s.length();
if (sLen == 0) {
return new byte[0];
}
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
// Trim illegal chars from start
while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0) {
sIx++;
}
// Trim illegal chars from end
while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0) {
eIx--;
}
// get the padding count (=) (0, 1 or 2)
int pad = s.charAt(eIx) == '=' ? s.charAt(eIx - 1) == '=' ? 2 : 1 : 0; // Count '=' at end.
int cCnt = eIx - sIx + 1; // Content count including possible separators
int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0;
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
// Decode all but the last 0 - 2 bytes.
int d = 0;
for (int cc = 0, eLen = len / 3 * 3; d < eLen;) {
// Assemble three bytes into an int from four "valid" characters.
int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)];
// Add the bytes
dArr[d++] = (byte) (i >> 16);
dArr[d++] = (byte) (i >> 8);
dArr[d++] = (byte) i;
// If line separator, jump over it.
if (sepCnt > 0 && ++cc == 19) {
sIx += 2;
cc = 0;
}
}
if (d < len) {
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
int i = 0;
for (int j = 0; sIx <= eIx - pad; j++) {
i |= IA[s.charAt(sIx++)] << 18 - j * 6;
}
for (int r = 16; d < len; r -= 8) {
dArr[d++] = (byte) (i >> r);
}
}
return dArr;
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 2015 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util;
public abstract class ClassResolver {
/**
* A helper class to get the call context. It subclasses SecurityManager to make getClassContext() accessible. An instance of
* CallerResolver only needs to be created, not installed as an actual security manager.
*/
private static final class CallerResolver extends SecurityManager {
@Override
protected Class<?>[] getClassContext() {
return super.getClassContext();
}
}
private static final int CALL_CONTEXT_OFFSET = 3; // may need to change if this class is redesigned
private static final CallerResolver CALLER_RESOLVER;
static {
try {
// This can fail if the current SecurityManager does not allow
// RuntimePermission ("createSecurityManager"):
CALLER_RESOLVER = new CallerResolver();
} catch (SecurityException se) {
throw new RuntimeException("ClassLoaderResolver: could not create CallerResolver: " + se);
}
}
/**
* Indexes into the current method call context with a given offset.
*/
public static Class<?> getCallerClass(final int callerOffset) {
return CALLER_RESOLVER.getClassContext()[CALL_CONTEXT_OFFSET + callerOffset];
}
}

111
src/dorkbox/util/LZMA.java Normal file
View File

@ -0,0 +1,111 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util;
import lzma.sdk.lzma.Decoder;
import lzma.sdk.lzma.Encoder;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class LZMA {
// LZMA (Java) 4.61 2008-11-23
// http://jponge.github.com/lzma-java/
public static final void encode(long fileSize, InputStream input, OutputStream output) throws IOException {
try {
final Encoder encoder = new Encoder();
if (!encoder.setDictionarySize(1 << 23)) {
throw new RuntimeException("Incorrect dictionary size");
}
if (!encoder.setNumFastBytes(273)) {
throw new RuntimeException("Incorrect -fb value");
}
if (!encoder.setMatchFinder(1)) {
throw new RuntimeException("Incorrect -mf value");
}
if (!encoder.setLcLpPb(3, 0, 2)) {
throw new RuntimeException("Incorrect -lc or -lp or -pb value");
}
encoder.setEndMarkerMode(false);
encoder.writeCoderProperties(output);
for (int ii = 0; ii < 8; ii++) {
output.write((int)(fileSize >>> 8 * ii) & 0xFF);
}
encoder.code(input, output, -1, -1, null);
} finally {
input.close();
output.flush();
}
}
public static final ByteArrayOutputStream decode(InputStream input) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(8192);
decode(input, byteArrayOutputStream);
return byteArrayOutputStream;
}
public static final void decode(InputStream input, OutputStream output) throws IOException {
try {
int propertiesSize = 5;
byte[] properties = new byte[propertiesSize];
if (input.read(properties, 0, propertiesSize) != propertiesSize) {
throw new IOException("input .lzma file is too short");
}
Decoder decoder = new Decoder();
if (!decoder.setDecoderProperties(properties)) {
throw new IOException("Incorrect stream properties");
}
long outSize = 0;
for (int i = 0; i < 8; i++)
{
int v = input.read();
if (v < 0) {
throw new IOException("Can't read stream size");
}
outSize |= (long)v << 8 * i;
}
if (!decoder.code(input, output, outSize)) {
throw new IOException("Error in data stream");
}
} finally {
output.flush();
input.close();
}
}
@Override
public final Object clone() throws java.lang.CloneNotSupportedException {
throw new java.lang.CloneNotSupportedException();
}
private final void writeObject(ObjectOutputStream out) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
}

View File

@ -0,0 +1,584 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* Convenience methods for working with resource/file/class locations
*/
public
class LocationResolver {
private static final Pattern SLASH_PATTERN = Pattern.compile("\\\\");
private static
void log(String message) {
System.err.println(prefix() + message);
}
/**
* Normalizes the path. fixes %20 as spaces (in winxp at least). Converts \ -> / (windows slash -> unix slash)
*
* @return a string pointing to the cleaned path
* @throws IOException
*/
private static
String normalizePath(String path) throws IOException {
// make sure the slashes are in unix format.
path = SLASH_PATTERN.matcher(path)
.replaceAll("/");
// Can have %20 as spaces (in winxp at least). need to convert to proper path from URL
return URLDecoder.decode(path, "UTF-8");
}
/**
* Retrieve the location of the currently loaded jar, or possibly null if it was compiled on the fly
*/
public static
File get() {
return get(LocationResolver.class);
}
/**
* Retrieve the location that this classfile was loaded from, or possibly null if the class was compiled on the fly
*/
public static
File get(Class<?> clazz) {
// Get the location of this class
ProtectionDomain pDomain = clazz.getProtectionDomain();
CodeSource cSource = pDomain.getCodeSource();
// file:/X:/workspace/XYZ/classes/ when it's in ide/flat
// jar:/X:/workspace/XYZ/jarname.jar when it's jar
URL loc = cSource.getLocation();
// we don't always have a protection domain (for example, when we compile classes on the fly, from memory)
if (loc == null) {
return null;
}
// Can have %20 as spaces (in winxp at least). need to convert to proper path from URL
try {
File file = new File(normalizePath(loc.getFile())).getAbsoluteFile()
.getCanonicalFile();
return file;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unable to decode file path!", e);
} catch (IOException e) {
throw new RuntimeException("Unable to get canonical file path!", e);
}
}
/**
* Retrieves a URL of a given resourceName. If the resourceName is a directory, the returned URL will be the URL for the directory.
* </p>
* This method searches the disk first (via new {@link File#File(String)}, then by {@link ClassLoader#getResource(String)}, then by
* {@link ClassLoader#getSystemResource(String)}.
*
* @param resourceName the resource name to search for
*
* @return the URL for that given resource name
*/
public static
URL getResource(String resourceName) {
try {
resourceName = normalizePath(resourceName);
} catch (IOException e) {
e.printStackTrace();
}
URL resource = null;
// 1) maybe it's on disk? priority is disk
File file = new File(resourceName);
if (file.canRead()) {
try {
resource = file.toURI()
.toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
// 2) is it in the context classloader
if (resource == null) {
resource = Thread.currentThread()
.getContextClassLoader()
.getResource(resourceName);
}
// 3) is it in the system classloader
if (resource == null) {
// maybe it's in the system classloader?
resource = ClassLoader.getSystemResource(resourceName);
}
// 4) look for it, and log the output (so we can find or debug it)
if (resource == null) {
try {
searchResource(resourceName);
} catch (IOException e) {
e.printStackTrace();
}
}
return resource;
}
/**
* Retrieves an enumeration of URLs of a given resourceName. If the resourceName is a directory, the returned list will be the URLs
* of the contents of that directory. The first URL will always be the directory URL, as returned by {@link #getResource(String)}.
* </p>
* This method searches the disk first (via new {@link File#File(String)}, then by {@link ClassLoader#getResources(String)}, then by
* {@link ClassLoader#getSystemResources(String)}.
*
* @param resourceName the resource name to search for
*
* @return the enumeration of URLs for that given resource name
*/
public static
Enumeration<URL> getResources(String resourceName) {
try {
resourceName = normalizePath(resourceName);
} catch (IOException e) {
e.printStackTrace();
}
Enumeration<URL> resources = null;
try {
// 1) maybe it's on disk? priority is disk
File file = new File(resourceName);
if (file.canRead()) {
ArrayDeque<URL> urlList = new ArrayDeque<URL>(4);
// add self always
urlList.add(file.toURI()
.toURL());
if (file.isDirectory()) {
// add urls of all children
File[] files = file.listFiles();
if (files != null) {
for (int i = 0, n = files.length; i < n; i++) {
urlList.add(files[i].toURI()
.toURL());
}
}
}
resources = new Vector<URL>(urlList).elements();
}
// 2) is it in the context classloader
if (resources == null) {
resources = Thread.currentThread()
.getContextClassLoader()
.getResources(resourceName);
}
// 3) is it in the system classloader
if (resources == null) {
// maybe it's in the system classloader?
resources = ClassLoader.getSystemResources(resourceName);
}
// 4) look for it, and log the output (so we can find or debug it)
if (resources == null) {
searchResource(resourceName);
}
} catch (IOException e) {
e.printStackTrace();
}
return resources;
}
/**
* Retrieves the resource as a stream.
* <p>
* 1) checks the disk in the relative location to the executing app<br/>
* 2) Checks the current thread context classloader <br/>
* 3) Checks the Classloader system resource
*
* @param resourceName the name, including path information (Only valid '\' as the path separator)
*
* @return the resource stream, if it could be found, otherwise null.
*/
public static
InputStream getResourceAsStream(String resourceName) {
try {
resourceName = normalizePath(resourceName);
} catch (IOException e) {
e.printStackTrace();
}
InputStream resourceAsStream = null;
// 1) maybe it's on disk? priority is disk
if (new File(resourceName).canRead()) {
try {
resourceAsStream = new FileInputStream(resourceName);
} catch (FileNotFoundException e) {
// shouldn't happen, but if there is something wonky...
e.printStackTrace();
}
}
// 2) is it in the context classloader
if (resourceAsStream == null) {
resourceAsStream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream(resourceName);
}
// 3) is it in the system classloader
if (resourceAsStream == null) {
// maybe it's in the system classloader?
resourceAsStream = ClassLoader.getSystemResourceAsStream(resourceName);
}
// 4) look for it, and log the output (so we can find or debug it)
if (resourceAsStream == null) {
try {
searchResource(resourceName);
} catch (IOException e) {
e.printStackTrace();
}
}
return resourceAsStream;
}
// via RIVEN at JGO. CC0 as far as I can tell.
public static
void searchResource(String path) throws IOException {
try {
path = normalizePath(path);
} catch (IOException e) {
e.printStackTrace();
}
List<Root> roots = new ArrayList<Root>();
ClassLoader contextClassLoader = Thread.currentThread()
.getContextClassLoader();
if (contextClassLoader instanceof URLClassLoader) {
URL[] urLs = ((URLClassLoader) contextClassLoader).getURLs();
for (URL url : urLs) {
roots.add(new Root(url));
}
System.err.println();
log("SEARCHING: \"" + path + "\"");
for (int attempt = 1; attempt <= 6; attempt++) {
for (Root root : roots) {
if (root.search(path, attempt)) {
return;
}
}
}
log("FAILED: failed to find anything like");
log(" \"" + path + "\"");
log(" in all classpath entries:");
for (Root root : roots) {
final File entry = root.entry;
if (entry != null) {
log(" \"" + entry.getAbsolutePath() + "\"");
}
}
}
else {
throw new IOException("Unable to search for '" + path + "' in the context classloader of type '" + contextClassLoader.getClass() +
"'. Please report this issue with as many specific details as possible (OS, Java version, application version");
}
}
@SuppressWarnings("Duplicates")
private static
class Root {
final File entry;
final List<String> resources = new ArrayList<String>();
public
Root(URL entry) throws IOException {
this.entry = visitRoot(entry, resources);
}
public
boolean search(String path, int attempt) {
try {
path = normalizePath(path);
} catch (IOException e) {
e.printStackTrace();
}
switch (attempt) {
case 1: {
for (String resource : resources) {
if (path.equals(resource)) {
log("SUCCESS: found resource \"" + path + "\" in root: " + entry);
return true;
}
}
break;
}
case 2: {
for (String resource : resources) {
if (path.toLowerCase()
.equals(resource.toLowerCase())) {
log("FOUND: similarly named resource:");
log(" \"" + resource + "\"");
log(" in classpath entry:");
log(" \"" + entry + "\"");
log(" for access use:");
log(" getResourceAsStream(\"/" + resource + "\");");
return true;
}
}
break;
}
case 3: {
for (String resource : resources) {
String r1 = path;
String r2 = resource;
if (r1.contains("/")) {
r1 = r1.substring(r1.lastIndexOf('/') + 1);
}
if (r2.contains("/")) {
r2 = r2.substring(r2.lastIndexOf('/') + 1);
}
if (r1.equals(r2)) {
log("FOUND: mislocated resource:");
log(" \"" + resource + "\"");
log(" in classpath entry:");
log(" \"" + entry + "\"");
log(" for access use:");
log(" getResourceAsStream(\"/" + resource + "\");");
return true;
}
}
break;
}
case 4: {
for (String resource : resources) {
String r1 = path.toLowerCase();
String r2 = resource.toLowerCase();
if (r1.contains("/")) {
r1 = r1.substring(r1.lastIndexOf('/') + 1);
}
if (r2.contains("/")) {
r2 = r2.substring(r2.lastIndexOf('/') + 1);
}
if (r1.equals(r2)) {
log("FOUND: mislocated, similarly named resource:");
log(" \"" + resource + "\"");
log(" in classpath entry:");
log(" \"" + entry + "\"");
log(" for access use:");
log(" getResourceAsStream(\"/" + resource + "\");");
return true;
}
}
break;
}
case 5: {
for (String resource : resources) {
String r1 = path;
String r2 = resource;
if (r1.contains("/")) {
r1 = r1.substring(r1.lastIndexOf('/') + 1);
}
if (r2.contains("/")) {
r2 = r2.substring(r2.lastIndexOf('/') + 1);
}
if (r1.contains(".")) {
r1 = r1.substring(0, r1.lastIndexOf('.'));
}
if (r2.contains(".")) {
r2 = r2.substring(0, r2.lastIndexOf('.'));
}
if (r1.equals(r2)) {
log("FOUND: resource with different extension:");
log(" \"" + resource + "\"");
log(" in classpath entry:");
log(" \"" + entry + "\"");
log(" for access use:");
log(" getResourceAsStream(\"/" + resource + "\");");
return true;
}
}
break;
}
case 6: {
for (String resource : resources) {
String r1 = path.toLowerCase();
String r2 = resource.toLowerCase();
if (r1.contains("/")) {
r1 = r1.substring(r1.lastIndexOf('/') + 1);
}
if (r2.contains("/")) {
r2 = r2.substring(r2.lastIndexOf('/') + 1);
}
if (r1.contains(".")) {
r1 = r1.substring(0, r1.lastIndexOf('.'));
}
if (r2.contains(".")) {
r2 = r2.substring(0, r2.lastIndexOf('.'));
}
if (r1.equals(r2)) {
log("FOUND: similarly named resource with different extension:");
log(" \"" + resource + "\"");
log(" in classpath entry:");
log(" \"" + entry + "\"");
log(" for access use:");
log(" getResourceAsStream(\"/" + resource + "\");");
return true;
}
}
break;
}
default:
return false;
}
return false;
}
}
private static
File visitRoot(URL url, List<String> resources) throws IOException {
if (!url.getProtocol()
.equals("file")) {
throw new IllegalStateException();
}
String path = url.getPath();
if (OS.isWindows()) {
if (path.startsWith("/")) {
path = path.substring(1);
}
}
File root = new File(path);
if (!root.exists()) {
log("failed to find classpath entry in filesystem: " + path);
return null;
}
if (root.isDirectory()) {
visitDir(normalizePath(root.getAbsolutePath()), root, resources);
}
else {
final String s = root.getName()
.toLowerCase();
if (s.endsWith(".zip")) {
visitZip(root, resources);
}
else if (s.endsWith(".jar")) {
visitZip(root, resources);
}
else {
log("unknown classpath entry type: " + path);
return null;
}
}
return root;
}
private static
void visitDir(String root, File dir, Collection<String> out) {
final File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
visitDir(root, file, out);
}
out.add(file.getAbsolutePath()
.replace('\\', '/')
.substring(root.length() + 1));
}
}
}
private static
void visitZip(File jar, Collection<String> out) throws IOException {
ZipInputStream zis = new ZipInputStream(new FileInputStream(jar));
while (true) {
ZipEntry entry = zis.getNextEntry();
if (entry == null) {
break;
}
out.add(entry.getName()
.replace('\\', '/'));
}
zis.close();
}
private static
String prefix() {
return "[" + LocationResolver.class.getSimpleName() + "] ";
}
}

316
src/dorkbox/util/OS.java Normal file
View File

@ -0,0 +1,316 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.charset.Charset;
import java.util.Locale;
import java.util.TimeZone;
@SuppressWarnings({"unused", "WeakerAccess"})
public
class OS {
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static final String LINE_SEPARATOR_UNIX = "\n";
public static final String LINE_SEPARATOR_WINDOWS = "\r\n";
public static final Charset US_ASCII = Charset.forName("US-ASCII");
public static final Charset UTF_8 = Charset.forName("UTF-8");
public static final Charset UTF_16LE = Charset.forName("UTF-16LE");
/**
* The currently running java version as a NUMBER. For example, "Java version 1.7u45", and converts it into 7
*/
public static final int javaVersion = _getJavaVersion();
private static final OsType osType;
private static final String originalTimeZone = TimeZone.getDefault()
.getID();
static {
/**
* By default, the timer resolution in some operating systems are not particularly high-resolution (ie: 'Thread.sleep(1)' will not
* really sleep for 1ms, but will really sleep for 16ms). This forces the JVM to use high resolution timers. This is USUALLY
* necessary on Windows.
*/
Thread timerAccuracyThread = new Thread(new Runnable() {
public
void run() {
//noinspection InfiniteLoopStatement
while (true) {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (Exception ignored) {
}
}
}
}, "ForceHighResTimer");
timerAccuracyThread.setDaemon(true);
timerAccuracyThread.start();
String osName = System.getProperty("os.name");
String osArch = System.getProperty("os.arch");
if (osName != null && osArch != null) {
osName = osName.toLowerCase(Locale.US);
osArch = osArch.toLowerCase(Locale.US);
if (osName.startsWith("linux")) {
// best way to determine if it's android or not
boolean isAndroid;
try {
Class.forName("android.app.Activity");
isAndroid = true;
} catch (ClassNotFoundException e) { isAndroid = false; }
if (isAndroid) {
// android check from https://stackoverflow.com/questions/14859954/android-os-arch-output-for-arm-mips-x86
if (osArch.equals("armeabi")) {
// really old/low-end non-hf 32bit cpu
osType = OsType.AndroidArm56;
}
else if (osArch.equals("armeabi-v7a")) {
// 32bit hf cpu
osType = OsType.AndroidArm7;
}
else if (osArch.equals("arm64-v8a")) {
// 64bit hf cpu
osType = OsType.AndroidArm8;
}
else if (osArch.equals("x86")) {
// 32bit x86 (usually emulator)
osType = OsType.AndroidX86;
}
else if (osArch.equals("x86_64")) {
// 64bit x86 (usually emulator)
osType = OsType.AndroidX86_64;
}
else if (osArch.equals("mips")) {
// 32bit mips
osType = OsType.AndroidMips;
}
else if (osArch.equals("mips64")) {
// 64bit mips
osType = OsType.AndroidMips64;
} else {
// who knows?
osType = null;
}
}
else {
// normal linux 32/64/arm32/arm64
if ("amd64".equals(osArch)) {
osType = OsType.Linux64;
}
else {
if (osArch.startsWith("arm")) {
if (osArch.contains("v8")) {
osType = OsType.LinuxArm64;
}
else {
osType = OsType.LinuxArm32;
}
}
else {
osType = OsType.Linux32;
}
}
}
}
else if (osName.startsWith("windows")) {
if ("amd64".equals(osArch)) {
osType = OsType.Windows64;
}
else {
osType = OsType.Windows32;
}
}
else if (osName.startsWith("mac") || osName.startsWith("darwin")) {
if ("x86_64".equals(osArch)) {
osType = OsType.MacOsX64;
}
else {
osType = OsType.MacOsX32;
}
}
else if (osName.startsWith("freebsd") || osName.contains("nix") || osName.contains("nux") || osName.startsWith("aix")) {
if ("x86".equals(osArch) || "i386".equals(osArch)) {
osType = OsType.Unix32;
}
else if ("arm".equals(osArch)) {
osType = OsType.UnixArm;
}
else {
osType = OsType.Unix64;
}
}
else if (osName.startsWith("solaris") || osName.startsWith("sunos")) {
osType = OsType.Solaris;
}
else {
osType = null;
}
}
else {
osType = null;
}
}
public static
OsType get() {
return osType;
}
public static
boolean is64bit() {
return osType.is64bit();
}
public static
boolean is32bit() {
return osType.is32bit();
}
/**
* @return true if this is a "standard" x86/x64 architecture (intel/amd/etc) processor.
*/
public static
boolean isX86() {
return osType.isX86();
}
public static
boolean isMips() {
return osType.isMips();
}
public static
boolean isArm() {
return osType.isArm();
}
public static
boolean isLinux() {
return osType.isLinux();
}
public static
boolean isUnix() {
return osType.isUnix();
}
public static
boolean isSolaris() {
return osType.isSolaris();
}
public static
boolean isWindows() {
return osType.isWindows();
}
public static
boolean isMacOsX() {
return osType.isMacOsX();
}
public static
boolean isAndroid() {
return osType.isAndroid();
}
/**
* Gets the currently running java version as a NUMBER. For example, "Java version 1.7u45", and converts it into 7
*/
private static
int _getJavaVersion() {
String fullJavaVersion = System.getProperty("java.version");
char versionChar;
if (fullJavaVersion.startsWith("1.")) {
versionChar = fullJavaVersion.charAt(2);
}
else {
versionChar = fullJavaVersion.charAt(0);
}
switch (versionChar) {
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
default:
return -1;
}
}
/**
* Set our system to UTC time zone. Retrieve the <b>original</b> time zone via {@link #getOriginalTimeZone()}
*/
public static
void setUTC() {
// have to set our default timezone to UTC. EVERYTHING will be UTC, and if we want local, we must explicitly ask for it.
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
/**
* Returns the *ORIGINAL* system time zone, before (*IF*) it was changed to UTC
*/
public static
String getOriginalTimeZone() {
return originalTimeZone;
}
/**
* @return the optimum number of threads for a given task. Makes certain not to take ALL the threads, always returns at least one
* thread.
*/
public static
int getOptimumNumberOfThreads() {
return Math.max(Runtime.getRuntime()
.availableProcessors() - 2, 1);
}
@Override
public final
Object clone() throws java.lang.CloneNotSupportedException {
throw new java.lang.CloneNotSupportedException();
}
public final
void writeObject(ObjectOutputStream out) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
public final
void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.NotSerializableException();
}
}

View File

@ -0,0 +1,136 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util;
public enum OsType {
Windows32("windows_32", ".dll"),
Windows64("windows_64", ".dll"),
Linux32("linux_32", ".so"),
Linux64("linux_64", ".so"),
MacOsX32("macosx_32", ".jnilib", ".dylib"),
MacOsX64("macosx_64", ".jnilib", ".dylib"),
UnixArm("unix_arm", ".so"),
Unix32("unix_32", ".so"),
Unix64("unix_64", ".so"),
Solaris("solaris", ".so"),
AndroidArm56("android_arm56", ".so"), // 32bit no hardware float support
AndroidArm7("android_arm7", ".so"), // 32bit hardware float support
AndroidArm8("android_arm8", ".so"), // 64bit (w/ hardware float. everything now has hard float)
AndroidMips("android_mips", ".so"), // 32bit mips
AndroidX86("android_x86", ".so"), // 32bit x86 (usually emulator)
AndroidMips64("android_mips64", ".so"), // 64bit mips
AndroidX86_64("android_x86_64", ".so"), // 64bit x86 (usually emulator)
/*
* Linux OS, Hard float, meaning floats are handled in hardware. WE ONLY SUPPORT HARD FLOATS for linux ARM!.
* For Raspberry-PI, Beaglebone, Odroid, etc PCs
*/
LinuxArm32("linux_arm7_hf", ".so"),
LinuxArm64("linux_arm8_hf", ".so"),
;
private final String name;
private final String[] libraryNames;
OsType(String name, String... libraryNames) {
this.name = name;
this.libraryNames = libraryNames;
}
public String getName() {
return this.name;
}
public String[] getLibraryNames() {
return this.libraryNames;
}
public
boolean is64bit() {
return this == OsType.Linux64 || this == OsType.LinuxArm64 ||
this == OsType.Windows64 || this == OsType.MacOsX64 ||
this == OsType.AndroidArm8 || this == OsType.AndroidX86_64 || this == OsType.AndroidMips64 ||
this == OsType.Unix64;
}
public
boolean is32bit() {
return this == OsType.Linux32 || this == OsType.LinuxArm32 ||
this == OsType.Windows32 || this == OsType.MacOsX32 ||
this == OsType.AndroidArm56 || this == OsType.AndroidArm7 || this == OsType.AndroidX86 || this == OsType.AndroidMips ||
this == OsType.UnixArm || this == OsType.Unix32;
}
public
boolean isMips() {
return this == OsType.AndroidMips || this == OsType.AndroidMips64;
}
/**
* @return true if this is a "standard" x86/x64 architecture (intel/amd/etc) processor.
*/
public
boolean isX86() {
return this == OsType.Linux64 || this == OsType.LinuxArm64 ||
this == OsType.Windows64 || this == OsType.MacOsX64 ||
this == OsType.Linux32 || this == OsType.LinuxArm32 ||
this == OsType.Windows32 || this == OsType.MacOsX32 ||
this == OsType.Unix32 || this == OsType.Unix64 ||
this == OsType.AndroidX86 || this == OsType.AndroidX86_64;
}
public
boolean isArm() {
return this == OsType.LinuxArm32 || this == OsType.LinuxArm64 ||
this == OsType.AndroidArm56 || this == OsType.AndroidArm7 || this == OsType.AndroidArm8;
}
public
boolean isLinux() {
return this == OsType.Linux32 || this == OsType.Linux64 || this == OsType.LinuxArm64 || this == OsType.LinuxArm32;
}
public
boolean isUnix() {
return this == OsType.Unix32 || this == OsType.Unix64 || this == OsType.UnixArm;
}
public
boolean isSolaris() {
return this == OsType.Solaris;
}
public
boolean isWindows() {
return this == OsType.Windows64 || this == OsType.Windows32;
}
public
boolean isMacOsX() {
return this == OsType.MacOsX64 || this == OsType.MacOsX32;
}
public
boolean isAndroid() {
return this == OsType.AndroidArm56 || this == OsType.AndroidArm7 || this == OsType.AndroidX86 || this == OsType.AndroidMips ||
this == OsType.AndroidArm8 || this == OsType.AndroidX86_64 || this == OsType.AndroidMips64;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to track system properties across the entire code-base. System properties are values that can be changed programmatically,
* via a "System.getProperty()", or via arguments.
* <br>
* Loading arguments is left for the end-user application. Using an annotation detector to load/save properties is recommended.
* <br>
* For example (if implemented): -Ddorkbox.Args.Debug=true
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.FIELD})
public
@interface Property {
/**
* This is used to mark a unique value for the property, in case the object name is used elsewhere, is generic, or is repeated.
*/
String alias() default "";
}