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