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

org.sikuli.basics.FileManager Maven / Gradle / Ivy

/*
 * Copyright (c) 2010-2016, Sikuli.org, sikulix.com
 * Released under the MIT License.
 *
 */
package org.sikuli.basics;

import org.sikuli.script.RunTime;
import java.awt.Desktop;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Random;
import java.util.Set;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import org.sikuli.script.Image;
import org.sikuli.script.ImagePath;
import org.sikuli.script.Sikulix;

/**
 * INTERNAL USE: Support for accessing files and other ressources
 */
public class FileManager {

  private static String me = "FileManager";
  private static int lvl = 3;

  private static void log(int level, String message, Object... args) {
    Debug.logx(level, me + ": " + message, args);
  }

  static final int DOWNLOAD_BUFFER_SIZE = 153600;
  private static SplashFrame _progress = null;
  private static final String EXECUTABLE = "#executable";

  public static int tryGetFileSize(URL aUrl) {
    HttpURLConnection conn = null;
    try {
      if (getProxy() != null) {
        conn = (HttpURLConnection) aUrl.openConnection(getProxy());
      } else {
        conn = (HttpURLConnection) aUrl.openConnection();
      }
      conn.setConnectTimeout(30000);
      conn.setReadTimeout(30000);
      conn.setRequestMethod("HEAD");
      conn.getInputStream();
      return conn.getContentLength();
    } catch (Exception ex) {
      return 0;
    } finally {
      if (conn != null) {
        conn.disconnect();
      }
    }
  }

	public static int isUrlUseabel(String sURL) {
		try {
			return isUrlUseabel(new URL(sURL));
		} catch (Exception ex) {
			return -1;
		}
	}

	public static int isUrlUseabel(URL aURL) {
    HttpURLConnection conn = null;
		try {
//			HttpURLConnection.setFollowRedirects(false);
	    if (getProxy() != null) {
    		conn = (HttpURLConnection) aURL.openConnection(getProxy());
      } else {
    		conn = (HttpURLConnection) aURL.openConnection();
      }
//			con.setInstanceFollowRedirects(false);
			conn.setRequestMethod("HEAD");
			int retval = conn.getResponseCode();
//				HttpURLConnection.HTTP_BAD_METHOD 405
//				HttpURLConnection.HTTP_NOT_FOUND 404
			if (retval == HttpURLConnection.HTTP_OK) {
				return 1;
			} else if (retval == HttpURLConnection.HTTP_NOT_FOUND) {
				return 0;
			} else if (retval == HttpURLConnection.HTTP_FORBIDDEN) {
				return 0;
			} else {
				return -1;
			}
		} catch (Exception ex) {
			return -1;
    } finally {
      if (conn != null) {
        conn.disconnect();
      }
    }
	}

