• 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 
37     //    ~ZipEntryRO() {
38     @Override
finalize()39     protected void finalize() {
40 //      EndIteration(cookie);
41     }
42 
43 //    private:
44 //    ZipEntryRO(final ZipEntryRO& other);
45 //    ZipEntryRO& operator=(final ZipEntryRO& other);
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   {
93     final Ref<ZipArchiveHandle> handle = new Ref<>(null);
94     final int error = OpenArchive(zipFileName, handle);
95     if (isTruthy(error)) {
96       ALOGW("Error opening archive %s: %s", zipFileName, ErrorCodeString(error));
97       CloseArchive();
98       return null;
99     }
100 
101     return new ZipFileRO(handle.get(), zipFileName);
102   }
103 
104   // /* static */ ZipFileRO* ZipFileRO::openFd(int fd, String debugFileName,
105   //     boolean assume_ownership)
106   // {
107   //   ZipArchiveHandle handle;
108   //   int error = OpenArchiveFd(fd, debugFileName, &handle, assume_ownership);
109   //   if (error) {
110   //     ALOGW("Error opening archive fd %d %s: %s", fd, debugFileName, ErrorCodeString(error));
111   //     CloseArchive(handle);
112   //     return NULL;
113   //   }
114   //
115   //   return new ZipFileRO(handle, strdup(debugFileName));
116   // }
117 
findEntryByName(final String entryName)118   org.robolectric.res.android.ZipFileRO.ZipEntryRO findEntryByName(final String entryName)
119   {
120     ZipEntryRO data = new ZipEntryRO();
121     data.name = String(entryName);
122 
123     if (mHandle.dataOffsets.get(entryName) == null) {
124       return null;
125     }
126     data.dataOffset = mHandle.dataOffsets.get(entryName);
127 
128     final Ref<ZipEntry> zipEntryRef = new Ref<>(data.entry);
129     final int error = FindEntry(mHandle, data.name, zipEntryRef);
130     if (isTruthy(error)) {
131       return null;
132     }
133 
134     data.entry = zipEntryRef.get();
135     return data;
136   }
137 
138   /*
139    * Get the useful fields from the zip entry.
140    *
141    * Returns "false" if the offsets to the fields or the contents of the fields
142    * appear to be bogus.
143    */
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)144   boolean getEntryInfo(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, Ref<Short> pMethod,
145       final Ref<Long> pUncompLen, Ref<Long> pCompLen, Ref<Long> pOffset,
146       final Ref<Long> pModWhen, Ref<Long> pCrc32)
147   {
148     final ZipEntryRO zipEntry = /*reinterpret_cast<ZipEntryRO*>*/ entry;
149     final ZipEntry ze = zipEntry.entry;
150 
151     if (pMethod != null) {
152       pMethod.set((short) ze.getMethod());
153     }
154     if (pUncompLen != null) {
155         pUncompLen.set(ze.getSize()); // uncompressed_length
156     }
157     if (pCompLen != null) {
158         pCompLen.set(ze.getCompressedSize());
159     }
160     if (pOffset != null) {
161       throw new UnsupportedOperationException("Figure out offset");
162       //        pOffset = ze.offset;
163     }
164     if (pModWhen != null) {
165         // todo pModWhen.set(ze.getLastModifiedTime().toMillis());
166     }
167     if (pCrc32 != null) {
168       pCrc32.set(ze.getCrc());
169     }
170 
171     return true;
172   }
173 
startIteration(Ref<Enumeration<? extends ZipEntry>> cookie)174   boolean startIteration(Ref<Enumeration<? extends ZipEntry>> cookie) {
175     return startIteration(cookie, null, null);
176   }
177 
startIteration( Ref<Enumeration<? extends ZipEntry>> cookie, final String prefix, final String suffix)178   boolean startIteration(/* void** */ Ref<Enumeration<? extends ZipEntry>> cookie, final String prefix, final String suffix)
179   {
180     cookie.set(this.mHandle.zipFile.entries());
181 //    ZipEntryRO* ze = new ZipEntryRO;
182 //    String pe(prefix ? prefix : "");
183 //    String se(suffix ? suffix : "");
184 //    int error = StartIteration(mHandle, &(ze.cookie),
185 //    prefix ? &pe : null,
186 //      suffix ? &se : null);
187 //    if (error) {
188 //      ALOGW("Could not start iteration over %s: %s", mFileName, ErrorCodeString(error));
189 //      delete ze;
190 //      return false;
191 //    }
192 //
193 //    *cookie = ze;
194     return true;
195   }
196 
nextEntry( Enumeration<? extends ZipEntry> cookie)197   org.robolectric.res.android.ZipFileRO.ZipEntryRO nextEntry(/*void* */ Enumeration<? extends ZipEntry> cookie)
198   {
199     if (!cookie.hasMoreElements()) {
200       return null;
201     }
202     ZipEntryRO zipEntryRO = new ZipEntryRO();
203     zipEntryRO.entry = cookie.nextElement();
204     return zipEntryRO;
205 //    ZipEntryRO ze = /*reinterpret_cast<ZipEntryRO*>*/(ZipEntryRO) cookie;
206 //    int error = Next(ze.cookie, &(ze.entry), &(ze.name));
207 //    if (error) {
208 //      if (error != -1) {
209 //        ALOGW("Error iteration over %s: %s", mFileName, ErrorCodeString(error));
210 //      }
211 //      return null;
212 //    }
213 //
214 //    return &(ze.entry);
215   }
216 
endIteration( Object cookie)217   void endIteration(/*void**/ Object cookie)
218   {
219 //    delete reinterpret_cast<ZipEntryRO*>(cookie);
220   }
221 
releaseEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry)222   void releaseEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry)
223   {
224 //    delete reinterpret_cast<ZipEntryRO*>(entry);
225   }
226 
227   /*
228    * Copy the entry's filename to the buffer.
229    */
getEntryFileName(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, Ref<String> buffer)230   int getEntryFileName(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, Ref<String> buffer)
231   {
232     buffer.set(entry.entry.getName());
233 
234 //    final ZipEntryRO* zipEntry = reinterpret_cast<ZipEntryRO*>(entry);
235 //    final uint16_t requiredSize = zipEntry.name.name_length + 1;
236 //
237 //    if (bufLen < requiredSize) {
238 //      ALOGW("Buffer too short, requires %d bytes for entry name", requiredSize);
239 //      return requiredSize;
240 //    }
241 //
242 //    memcpy(buffer, zipEntry.name.name, requiredSize - 1);
243 //    buffer[requiredSize - 1] = '\0';
244 //
245     return 0;
246   }
247 
248 /*
249  * Create a new FileMap object that spans the data in "entry".
250  */
ZipFileRO(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry)251   /*FileMap*/ ZipFileRO(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry)
252   {
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   {
280     // final _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry);
281     // const ZipEntry& ze = zipEntry->entry;
282     // int fd = GetFileDescriptor(mHandle);
283 
284     FileMap newMap = new FileMap();
285     if (!newMap.createFromZip(
286         mFileName,
287         mHandle.zipFile,
288         entry.entry,
289         entry.dataOffset,
290         toIntExact(entry.entry.getCompressedSize()),
291         true)) {
292       // delete newMap;
293       return null;
294     }
295 
296     return newMap;
297   }
298 
299   /*
300    * Uncompress an entry, in its entirety, into the provided output buffer.
301    *
302    * This doesn't verify the data's CRC, which might be useful for
303    * uncompressed data.  The caller should be able to manage it.
304    */
uncompressEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, Object buffer, int size)305   boolean uncompressEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, Object buffer, int size)
306   {
307     throw new UnsupportedOperationException("Implememnt me");
308 //    ZipEntryRO *zipEntry = reinterpret_cast<ZipEntryRO*>(entry);
309 //    final int error = ExtractToMemory(mHandle, &(zipEntry.entry),
310 //    (uint8_t*) buffer, size);
311 //    if (error) {
312 //      ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error));
313 //      return false;
314 //    }
315 //
316 //    return true;
317   }
318 
319   /*
320    * Uncompress an entry, in its entirety, to an open file descriptor.
321    *
322    * This doesn't verify the data's CRC, but probably should.
323    */
uncompressEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, int fd)324   boolean uncompressEntry(org.robolectric.res.android.ZipFileRO.ZipEntryRO entry, int fd)
325   {
326     throw new UnsupportedOperationException("Implememnt me");
327 //    ZipEntryRO *zipEntry = reinterpret_cast<ZipEntryRO*>(entry);
328 //    final int error = ExtractEntryToFile(mHandle, &(zipEntry.entry), fd);
329 //    if (error) {
330 //      ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error));
331 //      return false;
332 //    }
333 //
334 //    return true;
335   }
336 
String(String string)337   static String String(String string) {
338     return string;
339   }
340 }
341