PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/androidfw/Asset.cpp

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