  public static Proxy getProxy() {
    Proxy proxy = Settings.proxy;
    if (!Settings.proxyChecked) {
      String phost = Settings.proxyName;
      String padr = Settings.proxyIP;
      String pport = Settings.proxyPort;
      InetAddress a = null;
      int p = -1;
      if (phost != null) {
        a = getProxyAddress(phost);
      }
      if (a == null && padr != null) {
        a = getProxyAddress(padr);
      }
      if (a != null && pport != null) {
        p = getProxyPort(pport);
      }
      if (a != null && p > 1024) {
        proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(a, p));
        log(lvl, "Proxy defined: %s : %d", a.getHostAddress(), p);
      }
      Settings.proxyChecked = true;
      Settings.proxy = proxy;
    }
    return proxy;
  }

  public static boolean setProxy(String pName, String pPort) {
    InetAddress a = null;
    String host = null;
    String adr = null;
    int p = -1;
    if (pName != null) {
      a = getProxyAddress(pName);
      if (a == null) {
        a = getProxyAddress(pName);
        if (a != null) {
          adr = pName;
        }
      } else {
        host = pName;
      }
    }
    if (a != null && pPort != null) {
      p = getProxyPort(pPort);
    }
    if (a != null && p > 1024) {
      log(lvl, "Proxy stored: %s : %d", a.getHostAddress(), p);
      Settings.proxyChecked = true;
      Settings.proxyName = host;
      Settings.proxyIP = adr;
      Settings.proxyPort = pPort;
      Settings.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(a, p));
      PreferencesUser prefs = PreferencesUser.getInstance();
      prefs.put("ProxyName", (host == null ? "" : host));
      prefs.put("ProxyIP", (adr == null ? "" : adr));
      prefs.put("ProxyPort", ""+p);
      return true;
    }
    return false;
  }

  /**
   * download a file at the given url to a local folder
   *
   * @param url a valid url
   * @param localPath the folder where the file should go (will be created if necessary)
   * @return the absolute path to the downloaded file or null on any error
   */
  public static String downloadURL(URL url, String localPath) {
    String[] path = url.getPath().split("/");
    String filename = path[path.length - 1];
    String targetPath = null;
    int srcLength = 1;
    int srcLengthKB = 0;
    int done;
    int totalBytesRead = 0;
    File fullpath = new File(localPath);
    if (fullpath.exists()) {
      if (fullpath.isFile()) {
        log(-1, "download: target path must be a folder:\n%s", localPath);
        fullpath = null;
      }
    } else {
      if (!fullpath.mkdirs()) {
        log(-1, "download: could not create target folder:\n%s", localPath);
        fullpath = null;
      }
    }
    if (fullpath != null) {
      srcLength = tryGetFileSize(url);
      srcLengthKB = (int) (srcLength / 1024);
      if (srcLength > 0) {
        log(lvl, "Downloading %s having %d KB", filename, srcLengthKB);
			} else {
        log(lvl, "Downloading %s with unknown size", filename);
			}
			fullpath = new File(localPath, filename);
			targetPath = fullpath.getAbsolutePath();
			done = 0;
			if (_progress != null) {
				_progress.setProFile(filename);
				_progress.setProSize(srcLengthKB);
				_progress.setProDone(0);
				_progress.setVisible(true);
			}
			InputStream reader = null;
      FileOutputStream writer = null;
			try {
				writer = new FileOutputStream(fullpath);
				if (getProxy() != null) {
					reader = url.openConnection(getProxy()).getInputStream();
				} else {
					reader = url.openConnection().getInputStream();
				}
				byte[] buffer = new byte[DOWNLOAD_BUFFER_SIZE];
				int bytesRead = 0;
				long begin_t = (new Date()).getTime();
				long chunk = (new Date()).getTime();
				while ((bytesRead = reader.read(buffer)) > 0) {
					writer.write(buffer, 0, bytesRead);
					totalBytesRead += bytesRead;
					if (srcLength > 0) {
						done = (int) ((totalBytesRead / (double) srcLength) * 100);
					} else {
						done = (int) (totalBytesRead / 1024);
					}
					if (((new Date()).getTime() - chunk) > 1000) {
						if (_progress != null) {
							_progress.setProDone(done);
						}
						chunk = (new Date()).getTime();
					}
				}
				writer.close();
				log(lvl, "downloaded %d KB to:\n%s", (int) (totalBytesRead / 1024), targetPath);
				log(lvl, "download time: %d", (int) (((new Date()).getTime() - begin_t) / 1000));
			} catch (Exception ex) {
				log(-1, "problems while downloading\n%s", ex);
				targetPath = null;
			} finally {
				if (reader != null) {
					try {
						reader.close();
					} catch (IOException ex) {
					}
				}
				if (writer != null) {
					try {
						writer.close();
					} catch (IOException ex) {
					}
				}
			}
      if (_progress != null) {
        if (targetPath == null) {
          _progress.setProDone(-1);
        } else {
          if (srcLength <= 0) {
            _progress.setProSize((int) (totalBytesRead / 1024));
          }
          _progress.setProDone(100);
        }
        _progress.closeAfter(3);
        _progress = null;
      }
    }
    if (targetPath == null) {
      fullpath.delete();
    }
    return targetPath;
  }

  /**
   * download a file at the given url to a local folder
   *
   * @param url a string representing a valid url
   * @param localPath the folder where the file should go (will be created if necessary)
   * @return the absolute path to the downloaded file or null on any error
   */
  public static String downloadURL(String url, String localPath) {
    URL urlSrc = null;
    try {
      urlSrc = new URL(url);
    } catch (MalformedURLException ex) {
      log(-1, "download: bad URL: " + url);
      return null;
    }
    return downloadURL(urlSrc, localPath);
  }

  public static String downloadURL(String url, String localPath, JFrame progress) {
    _progress = (SplashFrame) progress;
    return downloadURL(url, localPath);
  }

  public static String downloadURLtoString(String src) {
    URL url = null;
    try {
      url = new URL(src);
    } catch (MalformedURLException ex) {
      log(-1, "download to string: bad URL:\n%s", src);
      return null;
    }
    return downloadURLtoString(url);
  }

  public static String downloadURLtoString(URL uSrc) {
    String content = "";
    InputStream reader = null;
    log(lvl, "download to string from:\n%s,", uSrc);
    try {
      if (getProxy() != null) {
        reader = uSrc.openConnection(getProxy()).getInputStream();
      } else {
        reader = uSrc.openConnection().getInputStream();
      }
      byte[] buffer = new byte[DOWNLOAD_BUFFER_SIZE];
      int bytesRead = 0;
      while ((bytesRead = reader.read(buffer)) > 0) {
        content += (new String(Arrays.copyOfRange(buffer, 0, bytesRead), Charset.forName("utf-8")));
      }
    } catch (Exception ex) {
      log(-1, "problems while downloading\n" + ex.getMessage());
    } finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (IOException ex) {
        }
      }
    }
    return content;
  }

  /**
   * open the given url in the standard browser
   *
   * @param url string representing a valid url
   * @return false on error, true otherwise
   */
  public static boolean openURL(String url) {
    try {
      URL u = new URL(url);
      Desktop.getDesktop().browse(u.toURI());
    } catch (Exception ex) {
      log(-1, "show in browser: bad URL: " + url);
      return false;
    }
    return true;
  }

  public static File createTempDir(String path) {
    File fTempDir = new File(RunTime.get().fpBaseTempPath, path);
    log(lvl, "createTempDir:\n%s", fTempDir);
    if (!fTempDir.exists()) {
      fTempDir.mkdirs();
    } else {
      FileManager.resetFolder(fTempDir);
    }
    if (!fTempDir.exists()) {
      log(-1, "createTempDir: not possible: %s", fTempDir);
      return null;
    }
    return fTempDir;
  }

  public static File createTempDir() {
    File fTempDir = createTempDir("tmp-" + getRandomInt() + ".sikuli");
    if (null != fTempDir) {
      fTempDir.deleteOnExit();
    }
    return fTempDir;
  }

  public static int getRandomInt() {
    int rand = 1 + new Random().nextInt();
    return (rand < 0 ? rand * -1 : rand);
  }

  public static void deleteTempDir(String path) {
    if (!deleteFileOrFolder(path)) {
      log(-1, "deleteTempDir: not possible");
    }
  }

  public static boolean deleteFileOrFolder(File fPath, FileFilter filter) {
    return doDeleteFileOrFolder(fPath, filter);
	}

  public static boolean deleteFileOrFolder(File fPath) {
    return doDeleteFileOrFolder(fPath, null);
	}

  public static boolean deleteFileOrFolder(String fpPath, FileFilter filter) {
    if (fpPath.startsWith("#")) {
      fpPath = fpPath.substring(1);
    } else {
  		log(lvl, "deleteFileOrFolder: %s\n%s", (filter == null ? "" : "filtered: "), fpPath);
    }
    return doDeleteFileOrFolder(new File(fpPath), filter);
	}

  public static boolean deleteFileOrFolder(String fpPath) {
    if (fpPath.startsWith("#")) {
      fpPath = fpPath.substring(1);
    } else {
  		log(lvl, "deleteFileOrFolder:\n%s", fpPath);
    }
    return doDeleteFileOrFolder(new File(fpPath), null);
  }

  public static void resetFolder(File fPath) {
		log(lvl, "resetFolder:\n%s", fPath);
    doDeleteFileOrFolder(fPath, null);
    fPath.mkdirs();
  }

  private static boolean doDeleteFileOrFolder(File fPath, FileFilter filter) {
    if (fPath == null) {
      return false;
    }
    File aFile;
    String[] entries;
    boolean somethingLeft = false;
    if (fPath.exists() && fPath.isDirectory()) {
      entries = fPath.list();
      for (int i = 0; i < entries.length; i++) {
        aFile = new File(fPath, entries[i]);
        if (filter != null && !filter.accept(aFile)) {
          somethingLeft = true;
          continue;
        }
        if (aFile.isDirectory()) {
          if (!doDeleteFileOrFolder(aFile, filter)) {
            return false;
          }
        } else {
          try {
            aFile.delete();
          } catch (Exception ex) {
            log(-1, "deleteFile: not deleted:\n%s\n%s", aFile, ex);
            return false;
          }
        }
      }
    }
    // deletes intermediate empty directories and finally the top now empty dir
    if (!somethingLeft && fPath.exists()) {
      try {
        fPath.delete();
      } catch (Exception ex) {
        log(-1, "deleteFolder: not deleted:\n" + fPath.getAbsolutePath() + "\n" + ex.getMessage());
        return false;
      }
    }
    return true;
  }

  public static void traverseFolder(File fPath, FileFilter filter) {
    if (fPath == null) {
      return;
    }
    File aFile;
    String[] entries;
    if (fPath.isDirectory()) {
      entries = fPath.list();
      for (int i = 0; i < entries.length; i++) {
        aFile = new File(fPath, entries[i]);
        if (filter != null) {
          filter.accept(aFile);
        }
        if (aFile.isDirectory()) {
          traverseFolder(aFile, filter);
        }
      }
    }
  }

  public static File createTempFile(String suffix) {
    return createTempFile(suffix, null);
  }

  public static File createTempFile(String suffix, String path) {
    String temp1 = "sikuli-";
    String temp2 = "." + suffix;
    File fpath = new File(RunTime.get().fpBaseTempPath);
    if (path != null) {
      fpath = new File(path);
    }
    try {
      fpath.mkdirs();
      File temp = File.createTempFile(temp1, temp2, fpath);
      temp.deleteOnExit();
      String fpTemp = temp.getAbsolutePath();
      if (!fpTemp.endsWith(".script")) {
        log(lvl, "tempfile create:\n%s", temp.getAbsolutePath());
      }
      return temp;
    } catch (IOException ex) {
      log(-1, "createTempFile: IOException: %s\n%s", ex.getMessage(),
              fpath + File.separator + temp1 + "12....56" + temp2);
      return null;
    }
  }

  public static String saveTmpImage(BufferedImage img) {
    return saveTmpImage(img, null);
  }

  public static String saveTmpImage(BufferedImage img, String path) {
    File tempFile;
    try {
      tempFile = createTempFile("png", path);
      if (tempFile != null) {
        ImageIO.write(img, "png", tempFile);
        return tempFile.getAbsolutePath();
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  }

  public static String saveTimedImage(BufferedImage img) {
    return saveTimedImage(img, ImagePath.getBundlePath(), null);
  }

  public static String saveTimedImage(BufferedImage img, String path) {
    return saveTimedImage(img, path, null);
  }

  public static String saveTimedImage(BufferedImage img, String path, String name) {
    RunTime.pause(0.01f);
    File fImage = new File(path, String.format("%s-%d.png", name, new Date().getTime()));
    try {
      ImageIO.write(img, "png", fImage);
    } catch (Exception ex) {
      return "";
    }
    return fImage.getAbsolutePath();
  }

  public static boolean unzip(String inpZip, String target) {
    return unzip(new File(inpZip), new File(target));
  }

  public static boolean unzip(File fZip, File fTarget) {
    String fpZip = null;
    String fpTarget = null;
    log(lvl, "unzip: from: %s\nto: %s", fZip, fTarget);
    try {
      fpZip = fZip.getCanonicalPath();
      if (!new File(fpZip).exists()) {
        throw new IOException();
      }
    } catch (IOException ex) {
      log(-1, "unzip: source not found:\n%s\n%s", fpZip, ex);
      return false;
    }
    try {
      fpTarget = fTarget.getCanonicalPath();
      deleteFileOrFolder(fpTarget);
      new File(fpTarget).mkdirs();
      if (!new File(fpTarget).exists()) {
        throw new IOException();
      }
    } catch (IOException ex) {
      log(-1, "unzip: target cannot be created:\n%s\n%s", fpTarget, ex);
      return false;
    }
    ZipInputStream inpZip = null;
    ZipEntry entry = null;
    try {
      final int BUF_SIZE = 2048;
      inpZip = new ZipInputStream(new BufferedInputStream(new FileInputStream(fZip)));
      while ((entry = inpZip.getNextEntry()) != null) {
        if (entry.getName().endsWith("/") || entry.getName().endsWith("\\")) {
          new File(fpTarget, entry.getName()).mkdir();
          continue;
        }
        int count;
        byte data[] = new byte[BUF_SIZE];
        File outFile = new File(fpTarget, entry.getName());
        File outFileParent = outFile.getParentFile();
        if (! outFileParent.exists()) {
          outFileParent.mkdirs();
        }
        FileOutputStream fos = new FileOutputStream(outFile);
        BufferedOutputStream dest = new BufferedOutputStream(fos, BUF_SIZE);
        while ((count = inpZip.read(data, 0, BUF_SIZE)) != -1) {
          dest.write(data, 0, count);
        }
        dest.close();
      }
    } catch (Exception ex) {
      log(-1, "unzip: not possible: source:\n%s\ntarget:\n%s\n(%s)%s",
          fpZip, fpTarget, entry.getName(), ex);
      return false;
    } finally {
      try {
        inpZip.close();
      } catch (IOException ex) {
        log(-1, "unzip: closing source:\n%s\n%s", fpZip, ex);
      }
    }
    return true;
  }

  public static boolean xcopy(File fSrc, File fDest) {
    if (fSrc == null || fDest == null) {
      return false;
    }
    try {
      doXcopy(fSrc, fDest, null);
    } catch (Exception ex) {
      log(lvl, "xcopy from: %s\nto: %s\n%s", fSrc, fDest, ex);
      return false;
    }
    return true;
	}

  public static boolean xcopy(File fSrc, File fDest, FileFilter filter) {
    if (fSrc == null || fDest == null) {
      return false;
    }
    try {
      doXcopy(fSrc, fDest, filter);
    } catch (Exception ex) {
      log(lvl, "xcopy from: %s\nto: %s\n%s", fSrc, fDest, ex);
      return false;
    }
    return true;
	}

  public static void xcopy(String src, String dest) throws IOException {
		doXcopy(new File(src), new File(dest), null);
	}

  public static void xcopy(String src, String dest, FileFilter filter) throws IOException {
		doXcopy(new File(src), new File(dest), filter);
	}

  private static void doXcopy(File fSrc, File fDest, FileFilter filter) throws IOException {
    if (fSrc.getAbsolutePath().equals(fDest.getAbsolutePath())) {
      return;
    }
    if (fSrc.isDirectory()) {
			if (filter == null || filter.accept(fSrc)) {
				if (!fDest.exists()) {
					fDest.mkdirs();
				}
				String[] children = fSrc.list();
				for (String child : children) {
					if (child.equals(fDest.getName())) {
						continue;
					}
					doXcopy(new File(fSrc, child), new File(fDest, child), filter);

				}
			}
		} else {
			if (filter == null || filter.accept(fSrc)) {
				if (fDest.isDirectory()) {
					fDest = new File(fDest, fSrc.getName());
				}
				InputStream in = new FileInputStream(fSrc);
				OutputStream out = new FileOutputStream(fDest);
				// Copy the bits from instream to outstream
				byte[] buf = new byte[1024];
				int len;
				while ((len = in.read(buf)) > 0) {
					out.write(buf, 0, len);
				}
				in.close();
				out.close();
			}
		}
  }

  private static String makeFileListString;
  private static String makeFileListPrefix;

  public static String makeFileList(File path, String prefix) {
    makeFileListPrefix = prefix;
    return makeFileListDo(path, true);
  }

  private static String makeFileListDo(File path, boolean starting) {
    String x;
    if (starting) {
      makeFileListString = "";
    }
    if (!path.exists()) {
      return makeFileListString;
    }
    if (path.isDirectory()) {
      String[] fcl = path.list();
      for (String fc : fcl) {
        makeFileListDo(new File(path, fc), false);
      }
    } else {
      x = path.getAbsolutePath();
      if (!makeFileListPrefix.isEmpty()) {
        x = x.replace(makeFileListPrefix, "").replace("\\", "/");
        if (x.startsWith("/")) {
          x = x.substring(1);
        }
      }
      makeFileListString += x + "\n";
    }
    return makeFileListString;
  }

  /**
   * Copy a file *src* to the path *dest* and check if the file name conflicts. If a file with the
   * same name exists in that path, rename *src* to an alternative name.
	 * @param src source file
	 * @param dest destination path
	 * @return the destination file if ok, null otherwise
	 * @throws java.io.IOException on failure
   */
  public static File smartCopy(String src, String dest) throws IOException {
    File fSrc = new File(src);
    String newName = fSrc.getName();
    File fDest = new File(dest, newName);
    if (fSrc.equals(fDest)) {
      return fDest;
    }
    while (fDest.exists()) {
      newName = getAltFilename(newName);
      fDest = new File(dest, newName);
    }
    xcopy(src, fDest.getAbsolutePath());
    if (fDest.exists()) {
      return fDest;
    }
    return null;
  }

  public static String convertStreamToString(InputStream is) {
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();
    String line;
    try {
      while ((line = reader.readLine()) != null) {
        sb.append(line).append("\n");
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        is.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return sb.toString();
  }

  public static String getAltFilename(String filename) {
    int pDot = filename.lastIndexOf('.');
    int pDash = filename.lastIndexOf('-');
    int ver = 1;
    String postfix = filename.substring(pDot);
    String name;
    if (pDash >= 0) {
      name = filename.substring(0, pDash);
      ver = Integer.parseInt(filename.substring(pDash + 1, pDot));
      ver++;
    } else {
      name = filename.substring(0, pDot);
    }
    return name + "-" + ver + postfix;
  }

  public static boolean exists(String path) {
    File f = new File(path);
    return f.exists();
  }

  public static void mkdir(String path) {
    File f = new File(path);
    if (!f.exists()) {
      f.mkdirs();
    }
  }

  public static String getName(String filename) {
    File f = new File(filename);
    return f.getName();
  }

  public static String slashify(String path, Boolean isDirectory) {
    if (path != null) {
      if (path.contains("%")) {
        try {
          path = URLDecoder.decode(path, "UTF-8");
        } catch (Exception ex) {
					log(lvl, "slashify: decoding problem with %s\nwarning: filename might not be useable.", path);
        }
      }
      if (File.separatorChar != '/') {
        path = path.replace(File.separatorChar, '/');
      }
      if (isDirectory != null) {
        if (isDirectory) {
          if (!path.endsWith("/")) {
            path = path + "/";
          }
        } else if (path.endsWith("/")) {
          path = path.substring(0, path.length() - 1);
        }
      }
			if (path.startsWith("./")) {
				path = path.substring(2);
			}
      return path;
    } else {
      return "";
    }
  }

	public static String normalize(String filename) {
		return slashify(filename, false);
	}

	public static String normalizeAbsolute(String filename, boolean withTrailingSlash) {
    filename = slashify(filename, false);
    String jarSuffix = "";
    int nJarSuffix;
    if (-1 < (nJarSuffix = filename.indexOf(".jar!/"))) {
      jarSuffix = filename.substring(nJarSuffix + 4);
      filename = filename.substring(0, nJarSuffix + 4);
    }
    File aFile = new File(filename);
    try {
      filename = aFile.getCanonicalPath();
      aFile = new File(filename);
    } catch (Exception ex) {
    }
    String fpFile = aFile.getAbsolutePath();
    if (!fpFile.startsWith("/")) {
      fpFile = "/" + fpFile;
    }
		return slashify(fpFile + jarSuffix, withTrailingSlash);
	}

	public static boolean isFilenameDotted(String name) {
		String nameParent = new File(name).getParent();
		if (nameParent != null && nameParent.contains(".")) {
			return true;
		}
		return false;
	}

  /**
   * Returns the directory that contains the images used by the ScriptRunner.
   *
   * @param scriptFile The file containing the script.
   * @return The directory containing the images.
   */
  public static File resolveImagePath(File scriptFile) {
    if (!scriptFile.isDirectory()) {
      return scriptFile.getParentFile();
    }
    return scriptFile;
  }

  public static URL makeURL(String fName) {
    return makeURL(fName, "file");
  }

  public static URL makeURL(String fName, String type) {
    try {
      if ("file".equals(type)) {
        fName = normalizeAbsolute(fName, false);
        if (!fName.startsWith("/")) {
          fName = "/" + fName;
        }
      }
			if ("jar".equals(type)) {
				if (!fName.contains("!/")) {
					fName += "!/";
				}
				return new URL("jar:" + fName);
			} else if ("file".equals(type)) {
        File aFile = new File(fName);
        if (aFile.exists() && aFile.isDirectory()) {
          if (!fName.endsWith("/")) {
            fName += "/";
          }
        }
      }
      return new URL(type, null, fName);
    } catch (MalformedURLException ex) {
      return null;
    }
  }

  public static URL makeURL(URL path, String fName) {
    try {
			if ("file".equals(path.getProtocol())) {
				return makeURL(new File(path.getFile(), fName).getAbsolutePath());
			} else if ("jar".equals(path.getProtocol())) {
				String jp = path.getPath();
				if (!jp.contains("!/")) {
					jp += "!/";
				}
				String jpu = "jar:" + jp;
				if (jp.endsWith("!/")) {
				  jpu += fName;
        } else {
          jpu += "/" + fName;
        }
				return new URL(jpu);
			}
      return new URL(path, slashify(fName, false));
    } catch (MalformedURLException ex) {
      return null;
    }
  }

  public static URL getURLForContentFromURL(URL uRes, String fName) {
    URL aURL = null;
    if ("jar".equals(uRes.getProtocol())) {
      return makeURL(uRes, fName);
    } else if ("file".equals(uRes.getProtocol())) {
      aURL = makeURL(new File(slashify(uRes.getPath(), false), slashify(fName, false)).getPath(), uRes.getProtocol());
    } else if (uRes.getProtocol().startsWith("http")) {
      String sRes = uRes.toString();
			if (!sRes.endsWith("/")) {
				sRes += "/";
			}
			try {
				aURL = new URL(sRes + fName);
				if (1 == isUrlUseabel(aURL)) {
					return aURL;
				} else {
					return null;
				}
			} catch (MalformedURLException ex) {
				return null;
			}
    }
    try {
      if (aURL != null) {
        aURL.getContent();
        return aURL;
      }
    } catch (IOException ex) {
      return null;
    }
    return aURL;
  }

	public static boolean checkJarContent(String jarPath, String jarContent) {
		URL jpu = makeURL(jarPath, "jar");
		if (jpu != null && jarContent != null) {
			jpu = makeURL(jpu, jarContent);
		}
		if (jpu != null) {
			try {
			  jpu.getContent();
				return true;
			} catch (IOException ex) {
        ex.getMessage();
			}
		}
		return false;
	}

  public static int getPort(String p) {
    int port;
    int pDefault = 50000;
    if (p != null) {
      try {
        port = Integer.parseInt(p);
      } catch (NumberFormatException ex) {
        return -1;
      }
    } else {
      return pDefault;
    }
    if (port < 1024) {
      port += pDefault;
    }
    return port;
  }

  public static int getProxyPort(String p) {
    int port;
    int pDefault = 8080;
    if (p != null) {
      try {
        port = Integer.parseInt(p);
      } catch (NumberFormatException ex) {
        return -1;
      }
    } else {
      return pDefault;
    }
    return port;
  }

  public static String getAddress(String arg) {
    try {
      if (arg == null) {
        return InetAddress.getLocalHost().getHostAddress();
      }
      return InetAddress.getByName(arg).getHostAddress();
    } catch (UnknownHostException ex) {
      return null;
    }
  }

  public static InetAddress getProxyAddress(String arg) {
    try {
      return InetAddress.getByName(arg);
    } catch (UnknownHostException ex) {
      return null;
    }
  }

  public static String saveImage(BufferedImage img, String sImage, String bundlePath) {
    final int MAX_ALT_NUM = 3;
    String fullpath = bundlePath;
    File fBundle = new File(fullpath);
    if (!fBundle.exists()) {
      fBundle.mkdir();
    }
    if (!sImage.endsWith(".png")) {
      sImage += ".png";
    }
    File fImage = new File(fBundle, sImage);
    boolean shouldReload = false;
    int count = 0;
    String msg = fImage.getName() + " exists - using ";
    while (count < MAX_ALT_NUM) {
      if (fImage.exists()) {
        if (Settings.OverwriteImages) {
          shouldReload = true;
          break;
        } else {
          fImage = new File(fBundle, FileManager.getAltFilename(fImage.getName()));
        }
      } else {
        if (count > 0) {
          Debug.log(msg + fImage.getName() + " (Utils.saveImage)");
        }
        break;
      }
      count++;
    }
    if (count >= MAX_ALT_NUM) {
      fImage = new File(fBundle, Settings.getTimestamp() + ".png");
      Debug.log(msg + fImage.getName() + " (Utils.saveImage)");
    }
    String fpImage = fImage.getAbsolutePath();
    fpImage = fpImage.replaceAll("\\\\", "/");
    try {
      ImageIO.write(img, "png", new File(fpImage));
    } catch (IOException e) {
      Debug.error("Util.saveImage: Problem trying to save image file: %s\n%s", fpImage, e.getMessage());
      return null;
    }
    if (shouldReload) {
      Image.reload(sImage);
    }
    return fpImage;
  }

  //TODO consolidate with FileManager and Settings
	public static void deleteNotUsedImages(String bundle, Set usedImages) {
		File scriptFolder = new File(bundle);
		if (!scriptFolder.isDirectory()) {
			return;
		}
		String path;
		for (File image : scriptFolder.listFiles(new FilenameFilter() {
					@Override
					public boolean accept(File dir, String name) {
						if ((name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".jpeg"))) {
							if (!name.startsWith("_")) {
                return true;
              }
						}
						return false;
					}
				})) {
			if (!usedImages.contains(image.getName())) {
				Debug.log(3, "FileManager: delete not used: %s", image.getName());
				image.delete();
			}
		}
	}

	public static boolean isBundle(String dir) {
		return dir.endsWith(".sikuli");
	}

//  public static IResourceLoader getNativeLoader(String name, String[] args) {
//    if (nativeLoader != null) {
//      return nativeLoader;
//    }
//    IResourceLoader nl = null;
//    ServiceLoader loader = ServiceLoader.load(IResourceLoader.class);
//    Iterator resourceLoaderIterator = loader.iterator();
//    while (resourceLoaderIterator.hasNext()) {
//      IResourceLoader currentLoader = resourceLoaderIterator.next();
//      if ((name != null && currentLoader.getName().toLowerCase().equals(name.toLowerCase()))) {
//        nl = currentLoader;
//        nl.init(args);
//        break;
//      }
//    }
//    if (nl == null) {
//      log0(-1, "Fatal error 121: Could not load any NativeLoader!");
//      (121);
//    } else {
//      nativeLoader = nl;
//    }
//    return nativeLoader;
//  }
//
  public static String getJarParentFolder() {
    CodeSource src = FileManager.class.getProtectionDomain().getCodeSource();
    String jarParentPath = "--- not known ---";
    String RunningFromJar = "Y";
    if (src.getLocation() != null) {
      String jarPath = src.getLocation().getPath();
      if (!jarPath.endsWith(".jar")) RunningFromJar = "N";
      jarParentPath = FileManager.slashify((new File(jarPath)).getParent(), true);
    } else {
      log(-1, "Fatal Error 101: Not possible to access the jar files!");
      Sikulix.terminate(101);
    }
    return RunningFromJar + jarParentPath;
  }

  public static String getJarPath(Class cname) {
    CodeSource src = cname.getProtectionDomain().getCodeSource();
    if (src.getLocation() != null) {
      return new File(src.getLocation().getPath()).getAbsolutePath();
    }
    return "";
  }

  public static String getJarName(Class cname) {
		String jp = getJarPath(cname);
		if (jp.isEmpty()) {
			return "";
		}
		return new File(jp).getName();
  }

  public static boolean writeStringToFile(String text, String path) {
    return writeStringToFile(text, new File(path));
  }

  public static boolean writeStringToFile(String text, File fPath) {
    PrintStream out = null;
    try {
      out = new PrintStream(new FileOutputStream(fPath));
      out.print(text);
    } catch (Exception e) {
      log(-1,"writeStringToFile: did not work: " + fPath + "\n" + e.getMessage());
    }
    if (out != null) {
      out.close();
      return true;
    }
    return false;
  }

  public static String readFileToString(File fPath) {
    try {
      return doRreadFileToString(fPath);
    } catch (Exception ex) {
      return "";
    }
  }

  private static String doRreadFileToString(File fPath) throws IOException {
    StringBuilder result = new StringBuilder();
    BufferedReader reader = null;
    try {
      reader = new BufferedReader(new FileReader(fPath));
      char[] buf = new char[1024];
      int r = 0;
      while ((r = reader.read(buf)) != -1) {
        result.append(buf, 0, r);
      }
    } finally {
      if (reader != null) {
        reader.close();
      }
    }
    return result.toString();
  }

  public static boolean packJar(String folderName, String jarName, String prefix) {
    jarName = FileManager.slashify(jarName, false);
    if (!jarName.endsWith(".jar")) {
      jarName += ".jar";
    }
    folderName = FileManager.slashify(folderName, true);
    if (!(new File(folderName)).isDirectory()) {
      log(-1, "packJar: not a directory or does not exist: " + folderName);
      return false;
    }
    try {
      File dir = new File((new File(jarName)).getAbsolutePath()).getParentFile();
      if (dir != null) {
        if (!dir.exists()) {
          dir.mkdirs();
        }
      } else {
        throw new Exception("workdir is null");
      }
      log(lvl, "packJar: %s from %s in workDir %s", jarName, folderName, dir.getAbsolutePath());
      if (!folderName.startsWith("http://") && !folderName.startsWith("https://")) {
        folderName = "file://" + (new File(folderName)).getAbsolutePath();
      }
      URL src = new URL(folderName);
      JarOutputStream jout = new JarOutputStream(new FileOutputStream(jarName));
      addToJar(jout, new File(src.getFile()), prefix);
      jout.close();
    } catch (Exception ex) {
      log(-1, "packJar: " + ex.getMessage());
      return false;
    }
    log(lvl, "packJar: completed");
    return true;
  }

  public static boolean buildJar(String targetJar, String[] jars,
          String[] files, String[] prefixs, FileManager.JarFileFilter filter) {
    boolean logShort = false;
    if (targetJar.startsWith("#")) {
      logShort = true;
      targetJar = targetJar.substring(1);
      log(lvl, "buildJar: %s", new File(targetJar).getName());
    } else {
      log(lvl, "buildJar:\n%s", targetJar);
    }
    try {
      JarOutputStream jout = new JarOutputStream(new FileOutputStream(targetJar));
      ArrayList done = new ArrayList();
      for (int i = 0; i < jars.length; i++) {
        if (jars[i] == null) {
          continue;
        }
        if (logShort) {
          log(lvl, "buildJar: adding: %s", new File(jars[i]).getName());
        } else {
          log(lvl, "buildJar: adding:\n%s", jars[i]);
        }
        BufferedInputStream bin = new BufferedInputStream(new FileInputStream(jars[i]));
        ZipInputStream zin = new ZipInputStream(bin);
        for (ZipEntry zipentry = zin.getNextEntry(); zipentry != null; zipentry = zin.getNextEntry()) {
          if (filter == null || filter.accept(zipentry, jars[i])) {
            if (!done.contains(zipentry.getName())) {
              jout.putNextEntry(zipentry);
              if (!zipentry.isDirectory()) {
                bufferedWrite(zin, jout);
              }
              done.add(zipentry.getName());
              log(lvl+1, "adding: %s", zipentry.getName());
            }
          }
        }
        zin.close();
        bin.close();
      }
      if (files != null) {
        for (int i = 0; i < files.length; i++) {
					if (files[i] == null) {
						continue;
					}
          if (logShort) {
            log(lvl, "buildJar: adding %s at %s", new File(files[i]).getName(), prefixs[i]);
          } else {
            log(lvl, "buildJar: adding %s at %s", files[i], prefixs[i]);
          }
         addToJar(jout, new File(files[i]), prefixs[i]);
        }
      }
      jout.close();
    } catch (Exception ex) {
      log(-1, "buildJar: %s", ex);
      return false;
    }
    log(lvl, "buildJar: completed");
    return true;
  }

  /**
   * unpack a jar file to a folder
   * @param jarName absolute path to jar file
   * @param folderName absolute path to the target folder
   * @param del true if the folder should be deleted before unpack
   * @param strip true if the path should be stripped
   * @param filter to select specific content
   * @return true if success,  false otherwise
   */
  public static boolean unpackJar(String jarName, String folderName, boolean del, boolean strip,
          FileManager.JarFileFilter filter) {
    jarName = FileManager.slashify(jarName, false);
    if (!jarName.endsWith(".jar")) {
      jarName += ".jar";
    }
    if (!new File(jarName).isAbsolute()) {
      log(-1, "unpackJar: jar path not absolute");
      return false;
    }
    if (folderName == null) {
      folderName = jarName.substring(0, jarName.length() - 4);
    } else if (!new File(folderName).isAbsolute()) {
      log(-1, "unpackJar: folder path not absolute");
      return false;
    }
    folderName = FileManager.slashify(folderName, true);
    ZipInputStream in;
    BufferedOutputStream out;
    try {
      if (del) {
        FileManager.deleteFileOrFolder(folderName);
      }
      in = new ZipInputStream(new BufferedInputStream(new FileInputStream(jarName)));
      log(lvl, "unpackJar: %s to %s", jarName, folderName);
      boolean isExecutable;
      int n;
      File f;
      for (ZipEntry z = in.getNextEntry(); z != null; z = in.getNextEntry()) {
        if (filter == null || filter.accept(z, null)) {
          if (z.isDirectory()) {
            (new File(folderName, z.getName())).mkdirs();
          } else {
            n = z.getName().lastIndexOf(EXECUTABLE);
            if (n >= 0) {
              f = new File(folderName, z.getName().substring(0, n));
              isExecutable = true;
            } else {
              f = new File(folderName, z.getName());
              isExecutable = false;
            }
            if (strip) {
              f = new File(folderName, f.getName());
            } else {
              f.getParentFile().mkdirs();
            }
            out = new BufferedOutputStream(new FileOutputStream(f));
            bufferedWrite(in, out);
            out.close();
            if (isExecutable) {
              f.setExecutable(true, false);
            }
          }
        }
      }
      in.close();
    } catch (Exception ex) {
      log(-1, "unpackJar: " + ex.getMessage());
      return false;
    }
    log(lvl, "unpackJar: completed");
    return true;
  }

  private static void addToJar(JarOutputStream jar, File dir, String prefix) throws IOException {
    File[] content;
    prefix = prefix == null ? "" : prefix;
    if (dir.isDirectory()) {
      content  = dir.listFiles();
      for (int i = 0, l = content.length; i < l; ++i) {
        if (content[i].isDirectory()) {
          jar.putNextEntry(new ZipEntry(prefix + (prefix.equals("") ? "" : "/") + content[i].getName() + "/"));
          addToJar(jar, content[i], prefix + (prefix.equals("") ? "" : "/") + content[i].getName());
        } else {
          addToJarWriteFile(jar, content[i], prefix);
        }
      }
    } else {
      addToJarWriteFile(jar, dir, prefix);
    }
  }

  private static void addToJarWriteFile(JarOutputStream jar, File file, String prefix) throws IOException {
    if (file.getName().startsWith(".")) {
      return;
    }
    String suffix = "";
//TODO buildjar: suffix EXECUTABL
//    if (file.canExecute()) {
//      suffix = EXECUTABLE;
//    }
    jar.putNextEntry(new ZipEntry(prefix + (prefix.equals("") ? "" : "/") + file.getName() + suffix));
    FileInputStream in = new FileInputStream(file);
    bufferedWrite(in, jar);
    in.close();
  }

  public static File[] getScriptFile(File fScriptFolder) {
    if (fScriptFolder == null) {
      return null;
    }
    String scriptName;
    String scriptType = "";
    String fpUnzippedSkl = null;
    File[] content = null;

    if (fScriptFolder.getName().endsWith(".skl") || fScriptFolder.getName().endsWith(".zip")) {
      fpUnzippedSkl = FileManager.unzipSKL(fScriptFolder.getAbsolutePath());
      if (fpUnzippedSkl == null) {
        return null;
      }
      scriptType = "sikuli-zipped";
      fScriptFolder = new File(fpUnzippedSkl);
    }

    int pos = fScriptFolder.getName().lastIndexOf(".");
    if (pos == -1) {
      scriptName = fScriptFolder.getName();
      scriptType = "sikuli-plain";
    } else {
      scriptName = fScriptFolder.getName().substring(0, pos);
      scriptType = fScriptFolder.getName().substring(pos + 1);
    }

    boolean success = true;
    if (!fScriptFolder.exists()) {
      if ("sikuli-plain".equals(scriptType)) {
        fScriptFolder = new File(fScriptFolder.getAbsolutePath() + ".sikuli");
        if (!fScriptFolder.exists()) {
          success = false;
        }
      } else {
        success = false;
      }
    }
    if (!success) {
      log(-1, "Not a valid Sikuli script project:\n%s", fScriptFolder.getAbsolutePath());
      return null;
    }
    if (scriptType.startsWith("sikuli")) {
      content = fScriptFolder.listFiles(new FileFilterScript(scriptName + "."));
      if (content == null || content.length == 0) {
        log(-1, "Script project %s \n has no script file %s.xxx", fScriptFolder, scriptName);
        return null;
      }
    } else if ("jar".equals(scriptType)) {
      log(-1, "Sorry, script projects as jar-files are not yet supported;");
      //TODO try to load and run as extension
      return null; // until ready
    }
    return content;
  }

  private static class FileFilterScript implements FilenameFilter {
    private String _check;
    public FileFilterScript(String check) {
      _check = check;
    }
    @Override
    public boolean accept(File dir, String fileName) {
      return fileName.startsWith(_check);
    }
  }

  public static String unzipSKL(String fpSkl) {
    File fSkl = new File(fpSkl);
    if (!fSkl.exists()) {
      log(-1, "unzipSKL: file not found: %s", fpSkl);
    }
    String name = fSkl.getName();
    name = name.substring(0, name.lastIndexOf('.'));
    File fSikuliDir = FileManager.createTempDir(name + ".sikuli");
    if (null != fSikuliDir) {
      fSikuliDir.deleteOnExit();
      FileManager.unzip(fSkl, fSikuliDir);
    }
    if (null == fSikuliDir) {
      log(-1, "unzipSKL: not possible for:\n%s", fpSkl);
      return null;
    }
    return fSikuliDir.getAbsolutePath();
  }

  public interface JarFileFilter {
    public boolean accept(ZipEntry entry, String jarname);
  }

  public interface FileFilter {
    public boolean accept(File entry);
  }

  public static String extractResourceAsLines(String src) {
    String res = null;
    ClassLoader cl = FileManager.class.getClassLoader();
    InputStream isContent = cl.getResourceAsStream(src);
    if (isContent != null) {
      res = "";
      String line;
      try {
        BufferedReader cnt = new BufferedReader(new InputStreamReader(isContent));
        line = cnt.readLine();
        while (line != null) {
          res += line + "\n";
          line = cnt.readLine();
        }
        cnt.close();
      } catch (Exception ex) {
        log(-1, "extractResourceAsLines: %s\n%s", src, ex);
      }
    }
    return res;
  }

  public static boolean extractResource(String src, File tgt) {
    ClassLoader cl = FileManager.class.getClassLoader();
    InputStream isContent = cl.getResourceAsStream(src);
    if (isContent != null) {
      try {
        log(lvl + 1, "extractResource: %s to %s", src, tgt);
        tgt.getParentFile().mkdirs();
        OutputStream osTgt = new FileOutputStream(tgt);
        bufferedWrite(isContent, osTgt);
        osTgt.close();
      } catch (Exception ex) {
        log(-1, "extractResource:\n%s", src, ex);
        return false;
      }
    } else {
      return false;
    }
    return true;
  }

  private static synchronized void bufferedWrite(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[1024 * 512];
    int read;
    while (true) {
      read = in.read(buffer);
      if (read == -1) {
        break;
      }
      out.write(buffer, 0, read);
    }
    out.flush();
  }

	/**
	 * compares to path strings using java.io.File.equals()
	 * @param path1 string
	 * @param path2 string
	 * @return true if same file or folder
	 */
	public static boolean pathEquals(String path1, String path2) {
    File f1 = new File(path1);
    File f2 = new File(path2);
    boolean isEqual = f1.equals(f2);
    return isEqual;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy