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

dorkbox.util.Sys Maven / Gradle / Ivy

/*
 * 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.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
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;

import dorkbox.os.OS;

@SuppressWarnings({"unused", "WeakerAccess"})
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); } /** * 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; } /** * this saves the char array in UTF-16 format of bytes */ @SuppressWarnings("NumericCastThatLosesPrecision") public static byte[] charToBytes16(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++) { //noinspection CharUsedInArithmeticContext 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]; } //noinspection NumericCastThatLosesPrecision 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 startPosition, int length) { int[] ints = new int[length]; int endPosition = startPosition + length; for (int i = startPosition; i < endPosition; i++) { ints[i] = bytes[i] & 0xFF; } return ints; } public static String bytesToHex(byte[] bytes) { return bytesToHex(bytes, 0, bytes.length, false); } public static String bytesToHex(byte[] bytes, int startPosition, int length) { return bytesToHex(bytes, startPosition, length, false); } public static String bytesToHex(byte[] bytes, int startPosition, int length, boolean padding) { int endPosition = startPosition + length; if (padding) { char[] hexString = new char[3 * length]; int j = 0; for (int i = startPosition; i < endPosition; 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 * length]; int j = 0; for (int i = startPosition; i < endPosition; 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. */ @SuppressWarnings("DuplicatedCode") 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"); } } /** * Converts an ASCII character representing a hexadecimal * value into its integer equivalent. */ @SuppressWarnings("DuplicatedCode") public static int hexCharToInt(char 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. */ @SuppressWarnings("CharUsedInArithmeticContext") public static void hex4(final char c, final 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); } /** * from netty 4.1, apache 2.0, https://netty.io */ public static byte hexToByte(CharSequence s, int pos) { int hi = hexCharToInt(s.charAt(pos)); int lo = hexCharToInt(s.charAt(pos + 1)); if (hi == -1 || lo == -1) { throw new IllegalArgumentException(String.format( "invalid hex byte '%s' at index %d of '%s'", s.subSequence(pos, pos + 2), pos, s)); } return (byte) ((hi << 4) + lo); } /** * Decodes a string with hex dump * * @param hex a {@link CharSequence} which contains the hex dump */ public static byte[] hexToBytes(CharSequence hex) { return hexToBytes(hex, 0, hex.length()); } /** * Decodes part of a string with hex dump * * from netty 4.1, apache 2.0, https://netty.io * * @param hexDump a {@link CharSequence} which contains the hex dump * @param fromIndex start of hex dump in {@code hexDump} * @param length hex string length */ public static byte[] hexToBytes(CharSequence hexDump, int fromIndex, int length) { if (length < 0 || (length & 1) != 0) { throw new IllegalArgumentException("length: " + length); } if (length == 0) { return new byte[0]; } byte[] bytes = new byte[length >>> 1]; for (int i = 0; i < length; i += 2) { bytes[i >>> 1] = hexToByte(hexDump, fromIndex + i); } return bytes; } /** * 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.INSTANCE.getLINE_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.INSTANCE.getLINE_SEPARATOR()); } if (includeByteCount) { builder.append("Bytes: ").append(length).append(OS.INSTANCE.getLINE_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.INSTANCE.getLINE_SEPARATOR()); } } builder.append("}"); System.err.println(builder.toString()); } /** * Raises an exception, but bypasses the compiler checks for the checked exception. This uses type erasure to work */ public static void throwException(Throwable t) { Sys.throwException0(t); } @SuppressWarnings("unchecked") private static void throwException0(Throwable t) throws E { throw (E) t; } private Sys() { } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy