PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/androidfw/Asset.cpp

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