• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.res.android;
2 
3 import static org.robolectric.res.android.Asset.toIntExact;
4 import static org.robolectric.res.android.Errors.NAME_NOT_FOUND;
5 import static org.robolectric.res.android.Errors.NO_ERROR;
6 import static org.robolectric.res.android.Util.ALOGW;
7 import static org.robolectric.res.android.Util.isTruthy;
8 
9 import java.io.IOException;
10 import java.util.Enumeration;
11 import java.util.zip.ZipEntry;
12 import java.util.zip.ZipFile;
13 
14 public class ZipFileRO {
15 
16   static final int kCompressStored = 0;
17   static final int kCompressDeflated = 8;
18 
19   final ZipArchiveHandle mHandle;
20   final String mFileName;
21 
ZipFileRO(ZipArchiveHandle handle, String fileName)22   ZipFileRO(ZipArchiveHandle handle, String fileName) {
23     this.mHandle = handle;
24     this.mFileName = fileName;
25   }
26 
27   static class ZipEntryRO {
28         ZipEntry entry;
29     String name;
30     Object cookie;
31 
ZipEntryRO()32     ZipEntryRO() {
33     }
34 
35     //    ~ZipEntryRO() {
36     @Override
finalize()37     protected void finalize() {
38 //      EndIteration(cookie);
39     }
40 
41 //    private:
42 //    ZipEntryRO(final ZipEntryRO& other);
43 //    ZipEntryRO& operator=(final ZipEntryRO& other);
44   };
45 
46 //  ~ZipFileRO() {
47   @Override
finalize()48   protected void finalize() {
49     CloseArchive(mHandle);
50 //    free(mFileName);
51   }
52 
OpenArchive(String zipFileName, Ref<ZipArchiveHandle> mHandle)53   static int OpenArchive(String zipFileName, Ref<ZipArchiveHandle> mHandle) {
54     try {
55       mHandle.set(new ZipArchiveHandle(new ZipFile(zipFileName)));
56       return NO_ERROR;
57     } catch (IOException e) {
58       return NAME_NOT_FOUND;
59     }
60   }
61 
CloseArchive(ZipArchiveHandle mHandle)62   private static void CloseArchive(ZipArchiveHandle mHandle) {
63     throw new UnsupportedOperationException();
64   }
65 
ErrorCodeString(int error)66   private static String ErrorCodeString(int error) {
67     return "error " + error;
68   }
69 
FindEntry(ZipArchiveHandle mHandle, String name, Ref<ZipEntry> zipEntryRef)70   static int FindEntry(ZipArchiveHandle mHandle, String name, Ref<ZipEntry> zipEntryRef) {
71     ZipEntry entry = mHandle.zipFile.getEntry(name);
72     zipEntryRef.set(entry);
73     if (entry == null) {
74       return NAME_NOT_FOUND;
75     }
76     return NO_ERROR;
77   }
78 
79   /*
80  * Open the specified file read-only.  We memory-map the entire thing and
81  * close the file before returning.
82  */
83 /* static */
open(final String zipFileName)84   static ZipFileRO open(final String zipFileName)
85   {
86     final Ref<ZipArchiveHandle> handle = new Ref<>(null);
87     final int error = OpenArchive(zipFileName, handle);
88     if (isTruthy(error)) {
89       ALOGW("Error opening archive %s: %s", zipFileName, ErrorCodeString(error));
90       CloseArchive(handle.get());
91       return null;
92     }
93 
94     return new ZipFileRO(handle.get(), zipFileName);
95   }
96 
97   // /* static */ ZipFileRO* ZipFileRO::openFd(int fd, String debugFileName,
98   //     boolean assume_ownership)
99   // {
100   //   ZipArchiveHandle handle;
101   //   int error = OpenArchiveFd(fd, debugFileName, &handle, assume_ownership);
102   //   if (error) {
103   //     ALOGW("Error opening archive fd %d %s: %s", fd, debugFileName, ErrorCodeString(error));
104   //     CloseArchive(handle);
105   //     return NULL;
106   //   }
107   //
108   //   return new ZipFileRO(handle, strdup(debugFileName));
109   // }
110 
findEntryByName(final String entryName)111   org.robolectric.res.android.ZipFileRO.ZipEntryRO findEntryByName(final String entryName)
112   {
113     ZipEntryRO data = new ZipEntryRO();
114 
115     data.name = String(entryName);
116 
117     final Ref<ZipEntry> zipEntryRef = new Ref<>(data.entry);
118     final int error = FindEntry(mHandle, data.name, zipEntryRef);
119     if (isTruthy(error)) {
120       return null;
121     }
122 
123     data.entry = zipEntryRef.get();
124     return data;
125   }
126 
127   /*
128    * Get the useful fields from the zip entry.
129    *
130    * Returns "false" if the offsets to the fields or the contents of the fields
131    * appear to be bogus.
132    */
getEntryInfo(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, Ref<Short> pMethod, final Ref<Long> pUncompLen, Ref<Long> pCompLen, Ref<Long> pOffset, final Ref<Long> pModWhen, Ref<Long> pCrc32)133   boolean getEntryInfo(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, Ref<Short> pMethod,
134       final Ref<Long> pUncompLen, Ref<Long> pCompLen, Ref<Long> pOffset,
135       final Ref<Long> pModWhen, Ref<Long> pCrc32)
136   {
137     final ZipEntryRO zipEntry = /*reinterpret_cast<ZipEntryRO*>*/(entry);
138     final ZipEntry ze = zipEntry.entry;
139 
140     if (pMethod != null) {
141       pMethod.set((short) ze.getMethod());
142     }
143     if (pUncompLen != null) {
144         pUncompLen.set(ze.getSize()); // uncompressed_length
145     }
146     if (pCompLen != null) {
147         pCompLen.set(ze.getCompressedSize());
148     }
149     if (pOffset != null) {
150       throw new UnsupportedOperationException("Figure out offset");
151       //        pOffset = ze.offset;
152     }
153     if (pModWhen != null) {
154         // todo pModWhen.set(ze.getLastModifiedTime().toMillis());
155     }
156     if (pCrc32 != null) {
157       pCrc32.set(ze.getCrc());
158     }
159 
160     return true;
161   }
162 
startIteration(Ref<Enumeration<? extends ZipEntry>> cookie)163   boolean startIteration(Ref<Enumeration<? extends ZipEntry>> cookie) {
164     return startIteration(cookie, null, null);
165   }
166 
startIteration( Ref<Enumeration<? extends ZipEntry>> cookie, final String prefix, final String suffix)167   boolean startIteration(/* void** */ Ref<Enumeration<? extends ZipEntry>> cookie, final String prefix, final String suffix)
168   {
169     cookie.set(this.mHandle.zipFile.entries());
170 //    ZipEntryRO* ze = new ZipEntryRO;
171 //    String pe(prefix ? prefix : "");
172 //    String se(suffix ? suffix : "");
173 //    int error = StartIteration(mHandle, &(ze.cookie),
174 //    prefix ? &pe : null,
175 //      suffix ? &se : null);
176 //    if (error) {
177 //      ALOGW("Could not start iteration over %s: %s", mFileName, ErrorCodeString(error));
178 //      delete ze;
179 //      return false;
180 //    }
181 //
182 //    *cookie = ze;
183     return true;
184   }
185 
nextEntry( Enumeration<? extends ZipEntry> cookie)186   org.robolectric.res.android.ZipFileRO.ZipEntryRO nextEntry(/*void* */ Enumeration<? extends ZipEntry> cookie)
187   {
188     if (!cookie.hasMoreElements()) {
189       return null;
190     }
191     ZipEntryRO zipEntryRO = new ZipEntryRO();
192     zipEntryRO.entry = cookie.nextElement();
193     return zipEntryRO;
194 //    ZipEntryRO ze = /*reinterpret_cast<ZipEntryRO*>*/(ZipEntryRO) cookie;
195 //    int error = Next(ze.cookie, &(ze.entry), &(ze.name));
196 //    if (error) {
197 //      if (error != -1) {
198 //        ALOGW("Error iteration over %s: %s", mFileName, ErrorCodeString(error));
199 //      }
200 //      return null;
201 //    }
202 //
203 //    return &(ze.entry);
204   }
205 
endIteration( Object cookie)206   void endIteration(/*void**/ Object cookie)
207   {
208 //    delete reinterpret_cast<ZipEntryRO*>(cookie);
209   }
210 
releaseEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry)211   void releaseEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry)
212   {
213 //    delete reinterpret_cast<ZipEntryRO*>(entry);
214   }
215 
216   /*
217    * Copy the entry's filename to the buffer.
218    */
getEntryFileName(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, Ref<String> buffer)219   int getEntryFileName(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, Ref<String> buffer)
220   {
221     buffer.set(entry.entry.getName());
222 
223 //    final ZipEntryRO* zipEntry = reinterpret_cast<ZipEntryRO*>(entry);
224 //    final uint16_t requiredSize = zipEntry.name.name_length + 1;
225 //
226 //    if (bufLen < requiredSize) {
227 //      ALOGW("Buffer too short, requires %d bytes for entry name", requiredSize);
228 //      return requiredSize;
229 //    }
230 //
231 //    memcpy(buffer, zipEntry.name.name, requiredSize - 1);
232 //    buffer[requiredSize - 1] = '\0';
233 //
234     return 0;
235   }
236 
237 /*
238  * Create a new FileMap object that spans the data in "entry".
239  */
ZipFileRO(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry)240   /*FileMap*/ ZipFileRO(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry)
241   {
242     throw new UnsupportedOperationException("Implememnt me");
243 
244 //    final ZipEntryRO *zipEntry = reinterpret_cast<ZipEntryRO*>(entry);
245 //    final ZipEntry& ze = zipEntry.entry;
246 //    int fd = GetFileDescriptor(mHandle);
247 //    size_t actualLen = 0;
248 //
249 //    if (ze.method == kCompressStored) {
250 //      actualLen = ze.uncompressed_length;
251 //    } else {
252 //      actualLen = ze.compressed_length;
253 //    }
254 //
255 //    FileMap* newMap = new FileMap();
256 //    if (!newMap.create(mFileName, fd, ze.offset, actualLen, true)) {
257 //      delete newMap;
258 //      return null;
259 //    }
260 //
261 //    return newMap;
262   }
263 
264   /*
265  * Create a new FileMap object that spans the data in "entry".
266  */
createEntryFileMap(ZipEntryRO entry)267   FileMap createEntryFileMap(ZipEntryRO entry)
268   {
269     // final _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry);
270     // const ZipEntry& ze = zipEntry->entry;
271     ZipEntry ze = entry.entry;
272     // int fd = GetFileDescriptor(mHandle);
273     int fd = -1;
274     int actualLen = 0;
275 
276     if (ze.getMethod() == kCompressStored) {
277       actualLen = toIntExact(ze.getSize());
278     } else {
279       actualLen = toIntExact(ze.getCompressedSize());
280     }
281 
282     FileMap newMap = new FileMap();
283     if (!newMap.createFromZip(mFileName, mHandle.zipFile, entry.entry, actualLen, true)) {
284       // delete newMap;
285       return null;
286     }
287 
288     return newMap;
289   }
290 
291   /*
292    * Uncompress an entry, in its entirety, into the provided output buffer.
293    *
294    * This doesn't verify the data's CRC, which might be useful for
295    * uncompressed data.  The caller should be able to manage it.
296    */
uncompressEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, Object buffer, int size)297   boolean uncompressEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, Object buffer, int size)
298   {
299     throw new UnsupportedOperationException("Implememnt me");
300 //    ZipEntryRO *zipEntry = reinterpret_cast<ZipEntryRO*>(entry);
301 //    final int error = ExtractToMemory(mHandle, &(zipEntry.entry),
302 //    (uint8_t*) buffer, size);
303 //    if (error) {
304 //      ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error));
305 //      return false;
306 //    }
307 //
308 //    return true;
309   }
310 
311   /*
312    * Uncompress an entry, in its entirety, to an open file descriptor.
313    *
314    * This doesn't verify the data's CRC, but probably should.
315    */
uncompressEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, int fd)316   boolean uncompressEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, int fd)
317   {
318     throw new UnsupportedOperationException("Implememnt me");
319 //    ZipEntryRO *zipEntry = reinterpret_cast<ZipEntryRO*>(entry);
320 //    final int error = ExtractEntryToFile(mHandle, &(zipEntry.entry), fd);
321 //    if (error) {
322 //      ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error));
323 //      return false;
324 //    }
325 //
326 //    return true;
327   }
328 
String(String string)329   static String String(String string) {
330     return string;
331   }
332 }
333