/* * This file is part of the L2J Mobius project. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package com.l2jmobius.commons.util; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.nio.ByteBuffer; import java.time.DayOfWeek; import java.time.LocalDateTime; import java.time.temporal.TemporalAdjusters; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.StringJoiner; import java.util.StringTokenizer; import com.l2jmobius.Config; public final class CommonUtil { private static final char[] ILLEGAL_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' }; /** * Method to generate the hexadecimal representation of a byte array.
* 16 bytes per row, while ascii chars or "." is shown at the end of the line. * @param data the byte array to be represented in hexadecimal representation * @param len the number of bytes to represent in hexadecimal representation * @return byte array represented in hexadecimal format */ public static String printData(byte[] data, int len) { return new String(HexUtils.bArr2HexEdChars(data, len)); } /** * This call is equivalent to Util.printData(data, data.length) * @see CommonUtil#printData(byte[],int) * @param data data to represent in hexadecimal * @return byte array represented in hexadecimal format */ public static String printData(byte[] data) { return printData(data, data.length); } /** * Method to represent the remaining bytes of a ByteBuffer as hexadecimal * @param buf ByteBuffer to represent the remaining bytes of as hexadecimal * @return hexadecimal representation of remaining bytes of the ByteBuffer */ public static String printData(ByteBuffer buf) { final byte[] data = new byte[buf.remaining()]; buf.get(data); final String hex = CommonUtil.printData(data, data.length); buf.position(buf.position() - data.length); return hex; } /** * Method to generate a random sequence of bytes returned as byte array * @param size number of random bytes to generate * @return byte array with sequence of random bytes */ public static byte[] generateHex(int size) { final byte[] array = new byte[size]; Rnd.nextBytes(array); // Don't allow 0s inside the array! for (int i = 0; i < array.length; i++) { while (array[i] == 0) { array[i] = (byte) Rnd.get(Byte.MAX_VALUE); } } return array; } /** * Replaces most invalid characters for the given string with an underscore. * @param str the string that may contain invalid characters * @return the string with invalid character replaced by underscores */ public static String replaceIllegalCharacters(String str) { String valid = str; for (char c : ILLEGAL_CHARACTERS) { valid = valid.replace(c, '_'); } return valid; } /** * Verify if a file name is valid. * @param name the name of the file * @return {@code true} if the file name is valid, {@code false} otherwise */ public static boolean isValidFileName(String name) { final File f = new File(name); try { f.getCanonicalPath(); return true; } catch (IOException e) { return false; } } /** * Split words with a space. * @param input the string to split * @return the split string */ public static String splitWords(String input) { return input.replaceAll("(\\p{Ll})(\\p{Lu})", "$1 $2"); } /** * Gets the next or same closest date from the specified days in {@code daysOfWeek Array} at specified {@code hour} and {@code min}. * @param daysOfWeek the days of week * @param hour the hour * @param min the min * @return the next or same date from the days of week at specified time * @throws IllegalArgumentException if the {@code daysOfWeek Array} is empty. */ public static LocalDateTime getNextClosestDateTime(DayOfWeek[] daysOfWeek, int hour, int min) throws IllegalArgumentException { return getNextClosestDateTime(Arrays.asList(daysOfWeek), hour, min); } /** * Gets the next or same closest date from the specified days in {@code daysOfWeek List} at specified {@code hour} and {@code min}. * @param daysOfWeek the days of week * @param hour the hour * @param min the min * @return the next or same date from the days of week at specified time * @throws IllegalArgumentException if the {@code daysOfWeek List} is empty. */ public static LocalDateTime getNextClosestDateTime(List daysOfWeek, int hour, int min) throws IllegalArgumentException { if (daysOfWeek.isEmpty()) { throw new IllegalArgumentException("daysOfWeek should not be empty."); } final LocalDateTime dateNow = LocalDateTime.now(); final LocalDateTime dateNowWithDifferentTime = dateNow.withHour(hour).withMinute(min).withSecond(0); // @formatter:off return daysOfWeek.stream() .map(d -> dateNowWithDifferentTime.with(TemporalAdjusters.nextOrSame(d))) .filter(d -> d.isAfter(dateNow)) .min(Comparator.naturalOrder()) .orElse(dateNowWithDifferentTime.with(TemporalAdjusters.next(daysOfWeek.get(0)))); // @formatter:on } /** * Method to get the stack trace of a Throwable into a String * @param t Throwable to get the stacktrace from * @return stack trace from Throwable as String */ public static String getStackTrace(Throwable t) { final StringWriter sw = new StringWriter(); t.printStackTrace(new PrintWriter(sw)); return sw.toString(); } public static String getTraceString(StackTraceElement[] stackTraceElements) { final StringJoiner sj = new StringJoiner(Config.EOL); for (StackTraceElement stackTraceElement : stackTraceElements) { sj.add(stackTraceElement.toString()); } return sj.toString(); } public static int min(int value1, int value2, int... values) { int min = Math.min(value1, value2); for (int value : values) { if (min > value) { min = value; } } return min; } public static int max(int value1, int value2, int... values) { int max = Math.max(value1, value2); for (int value : values) { if (max < value) { max = value; } } return max; } public static long min(long value1, long value2, long... values) { long min = Math.min(value1, value2); for (long value : values) { if (min > value) { min = value; } } return min; } public static long max(long value1, long value2, long... values) { long max = Math.max(value1, value2); for (long value : values) { if (max < value) { max = value; } } return max; } public static float min(float value1, float value2, float... values) { float min = Math.min(value1, value2); for (float value : values) { if (min > value) { min = value; } } return min; } public static float max(float value1, float value2, float... values) { float max = Math.max(value1, value2); for (float value : values) { if (max < value) { max = value; } } return max; } public static double min(double value1, double value2, double... values) { double min = Math.min(value1, value2); for (double value : values) { if (min > value) { min = value; } } return min; } public static double max(double value1, double value2, double... values) { double max = Math.max(value1, value2); for (double value : values) { if (max < value) { max = value; } } return max; } public static int getIndexOfMaxValue(int... array) { int index = 0; for (int i = 1; i < array.length; i++) { if (array[i] > array[index]) { index = i; } } return index; } public static int getIndexOfMinValue(int... array) { int index = 0; for (int i = 1; i < array.length; i++) { if (array[i] < array[index]) { index = i; } } return index; } /** * Re-Maps a value from one range to another. * @param input * @param inputMin * @param inputMax * @param outputMin * @param outputMax * @return The mapped value */ public static int map(int input, int inputMin, int inputMax, int outputMin, int outputMax) { input = constrain(input, inputMin, inputMax); return (((input - inputMin) * (outputMax - outputMin)) / (inputMax - inputMin)) + outputMin; } /** * Re-Maps a value from one range to another. * @param input * @param inputMin * @param inputMax * @param outputMin * @param outputMax * @return The mapped value */ public static long map(long input, long inputMin, long inputMax, long outputMin, long outputMax) { input = constrain(input, inputMin, inputMax); return (((input - inputMin) * (outputMax - outputMin)) / (inputMax - inputMin)) + outputMin; } /** * Re-Maps a value from one range to another. * @param input * @param inputMin * @param inputMax * @param outputMin * @param outputMax * @return The mapped value */ public static double map(double input, double inputMin, double inputMax, double outputMin, double outputMax) { input = constrain(input, inputMin, inputMax); return (((input - inputMin) * (outputMax - outputMin)) / (inputMax - inputMin)) + outputMin; } /** * Constrains a number to be within a range. * @param input the number to constrain, all data types * @param min the lower end of the range, all data types * @param max the upper end of the range, all data types * @return input: if input is between min and max, min: if input is less than min, max: if input is greater than max */ public static int constrain(int input, int min, int max) { return (input < min) ? min : (input > max) ? max : input; } /** * Constrains a number to be within a range. * @param input the number to constrain, all data types * @param min the lower end of the range, all data types * @param max the upper end of the range, all data types * @return input: if input is between min and max, min: if input is less than min, max: if input is greater than max */ public static long constrain(long input, long min, long max) { return (input < min) ? min : (input > max) ? max : input; } /** * Constrains a number to be within a range. * @param input the number to constrain, all data types * @param min the lower end of the range, all data types * @param max the upper end of the range, all data types * @return input: if input is between min and max, min: if input is less than min, max: if input is greater than max */ public static double constrain(double input, double min, double max) { return (input < min) ? min : (input > max) ? max : input; } /** * @param array - the array to look into * @param obj - the object to search for * @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise. */ public static boolean startsWith(String[] array, String obj) { for (String element : array) { if (element.startsWith(obj)) { return true; } } return false; } /** * @param * @param array - the array to look into * @param obj - the object to search for * @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise. */ public static boolean contains(T[] array, T obj) { for (T element : array) { if (element == obj) { return true; } } return false; } /** * @param array - the array to look into * @param obj - the integer to search for * @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise */ public static boolean contains(int[] array, int obj) { for (int element : array) { if (element == obj) { return true; } } return false; } /** * @param array - the array to look into * @param obj - the object to search for * @param ignoreCase * @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise. */ public static boolean contains(String[] array, String obj, boolean ignoreCase) { for (String element : array) { if (element.equals(obj) || (ignoreCase && element.equalsIgnoreCase(obj))) { return true; } } return false; } public static int parseNextInt(StringTokenizer st, int defaultVal) { try { final String value = st.nextToken().trim(); return Integer.parseInt(value); } catch (Exception e) { return defaultVal; } } /** * @param str - the string whose first letter to capitalize * @return a string with the first letter of the {@code str} capitalized */ public static String capitalizeFirst(String str) { if ((str == null) || str.isEmpty()) { return str; } final char[] arr = str.toCharArray(); final char c = arr[0]; if (Character.isLetter(c)) { arr[0] = Character.toUpperCase(c); } return new String(arr); } /** * Based on implode() in PHP * @param * @param iteratable * @param delim * @return a delimited string for a given array of string elements. */ public static String implode(Iterable iteratable, String delim) { final StringJoiner sj = new StringJoiner(delim); iteratable.forEach(o -> sj.add(o.toString())); return sj.toString(); } /** * Based on implode() in PHP * @param * @param array * @param delim * @return a delimited string for a given array of string elements. */ public static String implode(T[] array, String delim) { final StringJoiner sj = new StringJoiner(delim); for (T o : array) { sj.add(o.toString()); } return sj.toString(); } }