xref: /aosp_15_r20/frameworks/base/libs/androidfw/Asset.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2006 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker //
18*d57664e9SAndroid Build Coastguard Worker // Provide access to a read-only asset.
19*d57664e9SAndroid Build Coastguard Worker //
20*d57664e9SAndroid Build Coastguard Worker 
21*d57664e9SAndroid Build Coastguard Worker #define LOG_TAG "asset"
22*d57664e9SAndroid Build Coastguard Worker //#define NDEBUG 0
23*d57664e9SAndroid Build Coastguard Worker 
24*d57664e9SAndroid Build Coastguard Worker #include <androidfw/Asset.h>
25*d57664e9SAndroid Build Coastguard Worker #include <androidfw/StreamingZipInflater.h>
26*d57664e9SAndroid Build Coastguard Worker #include <androidfw/Util.h>
27*d57664e9SAndroid Build Coastguard Worker #include <androidfw/ZipFileRO.h>
28*d57664e9SAndroid Build Coastguard Worker #include <androidfw/ZipUtils.h>
29*d57664e9SAndroid Build Coastguard Worker #include <cutils/atomic.h>
30*d57664e9SAndroid Build Coastguard Worker #include <utils/FileMap.h>
31*d57664e9SAndroid Build Coastguard Worker #include <utils/Log.h>
32*d57664e9SAndroid Build Coastguard Worker #include <utils/threads.h>
33*d57664e9SAndroid Build Coastguard Worker 
34*d57664e9SAndroid Build Coastguard Worker #include <assert.h>
35*d57664e9SAndroid Build Coastguard Worker #include <errno.h>
36*d57664e9SAndroid Build Coastguard Worker #include <fcntl.h>
37*d57664e9SAndroid Build Coastguard Worker #include <memory.h>
38*d57664e9SAndroid Build Coastguard Worker #include <string.h>
39*d57664e9SAndroid Build Coastguard Worker #include <sys/stat.h>
40*d57664e9SAndroid Build Coastguard Worker #include <sys/types.h>
41*d57664e9SAndroid Build Coastguard Worker #include <unistd.h>
42*d57664e9SAndroid Build Coastguard Worker 
43*d57664e9SAndroid Build Coastguard Worker using namespace android;
44*d57664e9SAndroid Build Coastguard Worker 
45*d57664e9SAndroid Build Coastguard Worker #ifndef O_BINARY
46*d57664e9SAndroid Build Coastguard Worker # define O_BINARY 0
47*d57664e9SAndroid Build Coastguard Worker #endif
48*d57664e9SAndroid Build Coastguard Worker 
49*d57664e9SAndroid Build Coastguard Worker static const bool kIsDebug = false;
50*d57664e9SAndroid Build Coastguard Worker 
51*d57664e9SAndroid Build Coastguard Worker static Mutex gAssetLock;
52*d57664e9SAndroid Build Coastguard Worker static int32_t gCount = 0;
53*d57664e9SAndroid Build Coastguard Worker static Asset* gHead = NULL;
54*d57664e9SAndroid Build Coastguard Worker static Asset* gTail = NULL;
55*d57664e9SAndroid Build Coastguard Worker 
registerAsset(Asset * asset)56*d57664e9SAndroid Build Coastguard Worker void Asset::registerAsset(Asset* asset)
57*d57664e9SAndroid Build Coastguard Worker {
58*d57664e9SAndroid Build Coastguard Worker     AutoMutex _l(gAssetLock);
59*d57664e9SAndroid Build Coastguard Worker     gCount++;
60*d57664e9SAndroid Build Coastguard Worker     asset->mNext = asset->mPrev = NULL;
61*d57664e9SAndroid Build Coastguard Worker     if (gTail == NULL) {
62*d57664e9SAndroid Build Coastguard Worker         gHead = gTail = asset;
63*d57664e9SAndroid Build Coastguard Worker     } else {
64*d57664e9SAndroid Build Coastguard Worker         asset->mPrev = gTail;
65*d57664e9SAndroid Build Coastguard Worker         gTail->mNext = asset;
66*d57664e9SAndroid Build Coastguard Worker         gTail = asset;
67*d57664e9SAndroid Build Coastguard Worker     }
68*d57664e9SAndroid Build Coastguard Worker 
69*d57664e9SAndroid Build Coastguard Worker     if (kIsDebug) {
70*d57664e9SAndroid Build Coastguard Worker         ALOGI("Creating Asset %p #%d\n", asset, gCount);
71*d57664e9SAndroid Build Coastguard Worker     }
72*d57664e9SAndroid Build Coastguard Worker }
73*d57664e9SAndroid Build Coastguard Worker 
unregisterAsset(Asset * asset)74*d57664e9SAndroid Build Coastguard Worker void Asset::unregisterAsset(Asset* asset)
75*d57664e9SAndroid Build Coastguard Worker {
76*d57664e9SAndroid Build Coastguard Worker     AutoMutex _l(gAssetLock);
77*d57664e9SAndroid Build Coastguard Worker     gCount--;
78*d57664e9SAndroid Build Coastguard Worker     if (gHead == asset) {
79*d57664e9SAndroid Build Coastguard Worker         gHead = asset->mNext;
80*d57664e9SAndroid Build Coastguard Worker     }
81*d57664e9SAndroid Build Coastguard Worker     if (gTail == asset) {
82*d57664e9SAndroid Build Coastguard Worker         gTail = asset->mPrev;
83*d57664e9SAndroid Build Coastguard Worker     }
84*d57664e9SAndroid Build Coastguard Worker     if (asset->mNext != NULL) {
85*d57664e9SAndroid Build Coastguard Worker         asset->mNext->mPrev = asset->mPrev;
86*d57664e9SAndroid Build Coastguard Worker     }
87*d57664e9SAndroid Build Coastguard Worker     if (asset->mPrev != NULL) {
88*d57664e9SAndroid Build Coastguard Worker         asset->mPrev->mNext = asset->mNext;
89*d57664e9SAndroid Build Coastguard Worker     }
90*d57664e9SAndroid Build Coastguard Worker     asset->mNext = asset->mPrev = NULL;
91*d57664e9SAndroid Build Coastguard Worker 
92*d57664e9SAndroid Build Coastguard Worker     if (kIsDebug) {
93*d57664e9SAndroid Build Coastguard Worker         ALOGI("Destroying Asset in %p #%d\n", asset, gCount);
94*d57664e9SAndroid Build Coastguard Worker     }
95*d57664e9SAndroid Build Coastguard Worker }
96*d57664e9SAndroid Build Coastguard Worker 
getGlobalCount()97*d57664e9SAndroid Build Coastguard Worker int32_t Asset::getGlobalCount()
98*d57664e9SAndroid Build Coastguard Worker {
99*d57664e9SAndroid Build Coastguard Worker     AutoMutex _l(gAssetLock);
100*d57664e9SAndroid Build Coastguard Worker     return gCount;
101*d57664e9SAndroid Build Coastguard Worker }
102*d57664e9SAndroid Build Coastguard Worker 
getAssetAllocations()103*d57664e9SAndroid Build Coastguard Worker String8 Asset::getAssetAllocations()
104*d57664e9SAndroid Build Coastguard Worker {
105*d57664e9SAndroid Build Coastguard Worker     AutoMutex _l(gAssetLock);
106*d57664e9SAndroid Build Coastguard Worker     String8 res;
107*d57664e9SAndroid Build Coastguard Worker     Asset* cur = gHead;
108*d57664e9SAndroid Build Coastguard Worker     while (cur != NULL) {
109*d57664e9SAndroid Build Coastguard Worker         if (cur->isAllocated()) {
110*d57664e9SAndroid Build Coastguard Worker             res.append("    ");
111*d57664e9SAndroid Build Coastguard Worker             res.append(cur->getAssetSource());
112*d57664e9SAndroid Build Coastguard Worker             off64_t size = (cur->getLength()+512)/1024;
113*d57664e9SAndroid Build Coastguard Worker             char buf[64];
114*d57664e9SAndroid Build Coastguard Worker             snprintf(buf, sizeof(buf), ": %dK\n", (int)size);
115*d57664e9SAndroid Build Coastguard Worker             res.append(buf);
116*d57664e9SAndroid Build Coastguard Worker         }
117*d57664e9SAndroid Build Coastguard Worker         cur = cur->mNext;
118*d57664e9SAndroid Build Coastguard Worker     }
119*d57664e9SAndroid Build Coastguard Worker 
120*d57664e9SAndroid Build Coastguard Worker     return res;
121*d57664e9SAndroid Build Coastguard Worker }
122*d57664e9SAndroid Build Coastguard Worker 
Asset(void)123*d57664e9SAndroid Build Coastguard Worker Asset::Asset(void)
124*d57664e9SAndroid Build Coastguard Worker     : mAccessMode(ACCESS_UNKNOWN), mNext(NULL), mPrev(NULL)
125*d57664e9SAndroid Build Coastguard Worker {
126*d57664e9SAndroid Build Coastguard Worker }
127*d57664e9SAndroid Build Coastguard Worker 
128*d57664e9SAndroid Build Coastguard Worker /*
129*d57664e9SAndroid Build Coastguard Worker  * Create a new Asset from a file on disk.  There is a fair chance that
130*d57664e9SAndroid Build Coastguard Worker  * the file doesn't actually exist.
131*d57664e9SAndroid Build Coastguard Worker  *
132*d57664e9SAndroid Build Coastguard Worker  * We can use "mode" to decide how we want to go about it.
133*d57664e9SAndroid Build Coastguard Worker  */
createFromFile(const char * fileName,AccessMode mode)134*d57664e9SAndroid Build Coastguard Worker /*static*/ Asset* Asset::createFromFile(const char* fileName, AccessMode mode)
135*d57664e9SAndroid Build Coastguard Worker {
136*d57664e9SAndroid Build Coastguard Worker     return createFromFd(open(fileName, O_RDONLY | O_BINARY), fileName, mode);
137*d57664e9SAndroid Build Coastguard Worker }
138*d57664e9SAndroid Build Coastguard Worker 
139*d57664e9SAndroid Build Coastguard Worker /*
140*d57664e9SAndroid Build Coastguard Worker  * Create a new Asset from a file on disk.  There is a fair chance that
141*d57664e9SAndroid Build Coastguard Worker  * the file doesn't actually exist.
142*d57664e9SAndroid Build Coastguard Worker  *
143*d57664e9SAndroid Build Coastguard Worker  * We can use "mode" to decide how we want to go about it.
144*d57664e9SAndroid Build Coastguard Worker  */
createFromFd(const int fd,const char * fileName,AccessMode mode)145*d57664e9SAndroid Build Coastguard Worker /*static*/ Asset* Asset::createFromFd(const int fd, const char* fileName, AccessMode mode)
146*d57664e9SAndroid Build Coastguard Worker {
147*d57664e9SAndroid Build Coastguard Worker     if (fd < 0) {
148*d57664e9SAndroid Build Coastguard Worker         return NULL;
149*d57664e9SAndroid Build Coastguard Worker     }
150*d57664e9SAndroid Build Coastguard Worker 
151*d57664e9SAndroid Build Coastguard Worker     _FileAsset* pAsset;
152*d57664e9SAndroid Build Coastguard Worker     status_t result;
153*d57664e9SAndroid Build Coastguard Worker     off64_t length;
154*d57664e9SAndroid Build Coastguard Worker 
155*d57664e9SAndroid Build Coastguard Worker     /*
156*d57664e9SAndroid Build Coastguard Worker      * Under Linux, the lseek fails if we actually opened a directory.  To
157*d57664e9SAndroid Build Coastguard Worker      * be correct we should test the file type explicitly, but since we
158*d57664e9SAndroid Build Coastguard Worker      * always open things read-only it doesn't really matter, so there's
159*d57664e9SAndroid Build Coastguard Worker      * no value in incurring the extra overhead of an fstat() call.
160*d57664e9SAndroid Build Coastguard Worker      */
161*d57664e9SAndroid Build Coastguard Worker     // TODO(kroot): replace this with fstat despite the plea above.
162*d57664e9SAndroid Build Coastguard Worker #if 1
163*d57664e9SAndroid Build Coastguard Worker     length = lseek64(fd, 0, SEEK_END);
164*d57664e9SAndroid Build Coastguard Worker     if (length < 0) {
165*d57664e9SAndroid Build Coastguard Worker         ::close(fd);
166*d57664e9SAndroid Build Coastguard Worker         return NULL;
167*d57664e9SAndroid Build Coastguard Worker     }
168*d57664e9SAndroid Build Coastguard Worker     (void) lseek64(fd, 0, SEEK_SET);
169*d57664e9SAndroid Build Coastguard Worker #else
170*d57664e9SAndroid Build Coastguard Worker     struct stat st;
171*d57664e9SAndroid Build Coastguard Worker     if (fstat(fd, &st) < 0) {
172*d57664e9SAndroid Build Coastguard Worker         ::close(fd);
173*d57664e9SAndroid Build Coastguard Worker         return NULL;
174*d57664e9SAndroid Build Coastguard Worker     }
175*d57664e9SAndroid Build Coastguard Worker 
176*d57664e9SAndroid Build Coastguard Worker     if (!S_ISREG(st.st_mode)) {
177*d57664e9SAndroid Build Coastguard Worker         ::close(fd);
178*d57664e9SAndroid Build Coastguard Worker         return NULL;
179*d57664e9SAndroid Build Coastguard Worker     }
180*d57664e9SAndroid Build Coastguard Worker #endif
181*d57664e9SAndroid Build Coastguard Worker 
182*d57664e9SAndroid Build Coastguard Worker     pAsset = new _FileAsset;
183*d57664e9SAndroid Build Coastguard Worker     result = pAsset->openChunk(fileName, fd, 0, length);
184*d57664e9SAndroid Build Coastguard Worker     if (result != NO_ERROR) {
185*d57664e9SAndroid Build Coastguard Worker         delete pAsset;
186*d57664e9SAndroid Build Coastguard Worker         return NULL;
187*d57664e9SAndroid Build Coastguard Worker     }
188*d57664e9SAndroid Build Coastguard Worker 
189*d57664e9SAndroid Build Coastguard Worker     pAsset->mAccessMode = mode;
190*d57664e9SAndroid Build Coastguard Worker     return pAsset;
191*d57664e9SAndroid Build Coastguard Worker }
192*d57664e9SAndroid Build Coastguard Worker 
193*d57664e9SAndroid Build Coastguard Worker 
194*d57664e9SAndroid Build Coastguard Worker /*
195*d57664e9SAndroid Build Coastguard Worker  * Create a new Asset from a compressed file on disk.  There is a fair chance
196*d57664e9SAndroid Build Coastguard Worker  * that the file doesn't actually exist.
197*d57664e9SAndroid Build Coastguard Worker  *
198*d57664e9SAndroid Build Coastguard Worker  * We currently support gzip files.  We might want to handle .bz2 someday.
199*d57664e9SAndroid Build Coastguard Worker  */
createFromCompressedFile(const char * fileName,AccessMode mode)200*d57664e9SAndroid Build Coastguard Worker /*static*/ Asset* Asset::createFromCompressedFile(const char* fileName,
201*d57664e9SAndroid Build Coastguard Worker     AccessMode mode)
202*d57664e9SAndroid Build Coastguard Worker {
203*d57664e9SAndroid Build Coastguard Worker     _CompressedAsset* pAsset;
204*d57664e9SAndroid Build Coastguard Worker     status_t result;
205*d57664e9SAndroid Build Coastguard Worker     off64_t fileLen;
206*d57664e9SAndroid Build Coastguard Worker     bool scanResult;
207*d57664e9SAndroid Build Coastguard Worker     long offset;
208*d57664e9SAndroid Build Coastguard Worker     int method;
209*d57664e9SAndroid Build Coastguard Worker     long uncompressedLen, compressedLen;
210*d57664e9SAndroid Build Coastguard Worker     int fd;
211*d57664e9SAndroid Build Coastguard Worker 
212*d57664e9SAndroid Build Coastguard Worker     fd = open(fileName, O_RDONLY | O_BINARY);
213*d57664e9SAndroid Build Coastguard Worker     if (fd < 0)
214*d57664e9SAndroid Build Coastguard Worker         return NULL;
215*d57664e9SAndroid Build Coastguard Worker 
216*d57664e9SAndroid Build Coastguard Worker     fileLen = lseek(fd, 0, SEEK_END);
217*d57664e9SAndroid Build Coastguard Worker     if (fileLen < 0) {
218*d57664e9SAndroid Build Coastguard Worker         ::close(fd);
219*d57664e9SAndroid Build Coastguard Worker         return NULL;
220*d57664e9SAndroid Build Coastguard Worker     }
221*d57664e9SAndroid Build Coastguard Worker     (void) lseek(fd, 0, SEEK_SET);
222*d57664e9SAndroid Build Coastguard Worker 
223*d57664e9SAndroid Build Coastguard Worker     /* want buffered I/O for the file scan; must dup so fclose() is safe */
224*d57664e9SAndroid Build Coastguard Worker     FILE* fp = fdopen(dup(fd), "rb");
225*d57664e9SAndroid Build Coastguard Worker     if (fp == NULL) {
226*d57664e9SAndroid Build Coastguard Worker         ::close(fd);
227*d57664e9SAndroid Build Coastguard Worker         return NULL;
228*d57664e9SAndroid Build Coastguard Worker     }
229*d57664e9SAndroid Build Coastguard Worker 
230*d57664e9SAndroid Build Coastguard Worker     unsigned long crc32;
231*d57664e9SAndroid Build Coastguard Worker     scanResult = ZipUtils::examineGzip(fp, &method, &uncompressedLen,
232*d57664e9SAndroid Build Coastguard Worker                     &compressedLen, &crc32);
233*d57664e9SAndroid Build Coastguard Worker     offset = ftell(fp);
234*d57664e9SAndroid Build Coastguard Worker     fclose(fp);
235*d57664e9SAndroid Build Coastguard Worker     if (!scanResult) {
236*d57664e9SAndroid Build Coastguard Worker         ALOGD("File '%s' is not in gzip format\n", fileName);
237*d57664e9SAndroid Build Coastguard Worker         ::close(fd);
238*d57664e9SAndroid Build Coastguard Worker         return NULL;
239*d57664e9SAndroid Build Coastguard Worker     }
240*d57664e9SAndroid Build Coastguard Worker 
241*d57664e9SAndroid Build Coastguard Worker     pAsset = new _CompressedAsset;
242*d57664e9SAndroid Build Coastguard Worker     result = pAsset->openChunk(fd, offset, method, uncompressedLen,
243*d57664e9SAndroid Build Coastguard Worker                 compressedLen);
244*d57664e9SAndroid Build Coastguard Worker     if (result != NO_ERROR) {
245*d57664e9SAndroid Build Coastguard Worker         delete pAsset;
246*d57664e9SAndroid Build Coastguard Worker         return NULL;
247*d57664e9SAndroid Build Coastguard Worker     }
248*d57664e9SAndroid Build Coastguard Worker 
249*d57664e9SAndroid Build Coastguard Worker     pAsset->mAccessMode = mode;
250*d57664e9SAndroid Build Coastguard Worker     return pAsset;
251*d57664e9SAndroid Build Coastguard Worker }
252*d57664e9SAndroid Build Coastguard Worker 
253*d57664e9SAndroid Build Coastguard Worker 
254*d57664e9SAndroid Build Coastguard Worker #if 0
255*d57664e9SAndroid Build Coastguard Worker /*
256*d57664e9SAndroid Build Coastguard Worker  * Create a new Asset from part of an open file.
257*d57664e9SAndroid Build Coastguard Worker  */
258*d57664e9SAndroid Build Coastguard Worker /*static*/ Asset* Asset::createFromFileSegment(int fd, off64_t offset,
259*d57664e9SAndroid Build Coastguard Worker     size_t length, AccessMode mode)
260*d57664e9SAndroid Build Coastguard Worker {
261*d57664e9SAndroid Build Coastguard Worker     _FileAsset* pAsset;
262*d57664e9SAndroid Build Coastguard Worker     status_t result;
263*d57664e9SAndroid Build Coastguard Worker 
264*d57664e9SAndroid Build Coastguard Worker     pAsset = new _FileAsset;
265*d57664e9SAndroid Build Coastguard Worker     result = pAsset->openChunk(NULL, fd, offset, length);
266*d57664e9SAndroid Build Coastguard Worker     if (result != NO_ERROR) {
267*d57664e9SAndroid Build Coastguard Worker         delete pAsset;
268*d57664e9SAndroid Build Coastguard Worker         return NULL;
269*d57664e9SAndroid Build Coastguard Worker     }
270*d57664e9SAndroid Build Coastguard Worker 
271*d57664e9SAndroid Build Coastguard Worker     pAsset->mAccessMode = mode;
272*d57664e9SAndroid Build Coastguard Worker     return pAsset;
273*d57664e9SAndroid Build Coastguard Worker }
274*d57664e9SAndroid Build Coastguard Worker 
275*d57664e9SAndroid Build Coastguard Worker /*
276*d57664e9SAndroid Build Coastguard Worker  * Create a new Asset from compressed data in an open file.
277*d57664e9SAndroid Build Coastguard Worker  */
278*d57664e9SAndroid Build Coastguard Worker /*static*/ Asset* Asset::createFromCompressedData(int fd, off64_t offset,
279*d57664e9SAndroid Build Coastguard Worker     int compressionMethod, size_t uncompressedLen, size_t compressedLen,
280*d57664e9SAndroid Build Coastguard Worker     AccessMode mode)
281*d57664e9SAndroid Build Coastguard Worker {
282*d57664e9SAndroid Build Coastguard Worker     _CompressedAsset* pAsset;
283*d57664e9SAndroid Build Coastguard Worker     status_t result;
284*d57664e9SAndroid Build Coastguard Worker 
285*d57664e9SAndroid Build Coastguard Worker     pAsset = new _CompressedAsset;
286*d57664e9SAndroid Build Coastguard Worker     result = pAsset->openChunk(fd, offset, compressionMethod,
287*d57664e9SAndroid Build Coastguard Worker                 uncompressedLen, compressedLen);
288*d57664e9SAndroid Build Coastguard Worker     if (result != NO_ERROR) {
289*d57664e9SAndroid Build Coastguard Worker         delete pAsset;
290*d57664e9SAndroid Build Coastguard Worker         return NULL;
291*d57664e9SAndroid Build Coastguard Worker     }
292*d57664e9SAndroid Build Coastguard Worker 
293*d57664e9SAndroid Build Coastguard Worker     pAsset->mAccessMode = mode;
294*d57664e9SAndroid Build Coastguard Worker     return pAsset;
295*d57664e9SAndroid Build Coastguard Worker }
296*d57664e9SAndroid Build Coastguard Worker #endif
297*d57664e9SAndroid Build Coastguard Worker 
298*d57664e9SAndroid Build Coastguard Worker /*
299*d57664e9SAndroid Build Coastguard Worker  * Create a new Asset from a memory mapping.
300*d57664e9SAndroid Build Coastguard Worker  */
createFromUncompressedMap(incfs::IncFsFileMap && dataMap,AccessMode mode,base::unique_fd fd)301*d57664e9SAndroid Build Coastguard Worker /*static*/ std::unique_ptr<Asset> Asset::createFromUncompressedMap(incfs::IncFsFileMap&& dataMap,
302*d57664e9SAndroid Build Coastguard Worker                                                                    AccessMode mode,
303*d57664e9SAndroid Build Coastguard Worker                                                                    base::unique_fd fd)
304*d57664e9SAndroid Build Coastguard Worker {
305*d57664e9SAndroid Build Coastguard Worker     auto pAsset = util::make_unique<_FileAsset>();
306*d57664e9SAndroid Build Coastguard Worker 
307*d57664e9SAndroid Build Coastguard Worker     status_t result = pAsset->openChunk(std::move(dataMap), std::move(fd));
308*d57664e9SAndroid Build Coastguard Worker     if (result != NO_ERROR) {
309*d57664e9SAndroid Build Coastguard Worker         return NULL;
310*d57664e9SAndroid Build Coastguard Worker     }
311*d57664e9SAndroid Build Coastguard Worker 
312*d57664e9SAndroid Build Coastguard Worker     pAsset->mAccessMode = mode;
313*d57664e9SAndroid Build Coastguard Worker     return pAsset;
314*d57664e9SAndroid Build Coastguard Worker }
315*d57664e9SAndroid Build Coastguard Worker 
316*d57664e9SAndroid Build Coastguard Worker /*
317*d57664e9SAndroid Build Coastguard Worker  * Create a new Asset from compressed data in a memory mapping.
318*d57664e9SAndroid Build Coastguard Worker  */
createFromCompressedMap(incfs::IncFsFileMap && dataMap,size_t uncompressedLen,AccessMode mode)319*d57664e9SAndroid Build Coastguard Worker /*static*/ std::unique_ptr<Asset> Asset::createFromCompressedMap(incfs::IncFsFileMap&& dataMap,
320*d57664e9SAndroid Build Coastguard Worker                                                                  size_t uncompressedLen,
321*d57664e9SAndroid Build Coastguard Worker                                                                  AccessMode mode)
322*d57664e9SAndroid Build Coastguard Worker {
323*d57664e9SAndroid Build Coastguard Worker   auto pAsset = util::make_unique<_CompressedAsset>();
324*d57664e9SAndroid Build Coastguard Worker 
325*d57664e9SAndroid Build Coastguard Worker   status_t result = pAsset->openChunk(std::move(dataMap), uncompressedLen);
326*d57664e9SAndroid Build Coastguard Worker   if (result != NO_ERROR) {
327*d57664e9SAndroid Build Coastguard Worker       return NULL;
328*d57664e9SAndroid Build Coastguard Worker   }
329*d57664e9SAndroid Build Coastguard Worker 
330*d57664e9SAndroid Build Coastguard Worker   pAsset->mAccessMode = mode;
331*d57664e9SAndroid Build Coastguard Worker   return pAsset;
332*d57664e9SAndroid Build Coastguard Worker }
333*d57664e9SAndroid Build Coastguard Worker 
334*d57664e9SAndroid Build Coastguard Worker /*
335*d57664e9SAndroid Build Coastguard Worker  * Do generic seek() housekeeping.  Pass in the offset/whence values from
336*d57664e9SAndroid Build Coastguard Worker  * the seek request, along with the current chunk offset and the chunk
337*d57664e9SAndroid Build Coastguard Worker  * length.
338*d57664e9SAndroid Build Coastguard Worker  *
339*d57664e9SAndroid Build Coastguard Worker  * Returns the new chunk offset, or -1 if the seek is illegal.
340*d57664e9SAndroid Build Coastguard Worker  */
handleSeek(off64_t offset,int whence,off64_t curPosn,off64_t maxPosn)341*d57664e9SAndroid Build Coastguard Worker off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t maxPosn)
342*d57664e9SAndroid Build Coastguard Worker {
343*d57664e9SAndroid Build Coastguard Worker     off64_t newOffset;
344*d57664e9SAndroid Build Coastguard Worker 
345*d57664e9SAndroid Build Coastguard Worker     switch (whence) {
346*d57664e9SAndroid Build Coastguard Worker     case SEEK_SET:
347*d57664e9SAndroid Build Coastguard Worker         newOffset = offset;
348*d57664e9SAndroid Build Coastguard Worker         break;
349*d57664e9SAndroid Build Coastguard Worker     case SEEK_CUR:
350*d57664e9SAndroid Build Coastguard Worker         newOffset = curPosn + offset;
351*d57664e9SAndroid Build Coastguard Worker         break;
352*d57664e9SAndroid Build Coastguard Worker     case SEEK_END:
353*d57664e9SAndroid Build Coastguard Worker         newOffset = maxPosn + offset;
354*d57664e9SAndroid Build Coastguard Worker         break;
355*d57664e9SAndroid Build Coastguard Worker     default:
356*d57664e9SAndroid Build Coastguard Worker         ALOGW("unexpected whence %d\n", whence);
357*d57664e9SAndroid Build Coastguard Worker         // this was happening due to an off64_t size mismatch
358*d57664e9SAndroid Build Coastguard Worker         assert(false);
359*d57664e9SAndroid Build Coastguard Worker         return (off64_t) -1;
360*d57664e9SAndroid Build Coastguard Worker     }
361*d57664e9SAndroid Build Coastguard Worker 
362*d57664e9SAndroid Build Coastguard Worker     if (newOffset < 0 || newOffset > maxPosn) {
363*d57664e9SAndroid Build Coastguard Worker         ALOGW("seek out of range: want %ld, end=%ld\n",
364*d57664e9SAndroid Build Coastguard Worker             (long) newOffset, (long) maxPosn);
365*d57664e9SAndroid Build Coastguard Worker         return (off64_t) -1;
366*d57664e9SAndroid Build Coastguard Worker     }
367*d57664e9SAndroid Build Coastguard Worker 
368*d57664e9SAndroid Build Coastguard Worker     return newOffset;
369*d57664e9SAndroid Build Coastguard Worker }
370*d57664e9SAndroid Build Coastguard Worker 
371*d57664e9SAndroid Build Coastguard Worker 
372*d57664e9SAndroid Build Coastguard Worker /*
373*d57664e9SAndroid Build Coastguard Worker  * ===========================================================================
374*d57664e9SAndroid Build Coastguard Worker  *      _FileAsset
375*d57664e9SAndroid Build Coastguard Worker  * ===========================================================================
376*d57664e9SAndroid Build Coastguard Worker  */
377*d57664e9SAndroid Build Coastguard Worker 
378*d57664e9SAndroid Build Coastguard Worker /*
379*d57664e9SAndroid Build Coastguard Worker  * Constructor.
380*d57664e9SAndroid Build Coastguard Worker  */
_FileAsset(void)381*d57664e9SAndroid Build Coastguard Worker _FileAsset::_FileAsset(void)
382*d57664e9SAndroid Build Coastguard Worker     : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mFd(-1), mBuf(NULL)
383*d57664e9SAndroid Build Coastguard Worker {
384*d57664e9SAndroid Build Coastguard Worker     // Register the Asset with the global list here after it is fully constructed and its
385*d57664e9SAndroid Build Coastguard Worker     // vtable pointer points to this concrete type. b/31113965
386*d57664e9SAndroid Build Coastguard Worker     registerAsset(this);
387*d57664e9SAndroid Build Coastguard Worker }
388*d57664e9SAndroid Build Coastguard Worker 
389*d57664e9SAndroid Build Coastguard Worker /*
390*d57664e9SAndroid Build Coastguard Worker  * Destructor.  Release resources.
391*d57664e9SAndroid Build Coastguard Worker  */
~_FileAsset(void)392*d57664e9SAndroid Build Coastguard Worker _FileAsset::~_FileAsset(void)
393*d57664e9SAndroid Build Coastguard Worker {
394*d57664e9SAndroid Build Coastguard Worker     close();
395*d57664e9SAndroid Build Coastguard Worker 
396*d57664e9SAndroid Build Coastguard Worker     // Unregister the Asset from the global list here before it is destructed and while its vtable
397*d57664e9SAndroid Build Coastguard Worker     // pointer still points to this concrete type. b/31113965
398*d57664e9SAndroid Build Coastguard Worker     unregisterAsset(this);
399*d57664e9SAndroid Build Coastguard Worker }
400*d57664e9SAndroid Build Coastguard Worker 
401*d57664e9SAndroid Build Coastguard Worker /*
402*d57664e9SAndroid Build Coastguard Worker  * Operate on a chunk of an uncompressed file.
403*d57664e9SAndroid Build Coastguard Worker  *
404*d57664e9SAndroid Build Coastguard Worker  * Zero-length chunks are allowed.
405*d57664e9SAndroid Build Coastguard Worker  */
openChunk(const char * fileName,int fd,off64_t offset,size_t length)406*d57664e9SAndroid Build Coastguard Worker status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, size_t length)
407*d57664e9SAndroid Build Coastguard Worker {
408*d57664e9SAndroid Build Coastguard Worker     assert(mFp == NULL);    // no reopen
409*d57664e9SAndroid Build Coastguard Worker     assert(!mMap.has_value());
410*d57664e9SAndroid Build Coastguard Worker     assert(fd >= 0);
411*d57664e9SAndroid Build Coastguard Worker     assert(offset >= 0);
412*d57664e9SAndroid Build Coastguard Worker 
413*d57664e9SAndroid Build Coastguard Worker     /*
414*d57664e9SAndroid Build Coastguard Worker      * Seek to end to get file length.
415*d57664e9SAndroid Build Coastguard Worker      */
416*d57664e9SAndroid Build Coastguard Worker     off64_t fileLength;
417*d57664e9SAndroid Build Coastguard Worker     fileLength = lseek64(fd, 0, SEEK_END);
418*d57664e9SAndroid Build Coastguard Worker     if (fileLength == (off64_t) -1) {
419*d57664e9SAndroid Build Coastguard Worker         // probably a bad file descriptor
420*d57664e9SAndroid Build Coastguard Worker         ALOGD("failed lseek (errno=%d)\n", errno);
421*d57664e9SAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
422*d57664e9SAndroid Build Coastguard Worker     }
423*d57664e9SAndroid Build Coastguard Worker 
424*d57664e9SAndroid Build Coastguard Worker     if ((off64_t) (offset + length) > fileLength) {
425*d57664e9SAndroid Build Coastguard Worker         ALOGD("start (%ld) + len (%ld) > end (%ld)\n",
426*d57664e9SAndroid Build Coastguard Worker             (long) offset, (long) length, (long) fileLength);
427*d57664e9SAndroid Build Coastguard Worker         return BAD_INDEX;
428*d57664e9SAndroid Build Coastguard Worker     }
429*d57664e9SAndroid Build Coastguard Worker 
430*d57664e9SAndroid Build Coastguard Worker     /* after fdopen, the fd will be closed on fclose() */
431*d57664e9SAndroid Build Coastguard Worker     mFp = fdopen(fd, "rb");
432*d57664e9SAndroid Build Coastguard Worker     if (mFp == NULL)
433*d57664e9SAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
434*d57664e9SAndroid Build Coastguard Worker 
435*d57664e9SAndroid Build Coastguard Worker     mStart = offset;
436*d57664e9SAndroid Build Coastguard Worker     mLength = length;
437*d57664e9SAndroid Build Coastguard Worker     assert(mOffset == 0);
438*d57664e9SAndroid Build Coastguard Worker 
439*d57664e9SAndroid Build Coastguard Worker     /* seek the FILE* to the start of chunk */
440*d57664e9SAndroid Build Coastguard Worker     if (fseek(mFp, mStart, SEEK_SET) != 0) {
441*d57664e9SAndroid Build Coastguard Worker         assert(false);
442*d57664e9SAndroid Build Coastguard Worker     }
443*d57664e9SAndroid Build Coastguard Worker 
444*d57664e9SAndroid Build Coastguard Worker     mFileName = fileName != NULL ? strdup(fileName) : NULL;
445*d57664e9SAndroid Build Coastguard Worker 
446*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
447*d57664e9SAndroid Build Coastguard Worker }
448*d57664e9SAndroid Build Coastguard Worker 
449*d57664e9SAndroid Build Coastguard Worker /*
450*d57664e9SAndroid Build Coastguard Worker  * Create the chunk from the map.
451*d57664e9SAndroid Build Coastguard Worker  */
openChunk(incfs::IncFsFileMap && dataMap,base::unique_fd fd)452*d57664e9SAndroid Build Coastguard Worker status_t _FileAsset::openChunk(incfs::IncFsFileMap&& dataMap, base::unique_fd fd)
453*d57664e9SAndroid Build Coastguard Worker {
454*d57664e9SAndroid Build Coastguard Worker     assert(mFp == NULL);    // no reopen
455*d57664e9SAndroid Build Coastguard Worker     assert(!mMap.has_value());
456*d57664e9SAndroid Build Coastguard Worker     assert(dataMap != NULL);
457*d57664e9SAndroid Build Coastguard Worker 
458*d57664e9SAndroid Build Coastguard Worker     mMap = std::move(dataMap);
459*d57664e9SAndroid Build Coastguard Worker     mStart = -1;            // not used
460*d57664e9SAndroid Build Coastguard Worker     mLength = mMap->length();
461*d57664e9SAndroid Build Coastguard Worker     mFd = std::move(fd);
462*d57664e9SAndroid Build Coastguard Worker     assert(mOffset == 0);
463*d57664e9SAndroid Build Coastguard Worker 
464*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
465*d57664e9SAndroid Build Coastguard Worker }
466*d57664e9SAndroid Build Coastguard Worker 
467*d57664e9SAndroid Build Coastguard Worker /*
468*d57664e9SAndroid Build Coastguard Worker  * Read a chunk of data.
469*d57664e9SAndroid Build Coastguard Worker  */
read(void * buf,size_t count)470*d57664e9SAndroid Build Coastguard Worker ssize_t _FileAsset::read(void* buf, size_t count)
471*d57664e9SAndroid Build Coastguard Worker {
472*d57664e9SAndroid Build Coastguard Worker     size_t maxLen;
473*d57664e9SAndroid Build Coastguard Worker     size_t actual;
474*d57664e9SAndroid Build Coastguard Worker 
475*d57664e9SAndroid Build Coastguard Worker     assert(mOffset >= 0 && mOffset <= mLength);
476*d57664e9SAndroid Build Coastguard Worker 
477*d57664e9SAndroid Build Coastguard Worker     if (getAccessMode() == ACCESS_BUFFER) {
478*d57664e9SAndroid Build Coastguard Worker         /*
479*d57664e9SAndroid Build Coastguard Worker          * On first access, read or map the entire file.  The caller has
480*d57664e9SAndroid Build Coastguard Worker          * requested buffer access, either because they're going to be
481*d57664e9SAndroid Build Coastguard Worker          * using the buffer or because what they're doing has appropriate
482*d57664e9SAndroid Build Coastguard Worker          * performance needs and access patterns.
483*d57664e9SAndroid Build Coastguard Worker          */
484*d57664e9SAndroid Build Coastguard Worker         if (mBuf == NULL)
485*d57664e9SAndroid Build Coastguard Worker             getBuffer(false);
486*d57664e9SAndroid Build Coastguard Worker     }
487*d57664e9SAndroid Build Coastguard Worker 
488*d57664e9SAndroid Build Coastguard Worker     /* adjust count if we're near EOF */
489*d57664e9SAndroid Build Coastguard Worker     maxLen = mLength - mOffset;
490*d57664e9SAndroid Build Coastguard Worker     if (count > maxLen)
491*d57664e9SAndroid Build Coastguard Worker         count = maxLen;
492*d57664e9SAndroid Build Coastguard Worker 
493*d57664e9SAndroid Build Coastguard Worker     if (!count)
494*d57664e9SAndroid Build Coastguard Worker         return 0;
495*d57664e9SAndroid Build Coastguard Worker 
496*d57664e9SAndroid Build Coastguard Worker     if (mMap.has_value()) {
497*d57664e9SAndroid Build Coastguard Worker         /* copy from mapped area */
498*d57664e9SAndroid Build Coastguard Worker         //printf("map read\n");
499*d57664e9SAndroid Build Coastguard Worker         const auto readPos = mMap->data().offset(mOffset).convert<char>();
500*d57664e9SAndroid Build Coastguard Worker         if (!readPos.verify(count)) {
501*d57664e9SAndroid Build Coastguard Worker             return -1;
502*d57664e9SAndroid Build Coastguard Worker         }
503*d57664e9SAndroid Build Coastguard Worker 
504*d57664e9SAndroid Build Coastguard Worker         memcpy(buf, readPos.unsafe_ptr(), count);
505*d57664e9SAndroid Build Coastguard Worker         actual = count;
506*d57664e9SAndroid Build Coastguard Worker     } else if (mBuf != NULL) {
507*d57664e9SAndroid Build Coastguard Worker         /* copy from buffer */
508*d57664e9SAndroid Build Coastguard Worker         //printf("buf read\n");
509*d57664e9SAndroid Build Coastguard Worker         memcpy(buf, (char*)mBuf + mOffset, count);
510*d57664e9SAndroid Build Coastguard Worker         actual = count;
511*d57664e9SAndroid Build Coastguard Worker     } else {
512*d57664e9SAndroid Build Coastguard Worker         /* read from the file */
513*d57664e9SAndroid Build Coastguard Worker         //printf("file read\n");
514*d57664e9SAndroid Build Coastguard Worker         if (ftell(mFp) != mStart + mOffset) {
515*d57664e9SAndroid Build Coastguard Worker             ALOGE("Hosed: %ld != %ld+%ld\n",
516*d57664e9SAndroid Build Coastguard Worker                 ftell(mFp), (long) mStart, (long) mOffset);
517*d57664e9SAndroid Build Coastguard Worker             assert(false);
518*d57664e9SAndroid Build Coastguard Worker         }
519*d57664e9SAndroid Build Coastguard Worker 
520*d57664e9SAndroid Build Coastguard Worker         /*
521*d57664e9SAndroid Build Coastguard Worker          * This returns 0 on error or eof.  We need to use ferror() or feof()
522*d57664e9SAndroid Build Coastguard Worker          * to tell the difference, but we don't currently have those on the
523*d57664e9SAndroid Build Coastguard Worker          * device.  However, we know how much data is *supposed* to be in the
524*d57664e9SAndroid Build Coastguard Worker          * file, so if we don't read the full amount we know something is
525*d57664e9SAndroid Build Coastguard Worker          * hosed.
526*d57664e9SAndroid Build Coastguard Worker          */
527*d57664e9SAndroid Build Coastguard Worker         actual = fread(buf, 1, count, mFp);
528*d57664e9SAndroid Build Coastguard Worker         if (actual == 0)        // something failed -- I/O error?
529*d57664e9SAndroid Build Coastguard Worker             return -1;
530*d57664e9SAndroid Build Coastguard Worker 
531*d57664e9SAndroid Build Coastguard Worker         assert(actual == count);
532*d57664e9SAndroid Build Coastguard Worker     }
533*d57664e9SAndroid Build Coastguard Worker 
534*d57664e9SAndroid Build Coastguard Worker     mOffset += actual;
535*d57664e9SAndroid Build Coastguard Worker     return actual;
536*d57664e9SAndroid Build Coastguard Worker }
537*d57664e9SAndroid Build Coastguard Worker 
538*d57664e9SAndroid Build Coastguard Worker /*
539*d57664e9SAndroid Build Coastguard Worker  * Seek to a new position.
540*d57664e9SAndroid Build Coastguard Worker  */
seek(off64_t offset,int whence)541*d57664e9SAndroid Build Coastguard Worker off64_t _FileAsset::seek(off64_t offset, int whence)
542*d57664e9SAndroid Build Coastguard Worker {
543*d57664e9SAndroid Build Coastguard Worker     off64_t newPosn;
544*d57664e9SAndroid Build Coastguard Worker     off64_t actualOffset;
545*d57664e9SAndroid Build Coastguard Worker 
546*d57664e9SAndroid Build Coastguard Worker     // compute new position within chunk
547*d57664e9SAndroid Build Coastguard Worker     newPosn = handleSeek(offset, whence, mOffset, mLength);
548*d57664e9SAndroid Build Coastguard Worker     if (newPosn == (off64_t) -1)
549*d57664e9SAndroid Build Coastguard Worker         return newPosn;
550*d57664e9SAndroid Build Coastguard Worker 
551*d57664e9SAndroid Build Coastguard Worker     actualOffset = mStart + newPosn;
552*d57664e9SAndroid Build Coastguard Worker 
553*d57664e9SAndroid Build Coastguard Worker     if (mFp != NULL) {
554*d57664e9SAndroid Build Coastguard Worker         if (fseek(mFp, (long) actualOffset, SEEK_SET) != 0)
555*d57664e9SAndroid Build Coastguard Worker             return (off64_t) -1;
556*d57664e9SAndroid Build Coastguard Worker     }
557*d57664e9SAndroid Build Coastguard Worker 
558*d57664e9SAndroid Build Coastguard Worker     mOffset = actualOffset - mStart;
559*d57664e9SAndroid Build Coastguard Worker     return mOffset;
560*d57664e9SAndroid Build Coastguard Worker }
561*d57664e9SAndroid Build Coastguard Worker 
562*d57664e9SAndroid Build Coastguard Worker /*
563*d57664e9SAndroid Build Coastguard Worker  * Close the asset.
564*d57664e9SAndroid Build Coastguard Worker  */
close(void)565*d57664e9SAndroid Build Coastguard Worker void _FileAsset::close(void)
566*d57664e9SAndroid Build Coastguard Worker {
567*d57664e9SAndroid Build Coastguard Worker     if (mBuf != NULL) {
568*d57664e9SAndroid Build Coastguard Worker         delete[] mBuf;
569*d57664e9SAndroid Build Coastguard Worker         mBuf = NULL;
570*d57664e9SAndroid Build Coastguard Worker     }
571*d57664e9SAndroid Build Coastguard Worker 
572*d57664e9SAndroid Build Coastguard Worker     if (mFileName != NULL) {
573*d57664e9SAndroid Build Coastguard Worker         free(mFileName);
574*d57664e9SAndroid Build Coastguard Worker         mFileName = NULL;
575*d57664e9SAndroid Build Coastguard Worker     }
576*d57664e9SAndroid Build Coastguard Worker 
577*d57664e9SAndroid Build Coastguard Worker     if (mFp != NULL) {
578*d57664e9SAndroid Build Coastguard Worker         // can only be NULL when called from destructor
579*d57664e9SAndroid Build Coastguard Worker         // (otherwise we would never return this object)
580*d57664e9SAndroid Build Coastguard Worker         fclose(mFp);
581*d57664e9SAndroid Build Coastguard Worker         mFp = NULL;
582*d57664e9SAndroid Build Coastguard Worker     }
583*d57664e9SAndroid Build Coastguard Worker }
584*d57664e9SAndroid Build Coastguard Worker 
585*d57664e9SAndroid Build Coastguard Worker /*
586*d57664e9SAndroid Build Coastguard Worker  * Return a read-only pointer to a buffer.
587*d57664e9SAndroid Build Coastguard Worker  *
588*d57664e9SAndroid Build Coastguard Worker  * We can either read the whole thing in or map the relevant piece of
589*d57664e9SAndroid Build Coastguard Worker  * the source file.  Ideally a map would be established at a higher
590*d57664e9SAndroid Build Coastguard Worker  * level and we'd be using a different object, but we didn't, so we
591*d57664e9SAndroid Build Coastguard Worker  * deal with it here.
592*d57664e9SAndroid Build Coastguard Worker  */
getBuffer(bool aligned)593*d57664e9SAndroid Build Coastguard Worker const void* _FileAsset::getBuffer(bool aligned)
594*d57664e9SAndroid Build Coastguard Worker {
595*d57664e9SAndroid Build Coastguard Worker     auto buffer = getIncFsBuffer(aligned);
596*d57664e9SAndroid Build Coastguard Worker     if (mBuf != NULL)
597*d57664e9SAndroid Build Coastguard Worker         return mBuf;
598*d57664e9SAndroid Build Coastguard Worker     if (!buffer.convert<uint8_t>().verify(mLength))
599*d57664e9SAndroid Build Coastguard Worker         return NULL;
600*d57664e9SAndroid Build Coastguard Worker     return buffer.unsafe_ptr();
601*d57664e9SAndroid Build Coastguard Worker }
602*d57664e9SAndroid Build Coastguard Worker 
getIncFsBuffer(bool aligned)603*d57664e9SAndroid Build Coastguard Worker incfs::map_ptr<void> _FileAsset::getIncFsBuffer(bool aligned)
604*d57664e9SAndroid Build Coastguard Worker {
605*d57664e9SAndroid Build Coastguard Worker     /* subsequent requests just use what we did previously */
606*d57664e9SAndroid Build Coastguard Worker     if (mBuf != NULL)
607*d57664e9SAndroid Build Coastguard Worker         return mBuf;
608*d57664e9SAndroid Build Coastguard Worker     if (mMap.has_value()) {
609*d57664e9SAndroid Build Coastguard Worker         if (!aligned) {
610*d57664e9SAndroid Build Coastguard Worker             return mMap->data();
611*d57664e9SAndroid Build Coastguard Worker         }
612*d57664e9SAndroid Build Coastguard Worker         return ensureAlignment(*mMap);
613*d57664e9SAndroid Build Coastguard Worker     }
614*d57664e9SAndroid Build Coastguard Worker 
615*d57664e9SAndroid Build Coastguard Worker     assert(mFp != NULL);
616*d57664e9SAndroid Build Coastguard Worker 
617*d57664e9SAndroid Build Coastguard Worker     if (mLength < kReadVsMapThreshold) {
618*d57664e9SAndroid Build Coastguard Worker         unsigned char* buf;
619*d57664e9SAndroid Build Coastguard Worker         long allocLen;
620*d57664e9SAndroid Build Coastguard Worker 
621*d57664e9SAndroid Build Coastguard Worker         /* zero-length files are allowed; not sure about zero-len allocs */
622*d57664e9SAndroid Build Coastguard Worker         /* (works fine with gcc + x86linux) */
623*d57664e9SAndroid Build Coastguard Worker         allocLen = mLength;
624*d57664e9SAndroid Build Coastguard Worker         if (mLength == 0)
625*d57664e9SAndroid Build Coastguard Worker             allocLen = 1;
626*d57664e9SAndroid Build Coastguard Worker 
627*d57664e9SAndroid Build Coastguard Worker         buf = new unsigned char[allocLen];
628*d57664e9SAndroid Build Coastguard Worker         if (buf == NULL) {
629*d57664e9SAndroid Build Coastguard Worker             ALOGE("alloc of %ld bytes failed\n", (long) allocLen);
630*d57664e9SAndroid Build Coastguard Worker             return NULL;
631*d57664e9SAndroid Build Coastguard Worker         }
632*d57664e9SAndroid Build Coastguard Worker 
633*d57664e9SAndroid Build Coastguard Worker         ALOGV("Asset %p allocating buffer size %d (smaller than threshold)", this, (int)allocLen);
634*d57664e9SAndroid Build Coastguard Worker         if (mLength > 0) {
635*d57664e9SAndroid Build Coastguard Worker             long oldPosn = ftell(mFp);
636*d57664e9SAndroid Build Coastguard Worker             fseek(mFp, mStart, SEEK_SET);
637*d57664e9SAndroid Build Coastguard Worker             if (fread(buf, 1, mLength, mFp) != (size_t) mLength) {
638*d57664e9SAndroid Build Coastguard Worker                 ALOGE("failed reading %ld bytes\n", (long) mLength);
639*d57664e9SAndroid Build Coastguard Worker                 delete[] buf;
640*d57664e9SAndroid Build Coastguard Worker                 return NULL;
641*d57664e9SAndroid Build Coastguard Worker             }
642*d57664e9SAndroid Build Coastguard Worker             fseek(mFp, oldPosn, SEEK_SET);
643*d57664e9SAndroid Build Coastguard Worker         }
644*d57664e9SAndroid Build Coastguard Worker 
645*d57664e9SAndroid Build Coastguard Worker         ALOGV(" getBuffer: loaded into buffer\n");
646*d57664e9SAndroid Build Coastguard Worker 
647*d57664e9SAndroid Build Coastguard Worker         mBuf = buf;
648*d57664e9SAndroid Build Coastguard Worker         return mBuf;
649*d57664e9SAndroid Build Coastguard Worker     } else {
650*d57664e9SAndroid Build Coastguard Worker         incfs::IncFsFileMap map;
651*d57664e9SAndroid Build Coastguard Worker         if (!map.Create(fileno(mFp), mStart, mLength, NULL /* file_name */ )) {
652*d57664e9SAndroid Build Coastguard Worker             return NULL;
653*d57664e9SAndroid Build Coastguard Worker         }
654*d57664e9SAndroid Build Coastguard Worker 
655*d57664e9SAndroid Build Coastguard Worker         ALOGV(" getBuffer: mapped\n");
656*d57664e9SAndroid Build Coastguard Worker 
657*d57664e9SAndroid Build Coastguard Worker         mMap = std::move(map);
658*d57664e9SAndroid Build Coastguard Worker         if (!aligned) {
659*d57664e9SAndroid Build Coastguard Worker             return mMap->data();
660*d57664e9SAndroid Build Coastguard Worker         }
661*d57664e9SAndroid Build Coastguard Worker         return ensureAlignment(*mMap);
662*d57664e9SAndroid Build Coastguard Worker     }
663*d57664e9SAndroid Build Coastguard Worker }
664*d57664e9SAndroid Build Coastguard Worker 
openFileDescriptor(off64_t * outStart,off64_t * outLength) const665*d57664e9SAndroid Build Coastguard Worker int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const
666*d57664e9SAndroid Build Coastguard Worker {
667*d57664e9SAndroid Build Coastguard Worker     if (mMap.has_value()) {
668*d57664e9SAndroid Build Coastguard Worker         if (mFd.ok()) {
669*d57664e9SAndroid Build Coastguard Worker             *outStart = mMap->offset();
670*d57664e9SAndroid Build Coastguard Worker             *outLength = mMap->length();
671*d57664e9SAndroid Build Coastguard Worker             const int fd = dup(mFd);
672*d57664e9SAndroid Build Coastguard Worker             if (fd < 0) {
673*d57664e9SAndroid Build Coastguard Worker                 ALOGE("Unable to dup fd (%d).", mFd.get());
674*d57664e9SAndroid Build Coastguard Worker                 return -1;
675*d57664e9SAndroid Build Coastguard Worker             }
676*d57664e9SAndroid Build Coastguard Worker             lseek64(fd, 0, SEEK_SET);
677*d57664e9SAndroid Build Coastguard Worker             return fd;
678*d57664e9SAndroid Build Coastguard Worker         }
679*d57664e9SAndroid Build Coastguard Worker         const char* fname = mMap->file_name();
680*d57664e9SAndroid Build Coastguard Worker         if (fname == NULL) {
681*d57664e9SAndroid Build Coastguard Worker             fname = mFileName;
682*d57664e9SAndroid Build Coastguard Worker         }
683*d57664e9SAndroid Build Coastguard Worker         if (fname == NULL) {
684*d57664e9SAndroid Build Coastguard Worker             return -1;
685*d57664e9SAndroid Build Coastguard Worker         }
686*d57664e9SAndroid Build Coastguard Worker         *outStart = mMap->offset();
687*d57664e9SAndroid Build Coastguard Worker         *outLength = mMap->length();
688*d57664e9SAndroid Build Coastguard Worker         return open(fname, O_RDONLY | O_BINARY);
689*d57664e9SAndroid Build Coastguard Worker     }
690*d57664e9SAndroid Build Coastguard Worker     if (mFileName == NULL) {
691*d57664e9SAndroid Build Coastguard Worker         return -1;
692*d57664e9SAndroid Build Coastguard Worker     }
693*d57664e9SAndroid Build Coastguard Worker     *outStart = mStart;
694*d57664e9SAndroid Build Coastguard Worker     *outLength = mLength;
695*d57664e9SAndroid Build Coastguard Worker     return open(mFileName, O_RDONLY | O_BINARY);
696*d57664e9SAndroid Build Coastguard Worker }
697*d57664e9SAndroid Build Coastguard Worker 
ensureAlignment(const incfs::IncFsFileMap & map)698*d57664e9SAndroid Build Coastguard Worker incfs::map_ptr<void> _FileAsset::ensureAlignment(const incfs::IncFsFileMap& map)
699*d57664e9SAndroid Build Coastguard Worker {
700*d57664e9SAndroid Build Coastguard Worker     const auto data = map.data();
701*d57664e9SAndroid Build Coastguard Worker     if (util::IsFourByteAligned(data)) {
702*d57664e9SAndroid Build Coastguard Worker         // We can return this directly if it is aligned on a word
703*d57664e9SAndroid Build Coastguard Worker         // boundary.
704*d57664e9SAndroid Build Coastguard Worker         ALOGV("Returning aligned FileAsset %p (%s).", this,
705*d57664e9SAndroid Build Coastguard Worker                 getAssetSource());
706*d57664e9SAndroid Build Coastguard Worker         return data;
707*d57664e9SAndroid Build Coastguard Worker     }
708*d57664e9SAndroid Build Coastguard Worker 
709*d57664e9SAndroid Build Coastguard Worker      if (!data.convert<uint8_t>().verify(mLength)) {
710*d57664e9SAndroid Build Coastguard Worker         return NULL;
711*d57664e9SAndroid Build Coastguard Worker     }
712*d57664e9SAndroid Build Coastguard Worker 
713*d57664e9SAndroid Build Coastguard Worker     // If not aligned on a word boundary, then we need to copy it into
714*d57664e9SAndroid Build Coastguard Worker     // our own buffer.
715*d57664e9SAndroid Build Coastguard Worker     ALOGV("Copying FileAsset %p (%s) to buffer size %d to make it aligned.", this,
716*d57664e9SAndroid Build Coastguard Worker             getAssetSource(), (int)mLength);
717*d57664e9SAndroid Build Coastguard Worker     unsigned char* buf = new unsigned char[mLength];
718*d57664e9SAndroid Build Coastguard Worker     if (buf == NULL) {
719*d57664e9SAndroid Build Coastguard Worker         ALOGE("alloc of %ld bytes failed\n", (long) mLength);
720*d57664e9SAndroid Build Coastguard Worker         return NULL;
721*d57664e9SAndroid Build Coastguard Worker     }
722*d57664e9SAndroid Build Coastguard Worker 
723*d57664e9SAndroid Build Coastguard Worker     memcpy(buf, data.unsafe_ptr(), mLength);
724*d57664e9SAndroid Build Coastguard Worker     mBuf = buf;
725*d57664e9SAndroid Build Coastguard Worker     return buf;
726*d57664e9SAndroid Build Coastguard Worker }
727*d57664e9SAndroid Build Coastguard Worker 
728*d57664e9SAndroid Build Coastguard Worker /*
729*d57664e9SAndroid Build Coastguard Worker  * ===========================================================================
730*d57664e9SAndroid Build Coastguard Worker  *      _CompressedAsset
731*d57664e9SAndroid Build Coastguard Worker  * ===========================================================================
732*d57664e9SAndroid Build Coastguard Worker  */
733*d57664e9SAndroid Build Coastguard Worker 
734*d57664e9SAndroid Build Coastguard Worker /*
735*d57664e9SAndroid Build Coastguard Worker  * Constructor.
736*d57664e9SAndroid Build Coastguard Worker  */
_CompressedAsset(void)737*d57664e9SAndroid Build Coastguard Worker _CompressedAsset::_CompressedAsset(void)
738*d57664e9SAndroid Build Coastguard Worker     : mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0),
739*d57664e9SAndroid Build Coastguard Worker       mFd(-1), mZipInflater(NULL), mBuf(NULL)
740*d57664e9SAndroid Build Coastguard Worker {
741*d57664e9SAndroid Build Coastguard Worker     // Register the Asset with the global list here after it is fully constructed and its
742*d57664e9SAndroid Build Coastguard Worker     // vtable pointer points to this concrete type. b/31113965
743*d57664e9SAndroid Build Coastguard Worker     registerAsset(this);
744*d57664e9SAndroid Build Coastguard Worker }
745*d57664e9SAndroid Build Coastguard Worker 
746*d57664e9SAndroid Build Coastguard Worker /*
747*d57664e9SAndroid Build Coastguard Worker  * Destructor.  Release resources.
748*d57664e9SAndroid Build Coastguard Worker  */
~_CompressedAsset(void)749*d57664e9SAndroid Build Coastguard Worker _CompressedAsset::~_CompressedAsset(void)
750*d57664e9SAndroid Build Coastguard Worker {
751*d57664e9SAndroid Build Coastguard Worker     close();
752*d57664e9SAndroid Build Coastguard Worker 
753*d57664e9SAndroid Build Coastguard Worker     // Unregister the Asset from the global list here before it is destructed and while its vtable
754*d57664e9SAndroid Build Coastguard Worker     // pointer still points to this concrete type. b/31113965
755*d57664e9SAndroid Build Coastguard Worker     unregisterAsset(this);
756*d57664e9SAndroid Build Coastguard Worker }
757*d57664e9SAndroid Build Coastguard Worker 
758*d57664e9SAndroid Build Coastguard Worker /*
759*d57664e9SAndroid Build Coastguard Worker  * Open a chunk of compressed data inside a file.
760*d57664e9SAndroid Build Coastguard Worker  *
761*d57664e9SAndroid Build Coastguard Worker  * This currently just sets up some values and returns.  On the first
762*d57664e9SAndroid Build Coastguard Worker  * read, we expand the entire file into a buffer and return data from it.
763*d57664e9SAndroid Build Coastguard Worker  */
openChunk(int fd,off64_t offset,int compressionMethod,size_t uncompressedLen,size_t compressedLen)764*d57664e9SAndroid Build Coastguard Worker status_t _CompressedAsset::openChunk(int fd, off64_t offset,
765*d57664e9SAndroid Build Coastguard Worker     int compressionMethod, size_t uncompressedLen, size_t compressedLen)
766*d57664e9SAndroid Build Coastguard Worker {
767*d57664e9SAndroid Build Coastguard Worker     assert(mFd < 0);        // no re-open
768*d57664e9SAndroid Build Coastguard Worker     assert(!mMap.has_value());
769*d57664e9SAndroid Build Coastguard Worker     assert(fd >= 0);
770*d57664e9SAndroid Build Coastguard Worker     assert(offset >= 0);
771*d57664e9SAndroid Build Coastguard Worker     assert(compressedLen > 0);
772*d57664e9SAndroid Build Coastguard Worker 
773*d57664e9SAndroid Build Coastguard Worker     if (compressionMethod != ZipFileRO::kCompressDeflated) {
774*d57664e9SAndroid Build Coastguard Worker         assert(false);
775*d57664e9SAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
776*d57664e9SAndroid Build Coastguard Worker     }
777*d57664e9SAndroid Build Coastguard Worker 
778*d57664e9SAndroid Build Coastguard Worker     mStart = offset;
779*d57664e9SAndroid Build Coastguard Worker     mCompressedLen = compressedLen;
780*d57664e9SAndroid Build Coastguard Worker     mUncompressedLen = uncompressedLen;
781*d57664e9SAndroid Build Coastguard Worker     assert(mOffset == 0);
782*d57664e9SAndroid Build Coastguard Worker     mFd = fd;
783*d57664e9SAndroid Build Coastguard Worker     assert(mBuf == NULL);
784*d57664e9SAndroid Build Coastguard Worker 
785*d57664e9SAndroid Build Coastguard Worker     if (uncompressedLen > StreamingZipInflater::OUTPUT_CHUNK_SIZE) {
786*d57664e9SAndroid Build Coastguard Worker         mZipInflater = new StreamingZipInflater(mFd, offset, uncompressedLen, compressedLen);
787*d57664e9SAndroid Build Coastguard Worker     }
788*d57664e9SAndroid Build Coastguard Worker 
789*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
790*d57664e9SAndroid Build Coastguard Worker }
791*d57664e9SAndroid Build Coastguard Worker 
792*d57664e9SAndroid Build Coastguard Worker /*
793*d57664e9SAndroid Build Coastguard Worker  * Open a chunk of compressed data in a mapped region.
794*d57664e9SAndroid Build Coastguard Worker  *
795*d57664e9SAndroid Build Coastguard Worker  * Nothing is expanded until the first read call.
796*d57664e9SAndroid Build Coastguard Worker  */
openChunk(incfs::IncFsFileMap && dataMap,size_t uncompressedLen)797*d57664e9SAndroid Build Coastguard Worker status_t _CompressedAsset::openChunk(incfs::IncFsFileMap&& dataMap, size_t uncompressedLen)
798*d57664e9SAndroid Build Coastguard Worker {
799*d57664e9SAndroid Build Coastguard Worker     assert(mFd < 0);        // no re-open
800*d57664e9SAndroid Build Coastguard Worker     assert(!mMap.has_value());
801*d57664e9SAndroid Build Coastguard Worker     assert(dataMap != NULL);
802*d57664e9SAndroid Build Coastguard Worker 
803*d57664e9SAndroid Build Coastguard Worker     mMap = std::move(dataMap);
804*d57664e9SAndroid Build Coastguard Worker     mStart = -1;        // not used
805*d57664e9SAndroid Build Coastguard Worker     mCompressedLen = mMap->length();
806*d57664e9SAndroid Build Coastguard Worker     mUncompressedLen = uncompressedLen;
807*d57664e9SAndroid Build Coastguard Worker     assert(mOffset == 0);
808*d57664e9SAndroid Build Coastguard Worker 
809*d57664e9SAndroid Build Coastguard Worker     if (uncompressedLen > StreamingZipInflater::OUTPUT_CHUNK_SIZE) {
810*d57664e9SAndroid Build Coastguard Worker         mZipInflater = new StreamingZipInflater(&(*mMap), uncompressedLen);
811*d57664e9SAndroid Build Coastguard Worker     }
812*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
813*d57664e9SAndroid Build Coastguard Worker }
814*d57664e9SAndroid Build Coastguard Worker 
815*d57664e9SAndroid Build Coastguard Worker /*
816*d57664e9SAndroid Build Coastguard Worker  * Read data from a chunk of compressed data.
817*d57664e9SAndroid Build Coastguard Worker  *
818*d57664e9SAndroid Build Coastguard Worker  * [For now, that's just copying data out of a buffer.]
819*d57664e9SAndroid Build Coastguard Worker  */
read(void * buf,size_t count)820*d57664e9SAndroid Build Coastguard Worker ssize_t _CompressedAsset::read(void* buf, size_t count)
821*d57664e9SAndroid Build Coastguard Worker {
822*d57664e9SAndroid Build Coastguard Worker     size_t maxLen;
823*d57664e9SAndroid Build Coastguard Worker     size_t actual;
824*d57664e9SAndroid Build Coastguard Worker 
825*d57664e9SAndroid Build Coastguard Worker     assert(mOffset >= 0 && mOffset <= mUncompressedLen);
826*d57664e9SAndroid Build Coastguard Worker 
827*d57664e9SAndroid Build Coastguard Worker     /* If we're relying on a streaming inflater, go through that */
828*d57664e9SAndroid Build Coastguard Worker     if (mZipInflater) {
829*d57664e9SAndroid Build Coastguard Worker         actual = mZipInflater->read(buf, count);
830*d57664e9SAndroid Build Coastguard Worker     } else {
831*d57664e9SAndroid Build Coastguard Worker         if (mBuf == NULL) {
832*d57664e9SAndroid Build Coastguard Worker             if (getBuffer(false) == NULL)
833*d57664e9SAndroid Build Coastguard Worker                 return -1;
834*d57664e9SAndroid Build Coastguard Worker         }
835*d57664e9SAndroid Build Coastguard Worker         assert(mBuf != NULL);
836*d57664e9SAndroid Build Coastguard Worker 
837*d57664e9SAndroid Build Coastguard Worker         /* adjust count if we're near EOF */
838*d57664e9SAndroid Build Coastguard Worker         maxLen = mUncompressedLen - mOffset;
839*d57664e9SAndroid Build Coastguard Worker         if (count > maxLen)
840*d57664e9SAndroid Build Coastguard Worker             count = maxLen;
841*d57664e9SAndroid Build Coastguard Worker 
842*d57664e9SAndroid Build Coastguard Worker         if (!count)
843*d57664e9SAndroid Build Coastguard Worker             return 0;
844*d57664e9SAndroid Build Coastguard Worker 
845*d57664e9SAndroid Build Coastguard Worker         /* copy from buffer */
846*d57664e9SAndroid Build Coastguard Worker         //printf("comp buf read\n");
847*d57664e9SAndroid Build Coastguard Worker         memcpy(buf, (char*)mBuf + mOffset, count);
848*d57664e9SAndroid Build Coastguard Worker         actual = count;
849*d57664e9SAndroid Build Coastguard Worker     }
850*d57664e9SAndroid Build Coastguard Worker 
851*d57664e9SAndroid Build Coastguard Worker     mOffset += actual;
852*d57664e9SAndroid Build Coastguard Worker     return actual;
853*d57664e9SAndroid Build Coastguard Worker }
854*d57664e9SAndroid Build Coastguard Worker 
855*d57664e9SAndroid Build Coastguard Worker /*
856*d57664e9SAndroid Build Coastguard Worker  * Handle a seek request.
857*d57664e9SAndroid Build Coastguard Worker  *
858*d57664e9SAndroid Build Coastguard Worker  * If we're working in a streaming mode, this is going to be fairly
859*d57664e9SAndroid Build Coastguard Worker  * expensive, because it requires plowing through a bunch of compressed
860*d57664e9SAndroid Build Coastguard Worker  * data.
861*d57664e9SAndroid Build Coastguard Worker  */
seek(off64_t offset,int whence)862*d57664e9SAndroid Build Coastguard Worker off64_t _CompressedAsset::seek(off64_t offset, int whence)
863*d57664e9SAndroid Build Coastguard Worker {
864*d57664e9SAndroid Build Coastguard Worker     off64_t newPosn;
865*d57664e9SAndroid Build Coastguard Worker 
866*d57664e9SAndroid Build Coastguard Worker     // compute new position within chunk
867*d57664e9SAndroid Build Coastguard Worker     newPosn = handleSeek(offset, whence, mOffset, mUncompressedLen);
868*d57664e9SAndroid Build Coastguard Worker     if (newPosn == (off64_t) -1)
869*d57664e9SAndroid Build Coastguard Worker         return newPosn;
870*d57664e9SAndroid Build Coastguard Worker 
871*d57664e9SAndroid Build Coastguard Worker     if (mZipInflater) {
872*d57664e9SAndroid Build Coastguard Worker         mZipInflater->seekAbsolute(newPosn);
873*d57664e9SAndroid Build Coastguard Worker     }
874*d57664e9SAndroid Build Coastguard Worker     mOffset = newPosn;
875*d57664e9SAndroid Build Coastguard Worker     return mOffset;
876*d57664e9SAndroid Build Coastguard Worker }
877*d57664e9SAndroid Build Coastguard Worker 
878*d57664e9SAndroid Build Coastguard Worker /*
879*d57664e9SAndroid Build Coastguard Worker  * Close the asset.
880*d57664e9SAndroid Build Coastguard Worker  */
close(void)881*d57664e9SAndroid Build Coastguard Worker void _CompressedAsset::close(void)
882*d57664e9SAndroid Build Coastguard Worker {
883*d57664e9SAndroid Build Coastguard Worker     delete[] mBuf;
884*d57664e9SAndroid Build Coastguard Worker     mBuf = NULL;
885*d57664e9SAndroid Build Coastguard Worker 
886*d57664e9SAndroid Build Coastguard Worker     delete mZipInflater;
887*d57664e9SAndroid Build Coastguard Worker     mZipInflater = NULL;
888*d57664e9SAndroid Build Coastguard Worker 
889*d57664e9SAndroid Build Coastguard Worker     if (mFd > 0) {
890*d57664e9SAndroid Build Coastguard Worker         ::close(mFd);
891*d57664e9SAndroid Build Coastguard Worker         mFd = -1;
892*d57664e9SAndroid Build Coastguard Worker     }
893*d57664e9SAndroid Build Coastguard Worker }
894*d57664e9SAndroid Build Coastguard Worker 
895*d57664e9SAndroid Build Coastguard Worker /*
896*d57664e9SAndroid Build Coastguard Worker  * Get a pointer to a read-only buffer of data.
897*d57664e9SAndroid Build Coastguard Worker  *
898*d57664e9SAndroid Build Coastguard Worker  * The first time this is called, we expand the compressed data into a
899*d57664e9SAndroid Build Coastguard Worker  * buffer.
900*d57664e9SAndroid Build Coastguard Worker  */
getBuffer(bool)901*d57664e9SAndroid Build Coastguard Worker const void* _CompressedAsset::getBuffer(bool)
902*d57664e9SAndroid Build Coastguard Worker {
903*d57664e9SAndroid Build Coastguard Worker     unsigned char* buf = NULL;
904*d57664e9SAndroid Build Coastguard Worker 
905*d57664e9SAndroid Build Coastguard Worker     if (mBuf != NULL)
906*d57664e9SAndroid Build Coastguard Worker         return mBuf;
907*d57664e9SAndroid Build Coastguard Worker 
908*d57664e9SAndroid Build Coastguard Worker     /*
909*d57664e9SAndroid Build Coastguard Worker      * Allocate a buffer and read the file into it.
910*d57664e9SAndroid Build Coastguard Worker      */
911*d57664e9SAndroid Build Coastguard Worker     buf = new unsigned char[mUncompressedLen];
912*d57664e9SAndroid Build Coastguard Worker     if (buf == NULL) {
913*d57664e9SAndroid Build Coastguard Worker         ALOGW("alloc %ld bytes failed\n", (long) mUncompressedLen);
914*d57664e9SAndroid Build Coastguard Worker         goto bail;
915*d57664e9SAndroid Build Coastguard Worker     }
916*d57664e9SAndroid Build Coastguard Worker 
917*d57664e9SAndroid Build Coastguard Worker     if (mMap.has_value()) {
918*d57664e9SAndroid Build Coastguard Worker         if (!ZipUtils::inflateToBuffer(mMap->data(), buf,
919*d57664e9SAndroid Build Coastguard Worker                 mUncompressedLen, mCompressedLen))
920*d57664e9SAndroid Build Coastguard Worker             goto bail;
921*d57664e9SAndroid Build Coastguard Worker     } else {
922*d57664e9SAndroid Build Coastguard Worker         assert(mFd >= 0);
923*d57664e9SAndroid Build Coastguard Worker 
924*d57664e9SAndroid Build Coastguard Worker         /*
925*d57664e9SAndroid Build Coastguard Worker          * Seek to the start of the compressed data.
926*d57664e9SAndroid Build Coastguard Worker          */
927*d57664e9SAndroid Build Coastguard Worker         if (lseek(mFd, mStart, SEEK_SET) != mStart)
928*d57664e9SAndroid Build Coastguard Worker             goto bail;
929*d57664e9SAndroid Build Coastguard Worker 
930*d57664e9SAndroid Build Coastguard Worker         /*
931*d57664e9SAndroid Build Coastguard Worker          * Expand the data into it.
932*d57664e9SAndroid Build Coastguard Worker          */
933*d57664e9SAndroid Build Coastguard Worker         if (!ZipUtils::inflateToBuffer(mFd, buf, mUncompressedLen,
934*d57664e9SAndroid Build Coastguard Worker                 mCompressedLen))
935*d57664e9SAndroid Build Coastguard Worker             goto bail;
936*d57664e9SAndroid Build Coastguard Worker     }
937*d57664e9SAndroid Build Coastguard Worker 
938*d57664e9SAndroid Build Coastguard Worker     /*
939*d57664e9SAndroid Build Coastguard Worker      * Success - now that we have the full asset in RAM we
940*d57664e9SAndroid Build Coastguard Worker      * no longer need the streaming inflater
941*d57664e9SAndroid Build Coastguard Worker      */
942*d57664e9SAndroid Build Coastguard Worker     delete mZipInflater;
943*d57664e9SAndroid Build Coastguard Worker     mZipInflater = NULL;
944*d57664e9SAndroid Build Coastguard Worker 
945*d57664e9SAndroid Build Coastguard Worker     mBuf = buf;
946*d57664e9SAndroid Build Coastguard Worker     buf = NULL;
947*d57664e9SAndroid Build Coastguard Worker 
948*d57664e9SAndroid Build Coastguard Worker bail:
949*d57664e9SAndroid Build Coastguard Worker     delete[] buf;
950*d57664e9SAndroid Build Coastguard Worker     return mBuf;
951*d57664e9SAndroid Build Coastguard Worker }
952*d57664e9SAndroid Build Coastguard Worker 
getIncFsBuffer(bool aligned)953*d57664e9SAndroid Build Coastguard Worker incfs::map_ptr<void> _CompressedAsset::getIncFsBuffer(bool aligned) {
954*d57664e9SAndroid Build Coastguard Worker     return incfs::map_ptr<void>(getBuffer(aligned));
955*d57664e9SAndroid Build Coastguard Worker }
956