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

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

There is a newer version: 2.0.5
Show newest version
/*
 * Copyright (c) 2010-2020, sikuli.org, sikulix.com - MIT license
 */
package org.sikuli.basics;

import org.sikuli.script.support.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.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.*;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
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";

  private 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 InetAddress getProxyAddress(String arg) {
    try {
      return InetAddress.getByName(arg);
    } catch (UnknownHostException ex) {
      return null;
    }
  }

  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 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.get();
      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) {
    boolean silent = false;
    if (src.startsWith("#")) {
      silent = true;
      src = src.substring(1);
    }
    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, silent);
  }

  public static String downloadURLtoString(URL uSrc) {
    return downloadURLtoString(uSrc, false);
  }

  public static String downloadURLtoString(URL uSrc, boolean silent) {
    String content = "";
    InputStream reader = null;
    if (!silent) {
      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) {
      if (!silent) {
        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 fPrefix = "sikulitemp-";
    String fSuffix = "." + suffix;
    File fpath = new File(RunTime.get().fpBaseTempPath);
    if (path != null) {
      fpath = new File(path);
    }
    try {
      fpath.mkdirs();
      File temp = File.createTempFile(fPrefix, fSuffix, fpath);
      temp.deleteOnExit();
      return temp;
    } catch (IOException ex) {
      log(-1, "createTempFile: IOException: %s\n%s", ex.getMessage(),
          fpath + File.separator + fPrefix + "12....56" + fSuffix);
      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);
    if (null == path) {
      return null;
    }
    File fImage = new File(path, name);
    String formatName = "png";
    if (name == null) {
      fImage = new File(path, String.format("noname-%d.png", name, new Date().getTime()));
    } else if (name.startsWith("#")) {
      fImage = new File(path, String.format("%s-%d.png", name.substring(1), new Date().getTime()));
    } else if (!name.isEmpty()) {
      if(!name.contains(".")) {
        fImage = new File(path, name + ".png");
      } else {
        formatName = name.substring(name.lastIndexOf(".") + 1);
      }
    }
    try {
      ImageIO.write(img, formatName, fImage);
      log(3, "saveImage: %s", fImage);
    } catch (Exception ex) {
      log(-1, "saveTimedImage: did not work: %s (%s)", fImage, ex.getMessage());
      return null;
    }
    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)) {
        try {
          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();
        } catch (IOException ex) {
          log(-1, "xcopy: %s to: %s (%s)", fSrc, fDest, ex.getMessage());
          throw new IOException(ex.getMessage(), ex.getCause());
        }
      }
    }
  }

  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('-');
    String postfix = filename.substring(pDot);
    String name;
    String versionText = "1";
    if (pDash >= 0) {
      name = filename.substring(0, pDash);
      versionText = filename.substring(pDash + 1, pDot);
      try {
        versionText = "" + (Integer.parseInt(versionText) + 1);
      } catch (NumberFormatException e) {
        versionText = versionText + "-1";
      }
    } else {
      name = filename.substring(0, pDot);
    }
    return name + "-" + versionText + 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(-1, "slashify: filename might not be useable: %s", 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);
      }
      log(lvl, "slashify: file: %s", path);
      return path;
    } else {
      log(lvl, "slashify: file: null");
      return "";
    }
  }

  public static String normalize(String path) {
    String pathNormalized = path;
    if (path != null) {
      if (path.contains("%")) {
        try {
          pathNormalized = URLDecoder.decode(path, "UTF-8");
        } catch (Exception ex) {
        }
      }
      if (!new File(pathNormalized).isAbsolute() && pathNormalized.startsWith("\\")) {
        pathNormalized = new File(pathNormalized).getAbsoluteFile().getPath();
      }
    }
    return pathNormalized;
  }

  public static String normalizeAbsolute(String filename) {
    filename = normalize(filename);
    String jarSuffix = "";
    int nJarSuffix;
    if (0 < (nJarSuffix = filename.indexOf(".jar!"))) {
      jarSuffix = filename.substring(nJarSuffix + 4);
      filename = filename.substring(0, nJarSuffix + 4);
    }
    File aFile = new File(filename);
    try {
      aFile = aFile.getCanonicalFile();
    } catch (Exception ex) {
    }
    log(lvl, "normalizeAbsolute: file: %s", aFile);
    return aFile.getPath() + jarSuffix;
  }

  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 makeJarURL(File fJar) {
    return makeURL(fJar.getAbsolutePath(), "jar");
  }

  public static URL makeURL(String fName, String type) {
    try {
      if ("file".equals(type)) {
        fName = normalizeAbsolute(fName);
        if (!fName.startsWith("/")) {
          fName = "/" + fName;
        }
      }
      if ("jar".equals(type)) {
        if (!fName.contains("!/")) {
          fName += "!/";
        }
        fName = fName.startsWith("file:") ? "jar:" + fName : "jar:file:" + fName;
        URL url = new URL(fName);
        return url;
      } 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 String getAddress(String arg) {
    try {
      if (arg == null) {
        return InetAddress.getLocalHost().getHostAddress();
      }
      return InetAddress.getByName(arg).getHostAddress();
    } 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 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), false, "UTF-8");
      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 String makeScriptjar(List options) {
    File fSikulixTemp = new File(RunTime.get().fSikulixStore, "SikulixTemp");
    FileManager.resetFolder(fSikulixTemp);
    String target = doMakeScriptjar(options, fSikulixTemp);
    deleteFileOrFolder(fSikulixTemp);
    return target;
  }

  private static String doMakeScriptjar(List options, File fSikulixTemp) {
    boolean makingScriptjarPlain = false;
    RunTime runTime = RunTime.get();
//    File fSikulixapi = new File(runTime.fSikulixDownloadsGeneric, runTime.sSikulixapi);
//    File fSikulixjython = new File(runTime.fSikulixDownloadsGeneric, new File(runTime.SikuliJythonMaven).getName());
    if (options.size() > 0 && "plain".equals(options.get(0))) {
      makingScriptjarPlain = true;
      options.remove(0);
    } else {
//      if (!fSikulixapi.exists()) {
//        log(-1, "makingScriptJar: sikulixapi.jar missing. run setup first!");
//        return null;
//      }
//      if (!fSikulixjython.exists()) {
//        log(-1, "makingScriptJar: jython jar missing. run setup first!");
//        return null;
//      }
    }
    File scriptFile = null;
    File scriptFolder = null;
    File scriptFolderSikuli = null;
    String scriptName = null;
    String[] fileList = new String[]{null, null, null};
    String[] preList = new String[]{null, null, null};
    if (options.size() > 0) {
      scriptFolder = new File(options.get(0));
      if (!scriptFolder.exists()) {
        scriptFolderSikuli = new File(scriptFolder.getAbsolutePath() + ".sikuli");
        if (!scriptFolderSikuli.exists()) {
          log(-1, "makingScriptJar: script folder invalid: " + scriptFolder.getAbsolutePath());
          return null;
        }
      } else {
        if (scriptFolder.getAbsolutePath().endsWith(".sikuli")) {
          scriptFolderSikuli = scriptFolder;
        } else {
          scriptFile = new File(scriptFolder, "__run__.py");
          if (!scriptFile.exists()) {
            log(-1, "makingScriptJar: script file missing: " + scriptFile.getAbsolutePath());
            return null;
          }
        }
      }
    } else {
      log(-1, "makingScriptJar: no script file given");
      return null;
    }

    String fpScriptJar = "";
    File fScriptSource = new File(fSikulixTemp, "scriptSource");
    File fScriptCompiled = new File(fSikulixTemp, "scriptCompiled");
    File fWorkdir = scriptFolder.getParentFile();
    FileFilter skipCompiled = new FileManager.FileFilter() {
      @Override
      public boolean accept(File entry) {
        if (entry.getName().contains("$py.class")) {
          return false;
        }
        return true;
      }
    };
    if (null != scriptFolderSikuli) {
      log(lvl, "makingScriptJar: compiling sikuli script: %s", scriptFolderSikuli);
      fWorkdir = scriptFolderSikuli.getParentFile();
      scriptName = scriptFolder.getName().replace(".sikuli", "");
      fpScriptJar = scriptName + "_sikuli.jar";
      scriptFile = new File(scriptFolderSikuli, scriptName + ".py");
      if (!scriptFile.exists()) {
        log(-1, "makingScriptJar: script folder invalid: " + scriptFolderSikuli.getAbsolutePath());
        return null;
      }
      xcopy(scriptFolderSikuli, fScriptSource, skipCompiled);
      String script = "";
      String prolog = "import org.sikuli.script.SikulixForJython\n" +
          "from sikuli import *\n" +
          "Debug.on(3)\n" +
          "for e in sys.path:\n" +
          "    print e\n" +
          "    if e.endswith(\".jar\"):\n" +
          "        jar = e\n" +
          "        break\n" +
          "ImagePath.addJar(jar, \"\")\n" +
          "import " + scriptName + "\n";
      FileManager.writeStringToFile(prolog + script, new File(fScriptSource, "__run__.py"));
      FileManager.writeStringToFile(prolog + script, new File(fScriptSource, "__main__.py"));
      script = FileManager.readFileToString(new File(fScriptSource, scriptName + ".py"));
      prolog = "from sikuli import *\n";
      FileManager.writeStringToFile(prolog + script, new File(fScriptSource, scriptName + ".py"));
    } else {
      log(lvl, "makingScriptJar: compiling plain script: %s", scriptFolder);
      xcopy(scriptFolder, fScriptSource, skipCompiled);
    }

    Sikulix.compileJythonFolder(fScriptSource.getAbsolutePath(), fScriptCompiled.getAbsolutePath());
    FileManager.xcopy(fScriptCompiled, fSikulixTemp);
    FileManager.deleteFileOrFolder(fScriptSource);
    FileManager.deleteFileOrFolder(fScriptCompiled);
    fileList[0] = fSikulixTemp.getAbsolutePath();

    String[] jarsList = new String[]{null, null};
    if (!makingScriptjarPlain) {
//      log(lvl, "makingScriptJar: adding sikulixapi and jython - takes some time", fpScriptJar);
//      jarsList[0] = fSikulixjython.getAbsolutePath();
//      jarsList[1] = fSikulixapi.getAbsolutePath();
    } else {
//      File fJarRunner = new File(runTime.fSikulixExtensions, "archiv");
//      fJarRunner = new File(fJarRunner, "JarRunner.class");
//      File fJarRunnerDir = new File(fSikulixTemp, "org/python/util");
//      fJarRunnerDir.mkdirs();
//      FileManager.xcopy(fJarRunner, fJarRunnerDir);
    }

//    String manifest = "Manifest-Version: 1.0\nMain-Class: org.python.util.JarRunner\n";
//    File fMetaInf = new File(fSikulixTemp, "META-INF");
//    fMetaInf.mkdir();
//    FileManager.writeStringToFile(manifest, new File(fMetaInf, "MANIFEST.MF"));

    String targetJar = (new File(fWorkdir, fpScriptJar)).getAbsolutePath();
    if (!buildJar(targetJar, jarsList, fileList, preList, new FileManager.JarFileFilter() {
      @Override
      public boolean accept(ZipEntry entry, String jarname) {
        if (entry.getName().startsWith("META-INF")) {
          return false;
        }
        return true;
      }
    })) {
      log(-1, "makingScriptJar: problems building jar - for details see logfile");
      return null;
    }
    log(lvl, "makingScriptJar: ended successfully: %s", targetJar);
    return targetJar;
  }

  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 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();
  }

  static class JarFileFilter {
    boolean accept(ZipEntry entry, String jarname){return true;}
  }

  public static class FileFilter {
    public boolean accept(File entry){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();
  }

  public static boolean pathEquals(String path1, String path2) {
    return new File(path1).equals(new File(path2));
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy