/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2017 Andreas Maschke This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This software 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jwildfire.base; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; import org.jwildfire.base.mathlib.MathLib; import org.jwildfire.image.Pixel; public class Tools { public static final String APP_TITLE = "JWildfire"; public static final String APP_VERSION = "3.10 (21.04.2017)"; public static final boolean SPECIAL_VERSION = false; public static final int MAX_SPATIAL_OVERSAMPLING = 6; public static final int VPREC = 1024; public static final int SPREC = 10; public static final int PLOT_BUFFER_SIZE = 4096; private static final Pixel toolPixel = new Pixel(); public static final String FILE_ENCODING = "utf-8"; public static final String FILEEXT_ANB = "anb"; public static final String FILEEXT_FLAME = "flame"; public static final String FILEEXT_GRADIENT = "gradient"; public static final String FILEEXT_GIF = "gif"; public static final String FILEEXT_HDR = "hdr"; public static final String FILEEXT_JAVA = "java"; public static final String FILEEXT_JFX = "jfx"; public static final String FILEEXT_JPG = "jpg"; public static final String FILEEXT_JPS = "jps"; public static final String FILEEXT_JPEG = "jpeg"; public static final String FILEEXT_JWFDANCE = "jwfdance"; public static final String FILEEXT_JWFMOVIE = "jwfmovie"; public static final String FILEEXT_JWFRENDER = "jwfrender"; public static final String FILEEXT_JWFSCRIPT = "jwfscript"; public static final String FILEEXT_MP3 = "mp3"; public static final String FILEEXT_OBJ = "obj"; public static final String FILEEXT_PNG = "png"; public static final String FILEEXT_PNS = "pns"; public static final String FILEEXT_SPL = "spl"; public static final String FILEEXT_SUNFLOW_SCENE = "sc"; public static final String FILEEXT_SVG = "svg"; public static final String FILEEXT_TXT = "txt"; public static final String FILEEXT_TEXT = "text"; public static final String FILEEXT_UGR = "ugr"; public static final String FILEEXT_WAV = "wav"; public static final String FILEEXT_XML = "xml"; public static final String FILEEXT_MAP = "map"; public static final String CURVE_POSTFIX = "Curve"; public static final double fmod33(double arg) { return (arg - (double) ((int) arg)); } public static Integer RGBToARGBValue(int pR, int pG, int pB) { toolPixel.r = pR; toolPixel.g = pG; toolPixel.b = pB; return toolPixel.getARGBValue(); } public static boolean isDebugMode() { return true; } public static Date now() { return Calendar.getInstance().getTime(); } public static String DateToString(Date pDate) { DateFormat formatter = new SimpleDateFormat("dd.MM.yyyy"); return formatter.format(pDate); } public static String TimeToString(Date pDate) { DateFormat formatter = new SimpleDateFormat("hh:mm:ss"); return formatter.format(pDate); } public static String DateTimeToString(Date pDate) { DateFormat formatter = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss"); return formatter.format(pDate); } public static String forceFileExt(String pFilename, String pExt) { if ((pExt != null) && (pExt.length() > 0)) { boolean hasFileExt = false; for (int i = pFilename.length() - 1; i > 0; i--) { if (pFilename.charAt(i) == '.') { String ext = pFilename.substring(i + 1, pFilename.length()); hasFileExt = ext.equals(pExt); break; } } if (!hasFileExt) pFilename = pFilename + "." + pExt; } return pFilename; } public static String readUTF8Textfile(InputStream pInputStream) throws Exception { StringBuffer content = new StringBuffer(); String lineFeed = System.getProperty("line.separator"); String line; Reader r = new InputStreamReader(pInputStream, "utf-8"); BufferedReader in = new BufferedReader(r); while ((line = in.readLine()) != null) content.append(line).append(lineFeed); in.close(); return content.toString(); } public static String readUTF8Textfile(String pTextFileName) throws Exception { StringBuffer content = new StringBuffer(); String lineFeed = System.getProperty("line.separator"); String line; Reader r = new InputStreamReader(new FileInputStream(pTextFileName), "utf-8"); BufferedReader in = new BufferedReader(r); while ((line = in.readLine()) != null) content.append(line).append(lineFeed); in.close(); return content.toString(); } public static void writeUTF8Textfile(String pTextFileName, String pContent) throws Exception { String line, lineFeed = "\r\n"; BufferedReader in = new BufferedReader(new StringReader(pContent)); Writer w = new OutputStreamWriter(new FileOutputStream(pTextFileName), "utf-8"); BufferedWriter out = new BufferedWriter(w); while ((line = in.readLine()) != null) { out.write(line); out.write(lineFeed); } out.close(); in.close(); } public static double fabs33(double pArg) { if (pArg < 0.0) return (0.0 - pArg); else return (pArg); } private static int a123 = 1; private static final int RAND_MAX123 = 0x7fffffff; private static int rand123() { return (a123 = a123 * 1103515245 + 12345) % RAND_MAX123; } public static void srand123(int pSeed) { a123 = pSeed; } private static double rrmax = 1.0 / (double) RAND_MAX123; public static double drand() { double res = ((double) (rand123() * rrmax)); return (res < 0) ? 0.0 - res : res; } public static int roundColor(double pColor) { int res = (int) (pColor + 0.5); if (res < 0) res = 0; else if (res > 255) res = 255; return res; } public static int limitColor(int pColor) { if (pColor < 0) return 0; else if (pColor > 255) return 255; else return pColor; } public static int bresenham(int x1, int y1, int x2, int y2, int[] x, int[] y) { int dx, dy, xf, yf, a, b, c, i; if (x2 > x1) { dx = x2 - x1; xf = 1; } else { dx = x1 - x2; xf = -1; } if (y2 > y1) { dy = y2 - y1; yf = 1; } else { dy = y1 - y2; yf = -1; } if (dx > dy) { a = dy + dy; c = a - dx; b = c - dx; for (i = 0; i <= dx; i++) { x[i] = x1; y[i] = y1; x1 += xf; if (c < 0) { c += a; } else { c += b; y1 += yf; } } return dx + 1; } else { a = dx + dx; c = a - dy; b = c - dy; for (i = 0; i <= dy; i++) { x[i] = x1; y[i] = y1; y1 += yf; if (c < 0) { c += a; } else { c += b; x1 += xf; } } return dy + 1; } } public static double stringToDouble(String pValue) { pValue = pValue.replace(',', '.'); return Double.parseDouble(pValue); } private static NumberFormat dFmtNormal; private static NumberFormat dFmtMicro; public static boolean USE_TEXTURES = true; static { dFmtNormal = DecimalFormat.getInstance(Locale.US); dFmtNormal.setGroupingUsed(false); dFmtNormal.setMaximumFractionDigits(8); dFmtNormal.setMinimumIntegerDigits(1); dFmtMicro = DecimalFormat.getInstance(Locale.US); dFmtMicro.setGroupingUsed(false); dFmtMicro.setMaximumFractionDigits(16); dFmtMicro.setMinimumIntegerDigits(1); } public static String doubleToString(double pValue) { NumberFormat fmt = Math.abs(pValue) > 0.000001 ? dFmtNormal : dFmtMicro; return fmt.format(pValue); } public static int stringToInt(String pValue) { return Integer.parseInt(pValue); } public static String intToString(int pValue) { return String.valueOf(pValue); } private static final byte hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; public static String byteArrayToHexString(byte[] pByteArray) { if (pByteArray != null && pByteArray.length > 0) { byte[] b = new byte[2 * pByteArray.length]; int k = 0; for (int i = 0; i < pByteArray.length; i++) { int j = pByteArray[i]; if (j < 0) { j += 256; } b[k++] = hexChars[j >> 4]; b[k++] = hexChars[j % 16]; } return new String(b); } return null; } public static byte[] hexStringToByteArray(String pHexStr) { if (pHexStr.length() > 0) { if ((pHexStr.length() % 2) != 0) { throw new IllegalArgumentException(pHexStr); } byte[] b = new byte[pHexStr.length() / 2]; int k = 0; for (int i = 0; i < pHexStr.length(); i++) { char c = pHexStr.charAt(i); int v; switch (c) { case '0': v = 0; break; case '1': v = 1; break; case '2': v = 2; break; case '3': v = 3; break; case '4': v = 4; break; case '5': v = 5; break; case '6': v = 6; break; case '7': v = 7; break; case '8': v = 8; break; case '9': v = 9; break; case 'A': v = 10; break; case 'B': v = 11; break; case 'C': v = 12; break; case 'D': v = 13; break; case 'E': v = 14; break; case 'F': v = 15; break; default: throw new IllegalStateException("'" + c + "'"); } if ((i % 2) != 0) { b[i / 2] = (byte) (k + v); } else { k = v * 16; } } return b; } else { return null; } } // legacy code public static final int FTOI(double val) { int sig = MathLib.sign(val); if (sig > 0) return (int) (val + 0.5); else if (sig < 0) return (int) (0.0 - (MathLib.fabs(val) + 0.5)); else return 0; } public static final byte[] readFile(String pFilename) throws Exception { BufferedInputStream in = new BufferedInputStream(new FileInputStream(pFilename)); ByteArrayOutputStream os = new ByteArrayOutputStream(); final int BUFFER_SIZE = 40960; byte[] buffer = new byte[BUFFER_SIZE]; try { int n; while ((n = in.read(buffer, 0, BUFFER_SIZE)) >= 0) { os.write(buffer, 0, n); } os.flush(); os.close(); return os.toByteArray(); } finally { in.close(); } } public static final void writeFile(String pFilename, byte[] pData) throws Exception { FileOutputStream fos = new FileOutputStream(pFilename); fos.write(pData, 0, pData.length); fos.flush(); fos.close(); } public static class XMLAttributes { private final List<XMLAttribute> attrList = new ArrayList<XMLAttribute>(); private final Map<String, XMLAttribute> attrMap = new HashMap<String, XMLAttribute>(); public void addAttribute(XMLAttribute pAttribute) { attrList.add(pAttribute); attrMap.put(pAttribute.getName(), pAttribute); } public XMLAttribute getAttribute(String pKey) { return attrMap.get(pKey); } public String get(String pKey) { XMLAttribute attr = getAttribute(pKey); return attr != null ? attr.getValue() : null; } public List<XMLAttribute> getAttributes() { return attrList; } } public static class XMLAttribute { private final String name; private final String value; public XMLAttribute(String pName, String pValue) { name = pName; value = pValue; } public String getName() { return name; } public String getValue() { return value; } } public static XMLAttributes parseAttributes(String pXML) { XMLAttributes res = new XMLAttributes(); int p = 0; while (true) { int ps = pXML.indexOf("=\"", p + 1); if (ps < 0) break; int pe = pXML.indexOf("\"", ps + 2); String name = pXML.substring(p, ps).trim(); String value; try { value = pXML.substring(ps + 2, pe); // System.out.println("#" + name + "#" + value + "#"); } catch (Throwable ex) { throw new RuntimeException("Error parsing attribute \"" + name + "\" (" + pXML + ")", ex); } if (value != null) { value = value.replaceAll(""", "\"").replaceAll("<", "<").replaceAll(">", ">").replaceAll("&", "&"); } res.addAttribute(new XMLAttribute(name, value)); p = pe + 2; } return res; } public static String trimFileExt(String pName) { int p = pName.lastIndexOf("."); if (p > 0 && p < pName.length() - 1) { return pName.substring(0, p); } return pName; } public static String getFileExt(String pName) { int p = pName.lastIndexOf("."); if (p > 0 && p < pName.length() - 1) { return pName.substring(p + 1, pName.length()); } return pName; } public static boolean stringEquals(String a, String b) { if (a == null) return b == null; else return a.equals(b); } public static void writeObjectToFile(Object pObject, String pFilename) { try ( OutputStream file = new FileOutputStream(pFilename); OutputStream buffer = new BufferedOutputStream(file); ObjectOutput output = new ObjectOutputStream(buffer);) { output.writeObject(pObject); } catch (IOException ex) { Unchecker.rethrow(ex); } } public static Object readObjectFromFile(String pFilename) { try ( InputStream file = new FileInputStream(pFilename); InputStream buffer = new BufferedInputStream(file); ObjectInput input = new ObjectInputStream(buffer);) { return input.readObject(); } catch (Exception ex) { Unchecker.rethrow(ex); return null; } } public static double limitValue(double value, double min, double max) { return value < min ? min : value > max ? max : value; } public static int limitValue(int value, int min, int max) { return value < min ? min : value > max ? max : value; } public static String getRessourceAsString(Class<?> parent, String ressource) throws Exception { try (InputStream is = parent.getResourceAsStream(ressource)) { StringBuffer content = new StringBuffer(); String lineFeed = System.getProperty("line.separator"); String line; Reader r = new InputStreamReader(is, "utf-8"); BufferedReader in = new BufferedReader(r); while ((line = in.readLine()) != null) { content.append(line).append(lineFeed); } in.close(); return content.toString(); } } public static String makeZBufferFilename(String absolutePath) { File f = new File(absolutePath); return new File(f.getParent(), "zbuf_" + f.getName()).getAbsolutePath(); } public static String makeHDRFilename(String absolutePath) { File f = new File(absolutePath); String name = Tools.trimFileExt(f.getName()); return new File(f.getParent(), name + ".hdr").getAbsolutePath(); } public static final Random RANDOM = new Random(); /** * Returns a pseudorandom, uniformly distributed {@code int} value * between 0 (inclusive) and the specified value (exclusive). * Uses {@link Random#nextInt(int)}. * @param bound the upper bound (exclusive). Must be positive. (greater than zero) * @return a random int value between 0 (inclusive) and bound (exclusive) */ public static int randomInt(int bound) { return RANDOM.nextInt(bound); } public static String getStacktrace(Throwable ex) { try { try (StringWriter sw = new StringWriter()) { try (PrintWriter pw = new PrintWriter(sw)) { ex.printStackTrace(pw); return sw.toString(); } } } catch (Exception innerError) { throw new RuntimeException(innerError); } } public enum OSType { WINDOWS, MAC, LINUX, UNKNOWN } public static OSType getOSType() { String os = System.getProperty("os.name").toLowerCase(Locale.ENGLISH); if (os.startsWith("mac os")) return OSType.MAC; else if (os.startsWith("windows")) return OSType.WINDOWS; else if (os.startsWith("linux")) return OSType.LINUX; else return OSType.UNKNOWN; } }