PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/frameworks/base/libs/androidfw/Asset.cpp

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