1 /*
2  * Copyright (C) 2006 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 
17 //
18 // Class providing access to a read-only asset.  Asset objects are NOT
19 // thread-safe, and should not be shared across threads.
20 //
21 #ifndef __LIBS_ASSET_H
22 #define __LIBS_ASSET_H
23 
24 #include <stdio.h>
25 #include <sys/types.h>
26 
27 #include <memory>
28 
29 #include <android-base/unique_fd.h>
30 #include <utils/Compat.h>
31 #include <utils/Errors.h>
32 #include <utils/String8.h>
33 
34 namespace android {
35 
36 class FileMap;
37 
38 /*
39  * Instances of this class provide read-only operations on a byte stream.
40  *
41  * Access may be optimized for streaming, random, or whole buffer modes.  All
42  * operations are supported regardless of how the file was opened, but some
43  * things will be less efficient.  [pass that in??]
44  *
45  * "Asset" is the base class for all types of assets.  The classes below
46  * provide most of the implementation.  The AssetManager uses one of the
47  * static "create" functions defined here to create a new instance.
48  */
49 class Asset {
50 public:
51     virtual ~Asset(void) = default;
52 
53     static int32_t getGlobalCount();
54     static String8 getAssetAllocations();
55 
56     /* used when opening an asset */
57     typedef enum AccessMode {
58         ACCESS_UNKNOWN = 0,
59 
60         /* read chunks, and seek forward and backward */
61         ACCESS_RANDOM,
62 
63         /* read sequentially, with an occasional forward seek */
64         ACCESS_STREAMING,
65 
66         /* caller plans to ask for a read-only buffer with all data */
67         ACCESS_BUFFER,
68     } AccessMode;
69 
70     /*
71      * Read data from the current offset.  Returns the actual number of
72      * bytes read, 0 on EOF, or -1 on error.
73      */
74     virtual ssize_t read(void* buf, size_t count) = 0;
75 
76     /*
77      * Seek to the specified offset.  "whence" uses the same values as
78      * lseek/fseek.  Returns the new position on success, or (off64_t) -1
79      * on failure.
80      */
81     virtual off64_t seek(off64_t offset, int whence) = 0;
82 
83     /*
84      * Close the asset, freeing all associated resources.
85      */
86     virtual void close(void) = 0;
87 
88     /*
89      * Get a pointer to a buffer with the entire contents of the file.
90      */
91     virtual const void* getBuffer(bool wordAligned) = 0;
92 
93     /*
94      * Get the total amount of data that can be read.
95      */
96     virtual off64_t getLength(void) const = 0;
97 
98     /*
99      * Get the total amount of data that can be read from the current position.
100      */
101     virtual off64_t getRemainingLength(void) const = 0;
102 
103     /*
104      * Open a new file descriptor that can be used to read this asset.
105      * Returns -1 if you can not use the file descriptor (for example if the
106      * asset is compressed).
107      */
108     virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const = 0;
109 
110     /*
111      * Return whether this asset's buffer is allocated in RAM (not mmapped).
112      * Note: not virtual so it is safe to call even when being destroyed.
113      */
isAllocated(void)114     virtual bool isAllocated(void) const { return false; }
115 
116     /*
117      * Get a string identifying the asset's source.  This might be a full
118      * path, it might be a colon-separated list of identifiers.
119      *
120      * This is NOT intended to be used for anything except debug output.
121      * DO NOT try to parse this or use it to open a file.
122      */
getAssetSource(void)123     const char* getAssetSource(void) const { return mAssetSource.string(); }
124 
125     /*
126      * Create the asset from a file descriptor.
127      */
128     static Asset* createFromFd(const int fd, const char* fileName, AccessMode mode);
129 
130 protected:
131     /*
132      * Adds this Asset to the global Asset list for debugging and
133      * accounting.
134      * Concrete subclasses must call this in their constructor.
135      */
136     static void registerAsset(Asset* asset);
137 
138     /*
139      * Removes this Asset from the global Asset list.
140      * Concrete subclasses must call this in their destructor.
141      */
142     static void unregisterAsset(Asset* asset);
143 
144     Asset(void);        // constructor; only invoked indirectly
145 
146     /* handle common seek() housekeeping */
147     off64_t handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t maxPosn);
148 
149     /* set the asset source string */
setAssetSource(const String8 & path)150     void setAssetSource(const String8& path) { mAssetSource = path; }
151 
getAccessMode(void)152     AccessMode getAccessMode(void) const { return mAccessMode; }
153 
154 private:
155     /* these operations are not implemented */
156     Asset(const Asset& src);
157     Asset& operator=(const Asset& src);
158 
159     /* AssetManager needs access to our "create" functions */
160     friend class AssetManager;
161     friend class ApkAssets;
162     friend class ZipAssetsProvider;
163 
164     /*
165      * Create the asset from a named file on disk.
166      */
167     static Asset* createFromFile(const char* fileName, AccessMode mode);
168 
169     /*
170      * Create the asset from a named, compressed file on disk (e.g. ".gz").
171      */
172     static Asset* createFromCompressedFile(const char* fileName,
173         AccessMode mode);
174 
175 #if 0
176     /*
177      * Create the asset from a segment of an open file.  This will fail
178      * if "offset" and "length" don't fit within the bounds of the file.
179      *
180      * The asset takes ownership of the file descriptor.
181      */
182     static Asset* createFromFileSegment(int fd, off64_t offset, size_t length,
183         AccessMode mode);
184 
185     /*
186      * Create from compressed data.  "fd" should be seeked to the start of
187      * the compressed data.  This could be inside a gzip file or part of a
188      * Zip archive.
189      *
190      * The asset takes ownership of the file descriptor.
191      *
192      * This may not verify the validity of the compressed data until first
193      * use.
194      */
195     static Asset* createFromCompressedData(int fd, off64_t offset,
196         int compressionMethod, size_t compressedLength,
197         size_t uncompressedLength, AccessMode mode);
198 #endif
199 
200     /*
201      * Create the asset from a memory-mapped file segment.
202      *
203      * The asset takes ownership of the FileMap.
204      */
205     static Asset* createFromUncompressedMap(FileMap* dataMap, AccessMode mode);
206 
207     /*
208      * Create the asset from a memory-mapped file segment.
209      *
210      * The asset takes ownership of the FileMap and the file descriptor "fd". The file descriptor is
211      * used to request new file descriptors using "openFileDescriptor".
212      */
213     static std::unique_ptr<Asset> createFromUncompressedMap(std::unique_ptr<FileMap> dataMap,
214         base::unique_fd fd, AccessMode mode);
215 
216     /*
217      * Create the asset from a memory-mapped file segment with compressed
218      * data.
219      *
220      * The asset takes ownership of the FileMap.
221      */
222     static Asset* createFromCompressedMap(FileMap* dataMap,
223         size_t uncompressedLen, AccessMode mode);
224 
225     static std::unique_ptr<Asset> createFromCompressedMap(std::unique_ptr<FileMap> dataMap,
226         size_t uncompressedLen, AccessMode mode);
227 
228 
229     /*
230      * Create from a reference-counted chunk of shared memory.
231      */
232     // TODO
233 
234     AccessMode  mAccessMode;        // how the asset was opened
235     String8    mAssetSource;       // debug string
236 
237     Asset*		mNext;				// linked list.
238     Asset*		mPrev;
239 };
240 
241 
242 /*
243  * ===========================================================================
244  *
245  * Innards follow.  Do not use these classes directly.
246  */
247 
248 /*
249  * An asset based on an uncompressed file on disk.  It may encompass the
250  * entire file or just a piece of it.  Access is through fread/fseek.
251  */
252 class _FileAsset : public Asset {
253 public:
254     _FileAsset(void);
255     virtual ~_FileAsset(void);
256 
257     /*
258      * Use a piece of an already-open file.
259      *
260      * On success, the object takes ownership of "fd".
261      */
262     status_t openChunk(const char* fileName, int fd, off64_t offset, size_t length);
263 
264     /*
265      * Use a memory-mapped region.
266      *
267      * On success, the object takes ownership of "dataMap" and "fd".
268      */
269     status_t openChunk(FileMap* dataMap, base::unique_fd fd);
270 
271     /*
272      * Standard Asset interfaces.
273      */
274     virtual ssize_t read(void* buf, size_t count);
275     virtual off64_t seek(off64_t offset, int whence);
276     virtual void close(void);
277     virtual const void* getBuffer(bool wordAligned);
getLength(void)278     virtual off64_t getLength(void) const { return mLength; }
getRemainingLength(void)279     virtual off64_t getRemainingLength(void) const { return mLength-mOffset; }
280     virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const;
isAllocated(void)281     virtual bool isAllocated(void) const { return mBuf != NULL; }
282 
283 private:
284     off64_t         mStart;         // absolute file offset of start of chunk
285     off64_t         mLength;        // length of the chunk
286     off64_t         mOffset;        // current local offset, 0 == mStart
287     FILE*           mFp;            // for read/seek
288     char*           mFileName;      // for opening
289     base::unique_fd mFd;            // for opening file descriptors
290 
291     /*
292      * To support getBuffer() we either need to read the entire thing into
293      * a buffer or memory-map it.  For small files it's probably best to
294      * just read them in.
295      */
296     enum { kReadVsMapThreshold = 4096 };
297 
298     FileMap*    mMap;           // for memory map
299     unsigned char* mBuf;        // for read
300 
301     const void* ensureAlignment(FileMap* map);
302 };
303 
304 
305 /*
306  * An asset based on compressed data in a file.
307  */
308 class _CompressedAsset : public Asset {
309 public:
310     _CompressedAsset(void);
311     virtual ~_CompressedAsset(void);
312 
313     /*
314      * Use a piece of an already-open file.
315      *
316      * On success, the object takes ownership of "fd".
317      */
318     status_t openChunk(int fd, off64_t offset, int compressionMethod,
319         size_t uncompressedLen, size_t compressedLen);
320 
321     /*
322      * Use a memory-mapped region.
323      *
324      * On success, the object takes ownership of "fd".
325      */
326     status_t openChunk(FileMap* dataMap, size_t uncompressedLen);
327 
328     /*
329      * Standard Asset interfaces.
330      */
331     virtual ssize_t read(void* buf, size_t count);
332     virtual off64_t seek(off64_t offset, int whence);
333     virtual void close(void);
334     virtual const void* getBuffer(bool wordAligned);
getLength(void)335     virtual off64_t getLength(void) const { return mUncompressedLen; }
getRemainingLength(void)336     virtual off64_t getRemainingLength(void) const { return mUncompressedLen-mOffset; }
openFileDescriptor(off64_t *,off64_t *)337     virtual int openFileDescriptor(off64_t* /* outStart */, off64_t* /* outLength */) const { return -1; }
isAllocated(void)338     virtual bool isAllocated(void) const { return mBuf != NULL; }
339 
340 private:
341     off64_t     mStart;         // offset to start of compressed data
342     off64_t     mCompressedLen; // length of the compressed data
343     off64_t     mUncompressedLen; // length of the uncompressed data
344     off64_t     mOffset;        // current offset, 0 == start of uncomp data
345 
346     FileMap*    mMap;           // for memory-mapped input
347     int         mFd;            // for file input
348 
349     class StreamingZipInflater* mZipInflater;  // for streaming large compressed assets
350 
351     unsigned char*  mBuf;       // for getBuffer()
352 };
353 
354 // need: shared mmap version?
355 
356 }; // namespace android
357 
358 #endif // __LIBS_ASSET_H
359