1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.signature.cts;
17 
18 import java.io.File;
19 import java.io.FileInputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.net.URL;
23 import java.util.Objects;
24 import java.util.zip.ZipEntry;
25 import java.util.zip.ZipFile;
26 
27 /**
28  * Workaround for the lack of a zip file system provider on Android.
29  */
30 public abstract class VirtualPath {
31 
32     /**
33      * Get a path to the local file system.
34      */
get(String path)35     public static LocalFilePath get(String path) {
36         return new LocalFilePath(path);
37     }
38 
39     /**
40      * Get a path to an entry in a zip file, i.e. a zip file system.
41      */
get(ZipFile zip, ZipEntry entry)42     public static ZipEntryPath get(ZipFile zip, ZipEntry entry) {
43         return new ZipEntryPath(zip, entry);
44     }
45 
46     /**
47      * Get a path to a resource in a ClassLoader.
48      *
49      * @param classLoader the ClassLoader containing the resource.
50      * @param resourceName the name of the resource, must not start with a /.
51      */
get(ClassLoader classLoader, String resourceName)52     public static ResourcePath get(ClassLoader classLoader, String resourceName)
53             throws IOException {
54         return new ResourcePath(classLoader, resourceName);
55     }
56 
newInputStream()57     public abstract InputStream newInputStream() throws IOException;
58 
59     /**
60      * Override as abstract to force sub-classes to implement it.
61      */
62     @Override
hashCode()63     public abstract int hashCode();
64 
65     /**
66      * Override as abstract to force sub-classes to implement it.
67      */
68     @Override
equals(Object obj)69     public abstract boolean equals(Object obj);
70 
71     /**
72      * Override as abstract to force sub-classes to implement it.
73      */
74     @Override
toString()75     public abstract String toString();
76 
77     public static class LocalFilePath extends VirtualPath {
78         private final String path;
79 
LocalFilePath(String path)80         LocalFilePath(String path) {
81             this.path = path;
82         }
83 
toFile()84         public File toFile() {
85             return new File(path);
86         }
87 
resolve(String relative)88         public LocalFilePath resolve(String relative) {
89             return new LocalFilePath(path + "/" + relative);
90         }
91 
92         @Override
newInputStream()93         public InputStream newInputStream() throws IOException {
94             return new FileInputStream(path);
95         }
96 
97         @Override
equals(Object o)98         public boolean equals(Object o) {
99             if (this == o) {
100                 return true;
101             }
102             if (o == null || getClass() != o.getClass()) {
103                 return false;
104             }
105             LocalFilePath that = (LocalFilePath) o;
106             return path.equals(that.path);
107         }
108 
109         @Override
hashCode()110         public int hashCode() {
111             return Objects.hash(path);
112         }
113 
114         @Override
toString()115         public String toString() {
116             return path;
117         }
118     }
119 
120     private static class ZipEntryPath extends VirtualPath {
121 
122         private final ZipFile zip;
123 
124         private final ZipEntry entry;
125 
ZipEntryPath(ZipFile zip, ZipEntry entry)126         private ZipEntryPath(ZipFile zip, ZipEntry entry) {
127             this.zip = zip;
128             this.entry = entry;
129         }
130 
131         @Override
newInputStream()132         public InputStream newInputStream() throws IOException {
133             return zip.getInputStream(entry);
134         }
135 
136         @Override
equals(Object o)137         public boolean equals(Object o) {
138             if (this == o) {
139                 return true;
140             }
141             if (o == null || getClass() != o.getClass()) {
142                 return false;
143             }
144             ZipEntryPath that = (ZipEntryPath) o;
145             return zip.getName().equals(that.zip.getName())
146                     && entry.getName().equals(that.entry.getName());
147         }
148 
149         @Override
hashCode()150         public int hashCode() {
151             return Objects.hash(zip.getName(), entry.getName());
152         }
153 
154         @Override
toString()155         public String toString() {
156             return "zip:file:" + zip.getName() + "!/" + entry.getName();
157         }
158     }
159 
160     public static class ResourcePath extends VirtualPath {
161         private final URL url;
162 
ResourcePath(ClassLoader classLoader, String path)163         ResourcePath(ClassLoader classLoader, String path) throws IOException {
164             this.url = classLoader.getResource(path);
165             if (url == null) {
166                 throw new IOException("Could not find resource '" + path + "' in " + classLoader);
167             }
168         }
169 
170         @Override
newInputStream()171         public InputStream newInputStream() throws IOException {
172             return url.openStream();
173         }
174 
175         @Override
equals(Object o)176         public boolean equals(Object o) {
177             if (this == o) {
178                 return true;
179             }
180             if (o == null || getClass() != o.getClass()) {
181                 return false;
182             }
183             ResourcePath that = (ResourcePath) o;
184             return url.equals(that.url);
185         }
186 
187         @Override
hashCode()188         public int hashCode() {
189             return Objects.hash(url);
190         }
191 
192         @Override
toString()193         public String toString() {
194             return url.toExternalForm();
195         }
196     }
197 }
198