/* * The MIT License * * Copyright 2016 Pawel Marynowski. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package pattypan; import edu.stanford.ejalbert.BrowserLauncher; import edu.stanford.ejalbert.exception.BrowserLaunchingInitializingException; import edu.stanford.ejalbert.exception.UnsupportedOperatingSystemException; import java.awt.Desktop; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.security.MessageDigest; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.MissingResourceException; import java.util.Objects; import java.util.ResourceBundle; import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; import javafx.geometry.HPos; import javafx.scene.layout.ColumnConstraints; public final class Util { private Util() {} public static int WINDOW_WIDTH = 750; public static int WINDOW_HEIGHT = 550; static ResourceBundle bundle = ResourceBundle.getBundle("pattypan/text/messages"); public static String text(String key) { try { String val = bundle.getString(key); return new String(val.getBytes("ISO-8859-1"), "UTF-8"); } catch (final MissingResourceException ex) { return ""; } catch (UnsupportedEncodingException ex) { return ""; } } public static String text(String key, Object... vars) { String text = text(key); return String.format(text, vars); } /** * Open URL in browser * * @source http://stackoverflow.com/a/28807079 * @param url website URL */ public static void openUrl(String url) { String os = System.getProperty("os.name").toLowerCase(); try { if (os.contains("win")) { Desktop.getDesktop().browse(new URI(url)); } else if (os.contains("mac")) { Runtime rt = Runtime.getRuntime(); rt.exec("open " + url); } else { new BrowserLauncher().openURLinBrowser(url); } } catch (BrowserLaunchingInitializingException | UnsupportedOperatingSystemException ex) { Session.LOGGER.log(Level.WARNING, null, ex); } catch (URISyntaxException | IOException ex) { Session.LOGGER.log(Level.WARNING, null, ex); } } public static void openDirectory(Path path) { try { Desktop.getDesktop().open(new File(path.toString())); } catch (IllegalArgumentException | IOException ex) { Session.LOGGER.log(Level.WARNING, null, ex); } } /* row and column utils */ public static ColumnConstraints newColumn(int value) { return newColumn(value, "%", HPos.CENTER); } public static ColumnConstraints newColumn(int value, String unit) { return newColumn(value, unit, HPos.CENTER); } public static ColumnConstraints newColumn(int value, String unit, HPos position) { ColumnConstraints col = new ColumnConstraints(); if (unit.equals("%")) { col.setPercentWidth(value); } if (unit.equals("px")) { col.setMaxWidth(value); col.setMinWidth(value); } if (position != null) { col.setHalignment(position); } return col; } /* file utils */ private final static ArrayList<String> allowedFileExtension = new ArrayList<>( Arrays.asList("djvu", "flac", "gif", "jpg", "jpeg", "mid", "mkv", "oga", "ogg","ogv", "opus", "pdf", "png", "svg", "tiff", "tif", "wav", "webm", "webp", "xcf", "mp3", "stl") ); // https://commons.wikimedia.org/wiki/MediaWiki:Filename-prefix-blacklist private final static ArrayList<String> filenamePrefixBlacklist = new ArrayList<>( Arrays.asList("CIMG", "DSC_", "DSCF", "DSCN", "DUW", "GEDC", "IMG", "JD", "MGP", "PICT", "Imagen", "FOTO", "DSC", "SANY", "SAM") ); public static boolean stringHasValidFileExtension(String string) { return allowedFileExtension.parallelStream().anyMatch(string::endsWith); } public static boolean isPossibleBadFilename(String name) { return filenamePrefixBlacklist.parallelStream().anyMatch(name::startsWith); } public static String getNameFromFilename(String filename) { int pos = filename.lastIndexOf("."); if (pos > 0) { filename = filename.substring(0, pos); } return filename; } public static String getExtFromFilename(String filename) { String extension = ""; int i = filename.lastIndexOf('.'); if (i >= 0) { extension = filename.substring(i + 1).toLowerCase(); } return extension; } public static File[] getFilesAllowedToUpload(File directory, boolean includeSubdirectories) { ArrayList<File> files = new ArrayList<>(); try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory.toPath())) { for (Path path : stream) { if (path.toFile().isDirectory() && includeSubdirectories) { File[] dirFiles = getFilesAllowedToUpload(path.toFile(), includeSubdirectories); ArrayList<File> dirFilesList = new ArrayList<>(Arrays.asList(dirFiles)); files.addAll(dirFilesList); } else if (isFileAllowedToUpload(path.toFile().getName())) { files.add(path.toFile()); } } } catch (IOException e) { } return files.stream().toArray(File[]::new); } public static File[] getFilesAllowedToUpload(File directory, String ext) { return directory.listFiles((File dir, String name) -> name.toLowerCase().endsWith(ext) ); } public static Map<String, Integer> getFilesByExtention(File[] files) { Map<String, Integer> map = new HashMap<>(); for (File file : files) { String ext = getExtFromFilename(file.getName()); if (map.containsKey(ext)) { int count = map.get(ext); map.replace(ext, ++count); } else { map.put(ext, 1); } } return map; } // @TODO: remove fancy chars public static String getNormalizedName(String name) { return name.trim().replaceAll(" +", " "); } public static boolean isFileAllowedToUpload(String name) { return allowedFileExtension.indexOf(getExtFromFilename(name)) > -1; } // @source: https://howtodoinjava.com/java/io/how-to-generate-sha-or-md5-file-checksum-hash-in-java/ public static String getFileChecksum(MessageDigest digest, File file) throws IOException { //Get file input stream for reading the file content FileInputStream fis = new FileInputStream(file); //Create byte array to read data in chunks byte[] byteArray = new byte[1024]; int bytesCount = 0; //Read file data and update in message digest while ((bytesCount = fis.read(byteArray)) != -1) { digest.update(byteArray, 0, bytesCount); }; //close the stream; We don't need it now. fis.close(); //Get the hash's bytes byte[] bytes = digest.digest(); //This bytes[] has bytes in decimal format; //Convert it to hexadecimal format StringBuilder sb = new StringBuilder(); for(int i=0; i< bytes.length ;i++) { sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1)); } //return complete hash return sb.toString(); } public static String readUrl(String urlString) throws Exception { BufferedReader reader = null; try { URL url = new URL(urlString); reader = new BufferedReader(new InputStreamReader(url.openStream())); StringBuilder buffer = new StringBuilder(); int read; char[] chars = new char[1024]; while ((read = reader.read(chars)) != -1) { buffer.append(chars, 0, read); } return buffer.toString(); } finally { if (reader != null) { reader.close(); } } } public static boolean validUrl(String path) { try { URL url = new URL(path); url.toURI(); return true; } catch(Exception e) { return false; } } /** * Compares two version strings. * * Use this instead of String.compareTo() for a non-lexicographical comparison * that works for version strings. e.g. "1.10".compareTo("1.6"). * * @note It does not work if "1.10" is supposed to be equal to "1.10.0". * * @param str1 a string of ordinal numbers separated by decimal points. * @param str2 a string of ordinal numbers separated by decimal points. * @return The result is a negative integer if str1 is _numerically_ less than * str2. The result is a positive integer if str1 is _numerically_ greater * than str2. The result is zero if the strings are _numerically_ equal. * @source http://stackoverflow.com/a/6702029/1418878 */ public static Integer versionCompare(String str1, String str2) { String[] vals1 = str1.split("\\."); String[] vals2 = str2.split("\\."); int i = 0; // set index to first non-equal ordinal or length of shortest version string while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) { i++; } // compare first non-equal ordinal number if (i < vals1.length && i < vals2.length) { int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i])); return Integer.signum(diff); } // the strings are equal or one string is a substring of the other // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4" else { return Integer.signum(vals1.length - vals2.length); } } /** * Returns keys by value * * @param map map with data * @param value searched value * @return list of keys that has searched value * @source http://stackoverflow.com/a/2904266/1418878 */ public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) { return map.entrySet() .stream() .filter(entry -> Objects.equals(entry.getValue(), value)) .map(Map.Entry::getKey) .collect(Collectors.toSet()); } /** * Gets directory for local application files * * @source http://stackoverflow.com/a/16660314/1418878 * @return path to local Pattypan directory */ public static String getApplicationDirectory() { String dir; String OS = (System.getProperty("os.name")).toUpperCase(); if (OS.contains("WIN")) { dir = System.getenv("AppData") + "/Pattypan"; } else if (OS.contains("NUX")) { dir = System.getProperty("user.home") + "/.pattypan"; } else { dir = System.getProperty("user.home"); dir += "/Library/Application Support/Pattypan"; } return dir; } }