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