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

org.robolectric.res.Fs Maven / Gradle / Ivy

There is a newer version: 3.4-rc2
Show newest version
package org.robolectric.res;

import org.robolectric.util.Join;
import org.robolectric.util.Util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import static java.util.Arrays.asList;

abstract public class Fs {
  public static Fs fromJar(URL url) {
    return new JarFs(new File(fixFileURL(url).getPath()));
  }
  
  private static URI fixFileURL(URL u) {
    if (!"file".equals(u.getProtocol())) {
      throw new IllegalArgumentException();
    }
    return new File(u.getFile()).toURI();
  }

  public static FsFile fileFromPath(String urlString) {
    if (urlString.startsWith("jar:")) {
      String[] parts = urlString.replaceFirst("jar:", "").split("!");
      Fs fs = new JarFs(new File(parts[0]));
      return fs.join(parts[1].substring(1));
    } else {
      return new FileFsFile(new File(urlString));
    }
  }

  public static FsFile newFile(File file) {
    return new FileFsFile(file);
  }

  public static FsFile currentDirectory() {
    return newFile(new File("."));
  }

  static class JarFs extends Fs {
    private static final Map> CACHE =
        new LinkedHashMap>() {
          @Override
          protected boolean removeEldestEntry(Map.Entry> fileNavigableMapEntry) {
            return size() > 10;
          }
        };

    private final JarFile jarFile;
    private final NavigableMap jarEntryMap;

    public JarFs(File file) {
      try {
        jarFile = new JarFile(file);
      } catch (IOException e) {
        throw new RuntimeException(e);
      }

      NavigableMap cachedMap;
      synchronized (CACHE) {
        cachedMap = CACHE.get(file.getAbsoluteFile());
      }

      if (cachedMap == null) {
        cachedMap = new TreeMap<>();
        Enumeration entries = jarFile.entries();
        while (entries.hasMoreElements()) {
          JarEntry jarEntry = entries.nextElement();
          cachedMap.put(jarEntry.getName(), jarEntry);
        }
        synchronized (CACHE) {
          CACHE.put(file.getAbsoluteFile(), cachedMap);
        }
      }

      jarEntryMap = cachedMap;
    }

    @Override public FsFile join(String folderBaseName) {
      return new JarFsFile(folderBaseName);
    }

    class JarFsFile implements FsFile {
      private final String path;

      public JarFsFile(String path) {
        this.path = path;
      }

      @Override public boolean exists() {
        return isFile() || isDirectory();
      }

      @Override public boolean isDirectory() {
        return jarEntryMap.containsKey(path + "/");
      }

      @Override public boolean isFile() {
        return jarEntryMap.containsKey(path);
      }

      @Override public FsFile[] listFiles() {
        if (!isDirectory()) return null;
        NavigableSet strings = jarEntryMap.navigableKeySet().subSet(path + "/", false, path + "0", false);
        List fsFiles = new ArrayList<>();
        int startOfFilename = path.length() + 2;
        for (String string : strings) {
          int nextSlash = string.indexOf('/', startOfFilename);
          if (nextSlash == string.length() - 1) {
            // directory entry
            fsFiles.add(new JarFsFile(string.substring(0, string.length() - 1)));
          } else if (nextSlash == -1) {
            // file entry
            fsFiles.add(new JarFsFile(string));
          }
        }
        return fsFiles.toArray(new FsFile[fsFiles.size()]);
      }

      @Override public FsFile[] listFiles(Filter filter) {
        List filteredFsFiles = new ArrayList<>();
        for (FsFile fsFile : listFiles()) {
          if (filter.accept(fsFile)) {
            filteredFsFiles.add(fsFile);
          }
        }
        return filteredFsFiles.toArray(new FsFile[filteredFsFiles.size()]);
      }

      @Override public String[] listFileNames() {
        List fileNames = new ArrayList<>();
        for (FsFile fsFile : listFiles()) {
          fileNames.add(fsFile.getName());
        }
        return fileNames.toArray(new String[fileNames.size()]);
      }

      @Override public FsFile getParent() {
        int index = path.lastIndexOf('/');
        String parent = index != -1 ? path.substring(0, index) : "";
        return new JarFsFile(parent);
      }

      @Override public String getName() {
        int index = path.lastIndexOf('/');
        return index != -1 ? path.substring(index + 1, path.length()) : path;
      }

      @Override public InputStream getInputStream() throws IOException {
        return new BufferedInputStream(jarFile.getInputStream(jarEntryMap.get(path)));
      }

      @Override public byte[] getBytes() throws IOException {
        return Util.readBytes(jarFile.getInputStream(jarEntryMap.get(path)));
      }

      @Override public FsFile join(String... pathParts) {
        return new JarFsFile(path + "/" + Join.join("/", asList(pathParts)));
      }

      @Override public String getBaseName() {
        String name = getName();
        int dotIndex = name.indexOf(".");
        return dotIndex >= 0 ? name.substring(0, dotIndex) : name;
      }

      @Override public String getPath() {
        return "jar:" + getJarFileName() + "!/" + path;
      }

      @Override
      public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        JarFsFile jarFsFile = (JarFsFile) o;

        if (!getJarFileName().equals(jarFsFile.getJarFileName())) return false;
        if (!path.equals(jarFsFile.path)) return false;

        return true;
      }

      private String getJarFileName() {
        return jarFile.getName();
      }

      @Override
      public int hashCode() {
        return getJarFileName().hashCode() * 31 + path.hashCode();
      }

      @Override public String toString() {
        return getPath();
      }
    }
  }

  abstract public FsFile join(String folderBaseName);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy