1package org.robolectric.res;
2
3import com.google.common.annotations.VisibleForTesting;
4import java.io.BufferedInputStream;
5import java.io.File;
6import java.io.FileFilter;
7import java.io.FileInputStream;
8import java.io.IOException;
9import java.io.InputStream;
10import java.util.regex.Pattern;
11import javax.annotation.Nonnull;
12import org.robolectric.util.Util;
13
14public class FileFsFile implements FsFile {
15  @VisibleForTesting
16  static String FILE_SEPARATOR = File.separator;
17
18  private final File file;
19
20  FileFsFile(File file) {
21    this.file = file;
22  }
23
24  FileFsFile(String path) {
25    this.file = new File(path);
26  }
27
28  @Override
29  public boolean exists() {
30    return file.exists();
31  }
32
33  @Override
34  public boolean isDirectory() {
35    return file.isDirectory();
36  }
37
38  @Override
39  public boolean isFile() {
40    return file.isFile();
41  }
42
43  @Override
44  public FsFile[] listFiles() {
45    return asFsFiles(file.listFiles());
46  }
47
48  @Override
49  public FsFile[] listFiles(final Filter filter) {
50    return asFsFiles(file.listFiles(new FileFilter() {
51      @Override
52      public boolean accept(File pathname) {
53        return filter.accept(new FileFsFile(pathname));
54      }
55    }));
56  }
57
58  @Override
59  public String[] listFileNames() {
60    File[] files = file.listFiles();
61    if (files == null) return null;
62    String[] strings = new String[files.length];
63    for (int i = 0; i < files.length; i++) {
64      strings[i] = files[i].getName();
65    }
66    return strings;
67  }
68
69  @Override
70  public FsFile getParent() {
71    File parentFile = file.getParentFile();
72    return parentFile == null ? null : Fs.newFile(parentFile);
73  }
74
75  @Override
76  public String getName() {
77    return file.getName();
78  }
79
80  @Override
81  public InputStream getInputStream() throws IOException {
82    return new BufferedInputStream(new FileInputStream(file));
83  }
84
85  @Override
86  public byte[] getBytes() throws IOException {
87    return Util.readBytes(new FileInputStream(file));
88  }
89
90  @Override
91  public FsFile join(String... pathParts) {
92    File f = file;
93    for (String pathPart : pathParts) {
94      for (String part : pathPart.split(Pattern.quote(FILE_SEPARATOR))) {
95        if (!part.equals(".")) {
96          f = new File(f, part);
97        }
98      }
99    }
100
101    return Fs.newFile(f);
102  }
103
104  public File getFile() {
105    return file;
106  }
107
108  @Override
109  public String toString() {
110    return file.getPath();
111  }
112
113  @Override
114  public boolean equals(Object o) {
115    if (this == o) return true;
116    if (o == null || getClass() != o.getClass()) return false;
117
118    FileFsFile fsFile = (FileFsFile) o;
119
120    return file.equals(fsFile.file);
121  }
122
123  @Override
124  public int hashCode() {
125    return file.hashCode();
126  }
127
128  @Override
129  public String getBaseName() {
130    String name = getName();
131    int dotIndex = name.indexOf(".");
132    return dotIndex >= 0 ? name.substring(0, dotIndex) : name;
133  }
134
135  @Override
136  public String getPath() {
137    return file.getPath();
138  }
139
140  private FsFile[] asFsFiles(File[] files) {
141    if (files == null) return null;
142    FsFile[] fsFiles = new FsFile[files.length];
143    for (int i = 0; i < files.length; i++) {
144      fsFiles[i] = Fs.newFile(files[i]);
145    }
146    return fsFiles;
147  }
148
149  /**
150   * Construct an FileFsFile from a series of path components. Path components that are
151   * null or empty string will be ignored.
152   *
153   * @param paths Array of path components.
154   * @return New FileFsFile.
155   */
156  @Nonnull
157  public static FileFsFile from(String... paths) {
158    File file = null;
159    for (String path : paths) {
160      if (path != null && path.length() > 0) {
161        for (String part : path.split(Pattern.quote(FILE_SEPARATOR))) {
162          if (file != null && part.equals(".")) continue;
163          file = (file == null)
164              ? new File(part)
165              : new File(file, part);
166        }
167      }
168    }
169    return new FileFsFile(file);
170  }
171}
172