All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dorkbox.util.Sys Maven / Gradle / Ivy

There is a newer version: 1.20
Show newest version
/*
 * 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 org.bouncycastle.crypto.digests.SHA256Digest;

import java.awt.Color;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

public final
class Sys {
    public static final int KILOBYTE = 1024;
    public static final int MEGABYTE = 1024 * KILOBYTE;
    public static final int GIGABYTE = 1024 * MEGABYTE;
    public static final long TERABYTE = 1024L * GIGABYTE;

    public static final char[] HEX_CHARS = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    public static
    char[] convertStringToChars(String string) {
        char[] charArray = string.toCharArray();

        eraseString(string);

        return charArray;
    }

    public static
    void eraseString(String string) {
//      You can change the value of the inner char[] using reflection.
//
//      You must be careful to either change it with an array of the same length,
//      or to also update the count field.
//
//      If you want to be able to use it as an entry in a set or as a value in map,
//      you will need to recalculate the hash code and set the value of the hashCode field.

        //noinspection TryWithIdenticalCatches
        try {
            Field valueField = String.class.getDeclaredField("value");
            valueField.setAccessible(true);
            char[] chars = (char[]) valueField.get(string);
            Arrays.fill(chars, '*');  // asterisk it out in case of GC not picking up the old char array.

            valueField.set(string, new char[0]); // replace it.

            // set count to 0
            try {
                // newer versions of java don't have this field
                Field countField = String.class.getDeclaredField("count");
                countField.setAccessible(true);
                countField.set(string, 0);
            } catch (Exception ignored) {
            }

            // set hash to 0
            Field hashField = String.class.getDeclaredField("hash");
            hashField.setAccessible(true);
            hashField.set(string, 0);
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * FROM: https://www.cqse.eu/en/blog/string-replace-performance/
     * 

* Replaces all occurrences of keys of the given map in the given string * with the associated value in that map. *

* This method is semantically the same as calling * {@link String#replace(CharSequence, CharSequence)} for each of the * entries in the map, but may be significantly faster for many replacements * performed on a short string, since * {@link String#replace(CharSequence, CharSequence)} uses regular * expressions internally and results in many String object allocations when * applied iteratively. *

* The order in which replacements are applied depends on the order of the * map's entry set. */ public static String replaceStringFast(String string, Map replacements) { StringBuilder sb = new StringBuilder(string); for (Entry entry : replacements.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); int start = sb.indexOf(key, 0); while (start > -1) { int end = start + key.length(); int nextSearchStart = start + value.length(); sb.replace(start, end, value); start = sb.indexOf(key, nextSearchStart); } } return sb.toString(); } /** * Quickly finds a char in a string. * * @return index if it's there, -1 if not there */ public static int searchStringFast(String string, char c) { int length = string.length(); for (int i = 0; i < length; i++) { if (string.charAt(i) == c) { return i; } } return -1; } public static String getSizePretty(final long size) { if (size > TERABYTE) { return String.format("%2.2fTB", (double) size / TERABYTE); } if (size > GIGABYTE) { return String.format("%2.2fGB", (double) size / GIGABYTE); } if (size > MEGABYTE) { return String.format("%2.2fMB", (double) size / MEGABYTE); } if (size > KILOBYTE) { return String.format("%2.2fKB", (double) size / KILOBYTE); } return String.valueOf(size) + "B"; } /** * Returns a PRETTY string representation of the specified time. */ public static String getTimePretty(long nanoSeconds) { final TimeUnit unit; final String text; if (TimeUnit.DAYS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.DAYS; text = "d"; } else if (TimeUnit.HOURS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.HOURS; text = "h"; } else if (TimeUnit.MINUTES.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.MINUTES; text = "min"; } else if (TimeUnit.SECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.SECONDS; text = "s"; } else if (TimeUnit.MILLISECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.MILLISECONDS; text = "ms"; } else if (TimeUnit.MICROSECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.MICROSECONDS; text = "\u03bcs"; // μs } else { unit = TimeUnit.NANOSECONDS; text = "ns"; } // convert the unit into the largest time unit possible (since that is often what makes sense) double value = (double) nanoSeconds / TimeUnit.NANOSECONDS.convert(1, unit); return String.format("%.4g" + text, value); } /** * Returns a PRETTY string representation of the specified time. */ public static String getTimePrettyFull(long nanoSeconds) { final TimeUnit unit; String text; if (TimeUnit.DAYS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.DAYS; text = "day"; } else if (TimeUnit.HOURS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.HOURS; text = "hour"; } else if (TimeUnit.MINUTES.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.MINUTES; text = "minute"; } else if (TimeUnit.SECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.SECONDS; text = "second"; } else if (TimeUnit.MILLISECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.MILLISECONDS; text = "milli-second"; } else if (TimeUnit.MICROSECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) { unit = TimeUnit.MICROSECONDS; text = "micro-second"; } else { unit = TimeUnit.NANOSECONDS; text = "nano-second"; } // convert the unit into the largest time unit possible (since that is often what makes sense) double value = (double) nanoSeconds / TimeUnit.NANOSECONDS.convert(1, unit); if (value > 1.0D) { text += "s"; } return String.format("%.4g " + text, value); } /** * Convenient close for a stream. */ @SuppressWarnings("Duplicates") public static void close(InputStream inputStream) { if (inputStream != null) { try { inputStream.close(); } catch (IOException ioe) { System.err.println("Error closing the input stream:" + inputStream); ioe.printStackTrace(); } } } /** * Convenient close for a stream. */ @SuppressWarnings("Duplicates") public static void closeQuietly(InputStream inputStream) { if (inputStream != null) { try { inputStream.close(); } catch (IOException ignored) { } } } /** * Convenient close for a stream. */ @SuppressWarnings("Duplicates") public static void close(OutputStream outputStream) { if (outputStream != null) { try { outputStream.close(); } catch (IOException ioe) { System.err.println("Error closing the output stream:" + outputStream); ioe.printStackTrace(); } } } /** * Convenient close for a stream. */ @SuppressWarnings("Duplicates") public static void closeQuietly(OutputStream outputStream) { if (outputStream != null) { try { outputStream.close(); } catch (IOException ignored) { } } } /** * Convenient close for a Reader. */ @SuppressWarnings("Duplicates") public static void close(Reader inputReader) { if (inputReader != null) { try { inputReader.close(); } catch (IOException ioe) { System.err.println("Error closing input reader: " + inputReader); ioe.printStackTrace(); } } } /** * Convenient close for a Reader. */ @SuppressWarnings("Duplicates") public static void closeQuietly(Reader inputReader) { if (inputReader != null) { try { inputReader.close(); } catch (IOException ignored) { } } } /** * Convenient close for a Writer. */ @SuppressWarnings("Duplicates") public static void close(Writer outputWriter) { if (outputWriter != null) { try { outputWriter.close(); } catch (IOException ioe) { System.err.println("Error closing output writer: " + outputWriter); ioe.printStackTrace(); } } } /** * Convenient close for a Writer. */ @SuppressWarnings("Duplicates") public static void closeQuietly(Writer outputWriter) { if (outputWriter != null) { try { outputWriter.close(); } catch (IOException ignored) { } } } /** * Copy the contents of the input stream to the output stream. *

* DOES NOT CLOSE THE STEAMS! */ public static T copyStream(InputStream inputStream, T outputStream) throws IOException { byte[] buffer = new byte[4096]; int read; while ((read = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, read); } outputStream.flush(); return outputStream; } /** * Convert the contents of the input stream to a byte array. */ public static byte[] getBytesFromStream(InputStream inputStream) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(8192); byte[] buffer = new byte[4096]; int read; while ((read = inputStream.read(buffer)) > 0) { baos.write(buffer, 0, read); } baos.flush(); inputStream.close(); return baos.toByteArray(); } public static byte[] copyBytes(byte[] src) { return copyBytes(src, 0); } public static byte[] copyBytes(byte[] src, int position) { int length = src.length - position; byte[] b = new byte[length]; System.arraycopy(src, position, b, 0, length); return b; } public static byte[] concatBytes(byte[]... arrayBytes) { int length = 0; for (byte[] bytes : arrayBytes) { length += bytes.length; } byte[] concatBytes = new byte[length]; length = 0; for (byte[] bytes : arrayBytes) { System.arraycopy(bytes, 0, concatBytes, length, bytes.length); length += bytes.length; } return concatBytes; } /** * gets the SHA256 hash + SALT of the specified username, as UTF-16 */ public static byte[] getSha256WithSalt(String username, byte[] saltBytes) { if (username == null) { return null; } byte[] charToBytes = Sys.charToBytes(username.toCharArray()); byte[] userNameWithSalt = Sys.concatBytes(charToBytes, saltBytes); SHA256Digest sha256 = new SHA256Digest(); byte[] usernameHashBytes = new byte[sha256.getDigestSize()]; sha256.update(userNameWithSalt, 0, userNameWithSalt.length); sha256.doFinal(usernameHashBytes, 0); return usernameHashBytes; } /** * gets the SHA256 hash of the specified string, as UTF-16 */ public static byte[] getSha256(String string) { byte[] charToBytes = Sys.charToBytes(string.toCharArray()); SHA256Digest sha256 = new SHA256Digest(); byte[] usernameHashBytes = new byte[sha256.getDigestSize()]; sha256.update(charToBytes, 0, charToBytes.length); sha256.doFinal(usernameHashBytes, 0); return usernameHashBytes; } /** * gets the SHA256 hash of the specified byte array */ public static byte[] getSha256(byte[] bytes) { SHA256Digest sha256 = new SHA256Digest(); byte[] hashBytes = new byte[sha256.getDigestSize()]; sha256.update(bytes, 0, bytes.length); sha256.doFinal(hashBytes, 0); return hashBytes; } /** * this saves the char array in UTF-16 format of bytes */ @SuppressWarnings("NumericCastThatLosesPrecision") public static byte[] charToBytes(char[] text) { // NOTE: this saves the char array in UTF-16 format of bytes. byte[] bytes = new byte[text.length * 2]; for (int i = 0; i < text.length; i++) { bytes[2 * i] = (byte) (text[i] >> 8); bytes[2 * i + 1] = (byte) text[i]; } return bytes; } public static byte[] intsToBytes(int[] ints) { int length = ints.length; byte[] bytes = new byte[length]; for (int i = 0; i < length; i++) { int intValue = ints[i]; if (intValue < 0 || intValue > 255) { System.err.println("WARNING: int at index " + i + "(" + intValue + ") was not a valid byte value (0-255)"); return new byte[length]; } bytes[i] = (byte) intValue; } return bytes; } @SuppressWarnings("NumericCastThatLosesPrecision") public static byte[] charToBytesRaw(char[] chars) { int length = chars.length; byte[] bytes = new byte[length]; for (int i = 0; i < length; i++) { char charValue = chars[i]; bytes[i] = (byte) charValue; } return bytes; } public static int[] bytesToInts(byte[] bytes) { int length = bytes.length; int[] ints = new int[length]; for (int i = 0; i < length; i++) { ints[i] = bytes[i] & 0xFF; } return ints; } public static String bytesToHex(byte[] bytes) { return bytesToHex(bytes, false); } public static String bytesToHex(byte[] bytes, boolean padding) { if (padding) { char[] hexString = new char[3 * bytes.length]; int j = 0; for (int i = 0; i < bytes.length; i++) { hexString[j++] = HEX_CHARS[(bytes[i] & 0xF0) >> 4]; hexString[j++] = HEX_CHARS[bytes[i] & 0x0F]; hexString[j++] = ' '; } return new String(hexString); } else { char[] hexString = new char[2 * bytes.length]; int j = 0; for (int i = 0; i < bytes.length; i++) { hexString[j++] = HEX_CHARS[(bytes[i] & 0xF0) >> 4]; hexString[j++] = HEX_CHARS[bytes[i] & 0x0F]; } return new String(hexString); } } /** * Converts an ASCII character representing a hexadecimal * value into its integer equivalent. */ public static int hexByteToInt(byte b) { switch (b) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': case 'a': return 10; case 'B': case 'b': return 11; case 'C': case 'c': return 12; case 'D': case 'd': return 13; case 'E': case 'e': return 14; case 'F': case 'f': return 15; default: throw new IllegalArgumentException("Error decoding byte"); } } /** * A 4-digit hex result. */ public static void hex4(char c, StringBuilder sb) { sb.append(HEX_CHARS[(c & 0xF000) >> 12]); sb.append(HEX_CHARS[(c & 0x0F00) >> 8]); sb.append(HEX_CHARS[(c & 0x00F0) >> 4]); sb.append(HEX_CHARS[c & 0x000F]); } /** * Returns a string representation of the byte array as a series of * hexadecimal characters. * * @param bytes byte array to convert * @return a string representation of the byte array as a series of * hexadecimal characters */ public static String toHexString(byte[] bytes) { char[] hexString = new char[2 * bytes.length]; int j = 0; for (int i = 0; i < bytes.length; i++) { hexString[j++] = HEX_CHARS[(bytes[i] & 0xF0) >> 4]; hexString[j++] = HEX_CHARS[bytes[i] & 0x0F]; } return new String(hexString); } /** * XOR two byte arrays together, and save result in originalArray * * @param originalArray this is the base of the XOR operation. * @param keyArray this is XOR'd into the original array, repeats if necessary. */ @SuppressWarnings("NumericCastThatLosesPrecision") public static void xorArrays(byte[] originalArray, byte[] keyArray) { int keyIndex = 0; int keyLength = keyArray.length; for (int i = 0; i < originalArray.length; i++) { //XOR the data and start over if necessary originalArray[i] = (byte) (originalArray[i] ^ keyArray[keyIndex++ % keyLength]); } } public static byte[] encodeStringArray(List array) { int length = 0; for (String s : array) { byte[] bytes = s.getBytes(); length += bytes.length; } if (length == 0) { return new byte[0]; } byte[] bytes = new byte[length + array.size()]; length = 0; for (String s : array) { byte[] sBytes = s.getBytes(); System.arraycopy(sBytes, 0, bytes, length, sBytes.length); length += sBytes.length; bytes[length++] = (byte) 0x01; } return bytes; } public static ArrayList decodeStringArray(byte[] bytes) { int length = bytes.length; int position = 0; byte token = (byte) 0x01; ArrayList list = new ArrayList(0); int last = 0; while (last + position < length) { byte b = bytes[last + position++]; if (b == token) { byte[] xx = new byte[position - 1]; System.arraycopy(bytes, last, xx, 0, position - 1); list.add(new String(xx)); last += position; position = 0; } } return list; } public static String printArrayRaw(final byte[] bytes) { return printArrayRaw(bytes, 0); } public static String printArrayRaw(final byte[] bytes, final int lineLength) { if (lineLength > 0) { int length = bytes.length; int comma = length - 1; StringBuilder builder = new StringBuilder(length + length / lineLength); for (int i = 0; i < length; i++) { builder.append(bytes[i]); if (i < comma) { builder.append(","); } if (i > 0 && i % lineLength == 0) { builder.append(OS.LINE_SEPARATOR); } } return builder.toString(); } else { int length = bytes.length; int comma = length - 1; StringBuilder builder = new StringBuilder(length + length); for (int i = 0; i < length; i++) { builder.append(bytes[i]); if (i < comma) { builder.append(","); } } return builder.toString(); } } public static void printArray(byte[] bytes) { printArray(bytes, bytes.length, true); } public static void printArray(byte[] bytes, int length, boolean includeByteCount) { printArray(bytes, 0, length, includeByteCount, 40, null); } public static void printArray(byte[] bytes, int inputOffset, int length, boolean includeByteCount) { printArray(bytes, inputOffset, length, includeByteCount, 40, null); } public static void printArray(byte[] bytes, int inputOffset, int length, boolean includeByteCount, int lineLength, String header) { int comma = length - 1; int builderLength = length + comma + 2; if (includeByteCount) { builderLength += 7 + Integer.toString(length) .length(); } if (lineLength > 0) { builderLength += length / lineLength; } if (header != null) { builderLength += header.length() + 2; } StringBuilder builder = new StringBuilder(builderLength); if (header != null) { builder.append(header) .append(OS.LINE_SEPARATOR); } if (includeByteCount) { builder.append("Bytes: ").append(length).append(OS.LINE_SEPARATOR); } builder.append("{"); for (int i = inputOffset; i < length; i++) { builder.append(bytes[i]); if (i < comma) { builder.append(","); } if (i > inputOffset && lineLength > 0 && i % lineLength == 0) { builder.append(OS.LINE_SEPARATOR); } } builder.append("}"); System.err.println(builder.toString()); } // Easier access for system properties, if necessary public static String getSystemString(final String property, final String defaultValue) { String property1 = System.getProperty(property); if (property1 == null) { return defaultValue; } return property1; } public static int getSystemInt(final String property, final int defaultValue) { String property1 = System.getProperty(property); if (property1 == null) { return defaultValue; } return Integer.parseInt(property1); } public static long getSystemLong(final String property, final long defaultValue) { String property1 = System.getProperty(property); if (property1 == null) { return defaultValue; } return Long.parseLong(property1); } public static boolean getSystemBoolean(final String property, final boolean defaultValue) { String property1 = System.getProperty(property); if (property1 == null) { return defaultValue; } return Boolean.parseBoolean(property1); } public static Color getSystemColor(final String property, final Color defaultValue) { String property1 = System.getProperty(property); if (property1 == null) { return defaultValue; } return Color.decode(property1); } // Parsing font from a string is inside SwingUtil private Sys() { } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy