13344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 23344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Copyright (C) 2006 The Android Open Source Project 33344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 43344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Licensed under the Apache License, Version 2.0 (the "License"); 53344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * you may not use this file except in compliance with the License. 63344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * You may obtain a copy of the License at 73344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 83344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * http://www.apache.org/licenses/LICENSE-2.0 93344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Unless required by applicable law or agreed to in writing, software 113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * distributed under the License is distributed on an "AS IS" BASIS, 123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * See the License for the specific language governing permissions and 143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * limitations under the License. 153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian// 183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian// Access to Zip archives. 193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian// 203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#define LOG_TAG "zip" 223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 23f14d85d6fcb740930f15325611609406d658684cMathias Agopian#include <androidfw/ZipUtils.h> 243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <utils/Log.h> 253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include "ZipFile.h" 273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <zlib.h> 293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#define DEF_MEM_LEVEL 8 // normally in zutil.h? 303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 31093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien#include "zopfli/deflate.h" 32093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <memory.h> 343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <sys/stat.h> 353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <errno.h> 363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <assert.h> 373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianusing namespace android; 393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Some environments require the "b", some choke on it. 423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#define FILE_OPEN_RO "rb" 443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#define FILE_OPEN_RW "r+b" 453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#define FILE_OPEN_RW_CREATE "w+b" 463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* should live somewhere else? */ 483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatic status_t errnoToStatus(int err) 493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (err == ENOENT) 513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NAME_NOT_FOUND; 523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian else if (err == EACCES) 533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return PERMISSION_DENIED; 543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian else 553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Open a file and parse its guts. 603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::open(const char* zipFileName, int flags) 623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian bool newArchive = false; 643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(mZipFp == NULL); // no reopen 663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if ((flags & kOpenTruncate)) 683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian flags |= kOpenCreate; // trunc implies create 693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite)) 713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return INVALID_OPERATION; // not both 723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite))) 733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return INVALID_OPERATION; // not neither 743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if ((flags & kOpenCreate) && !(flags & kOpenReadWrite)) 753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return INVALID_OPERATION; // create requires write 763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (flags & kOpenTruncate) { 783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian newArchive = true; 793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } else { 803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian newArchive = (access(zipFileName, F_OK) != 0); 813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (!(flags & kOpenCreate) && newArchive) { 823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* not creating, must already exist */ 8315fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("File %s does not exist", zipFileName); 843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NAME_NOT_FOUND; 853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* open the file */ 893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian const char* openflags; 903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (flags & kOpenReadWrite) { 913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (newArchive) 923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian openflags = FILE_OPEN_RW_CREATE; 933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian else 943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian openflags = FILE_OPEN_RW; 953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } else { 963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian openflags = FILE_OPEN_RO; 973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mZipFp = fopen(zipFileName, openflags); 993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (mZipFp == NULL) { 1003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian int err = errno; 10115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("fopen failed: %d\n", err); 1023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return errnoToStatus(err); 1033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 1043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian status_t result; 1063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (!newArchive) { 1073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 1083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Load the central directory. If that fails, then this probably 1093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * isn't a Zip archive. 1103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 1113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = readCentralDir(); 1123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } else { 1133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 1143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Newly-created. The EndOfCentralDir constructor actually 1153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * sets everything to be the way we want it (all zeroes). We 1163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * set mNeedCDRewrite so that we create *something* if the 1173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * caller doesn't add any files. (We could also just unlink 1183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * the file if it's brand new and nothing was added, but that's 1193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * probably doing more than we really should -- the user might 1203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * have a need for empty zip files.) 1213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 1223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mNeedCDRewrite = true; 1233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = NO_ERROR; 1243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 1253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (flags & kOpenReadOnly) 1273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mReadOnly = true; 1283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian else 1293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(!mReadOnly); 1303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return result; 1323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 1333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 1353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Return the Nth entry in the archive. 1363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 1373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias AgopianZipEntry* ZipFile::getEntryByIndex(int idx) const 1383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 1393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (idx < 0 || idx >= (int) mEntries.size()) 1403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NULL; 1413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return mEntries[idx]; 1433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 1443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 1463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Find an entry by name. 1473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 1483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias AgopianZipEntry* ZipFile::getEntryByName(const char* fileName) const 1493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 1503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 1513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Do a stupid linear string-compare search. 1523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 1533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * There are various ways to speed this up, especially since it's rare 1543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * to intermingle changes to the archive with "get by name" calls. We 1553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * don't want to sort the mEntries vector itself, however, because 1563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * it's used to recreate the Central Directory. 1573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 1583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * (Hash table works, parallel list of pointers in sorted order is good.) 1593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 1603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian int idx; 1613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian for (idx = mEntries.size()-1; idx >= 0; idx--) { 1633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry* pEntry = mEntries[idx]; 1643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (!pEntry->getDeleted() && 1653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian strcmp(fileName, pEntry->getFileName()) == 0) 1663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian { 1673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return pEntry; 1683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 1693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 1703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NULL; 1723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 1733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 1753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Empty the mEntries vector. 1763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 1773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianvoid ZipFile::discardEntries(void) 1783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 1793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian int count = mEntries.size(); 1803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian while (--count >= 0) 1823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian delete mEntries[count]; 1833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEntries.clear(); 1853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 1863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 1893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Find the central directory and read the contents. 1903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 1913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * The fun thing about ZIP archives is that they may or may not be 1923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * readable from start to end. In some cases, notably for archives 1933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * that were written to stdout, the only length information is in the 1943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * central directory at the end of the file. 1953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 1963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Of course, the central directory can be followed by a variable-length 1973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * comment field, so we have to scan through it backwards. The comment 1983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff 1993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * itself, plus apparently sometimes people throw random junk on the end 2003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * just for the fun of it. 2013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 2023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * This is all a little wobbly. If the wrong value ends up in the EOCD 2033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * area, we're hosed. This appears to be the way that everbody handles 2043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * it though, so we're in pretty good company if this fails. 2053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 2063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::readCentralDir(void) 2073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 2083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian status_t result = NO_ERROR; 2093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian unsigned char* buf = NULL; 2103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian off_t fileLength, seekStart; 2113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian long readAmount; 2123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian int i; 2133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 2143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian fseek(mZipFp, 0, SEEK_END); 2153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian fileLength = ftell(mZipFp); 2163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian rewind(mZipFp); 2173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 2183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* too small to be a ZIP archive? */ 2193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fileLength < EndOfCentralDir::kEOCDLen) { 22015fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("Length is %ld -- too small\n", (long)fileLength); 2213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = INVALID_OPERATION; 2223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 2233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 2243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 2253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch]; 2263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (buf == NULL) { 22715fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("Failure allocating %d bytes for EOCD search", 2283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian EndOfCentralDir::kMaxEOCDSearch); 2293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = NO_MEMORY; 2303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 2313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 2323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 2333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fileLength > EndOfCentralDir::kMaxEOCDSearch) { 2343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch; 2353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian readAmount = EndOfCentralDir::kMaxEOCDSearch; 2363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } else { 2373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian seekStart = 0; 2383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian readAmount = (long) fileLength; 2393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 2403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fseek(mZipFp, seekStart, SEEK_SET) != 0) { 24115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("Failure seeking to end of zip at %ld", (long) seekStart); 2423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = UNKNOWN_ERROR; 2433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 2443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 2453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 2463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* read the last part of the file into the buffer */ 2473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) { 24815fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("short file? wanted %ld\n", readAmount); 2493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = UNKNOWN_ERROR; 2503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 2513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 2523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 2533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* find the end-of-central-dir magic */ 2543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian for (i = readAmount - 4; i >= 0; i--) { 2553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (buf[i] == 0x50 && 2563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature) 2573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian { 2582da72c6265bab1322876fa9702f7580bff7fd8beSteve Block ALOGV("+++ Found EOCD at buf+%d\n", i); 2593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian break; 2603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 2613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 2623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (i < 0) { 26315fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("EOCD not found, not Zip\n"); 2643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = INVALID_OPERATION; 2653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 2663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 2673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 2683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* extract eocd values */ 2693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = mEOCD.readBuf(buf + i, readAmount - i); 2703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (result != NO_ERROR) { 27115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("Failure reading %ld bytes of EOCD values", readAmount - i); 2723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 2733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 2743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian //mEOCD.dump(); 2753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 2763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 || 2773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mNumEntries != mEOCD.mTotalNumEntries) 2783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian { 27915fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("Archive spanning not supported\n"); 2803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = INVALID_OPERATION; 2813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 2823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 2833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 2843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 2853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * So far so good. "mCentralDirSize" is the size in bytes of the 2863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * central directory, so we can just seek back that far to find it. 2873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * We can also seek forward mCentralDirOffset bytes from the 2883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * start of the file. 2893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 2903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * We're not guaranteed to have the rest of the central dir in the 2913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * buffer, nor are we guaranteed that the central dir will have any 2923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * sort of convenient size. We need to skip to the start of it and 2933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * read the header, then the other goodies. 2943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 2953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * The only thing we really need right now is the file comment, which 2963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * we're hoping to preserve. 2973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 2983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { 29915fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("Failure seeking to central dir offset %ld\n", 3003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mCentralDirOffset); 3013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = UNKNOWN_ERROR; 3023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 3033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 3043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 3063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Loop through and read the central dir entries. 3073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 3082da72c6265bab1322876fa9702f7580bff7fd8beSteve Block ALOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries); 3093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian int entry; 3103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) { 3113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry* pEntry = new ZipEntry; 3123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = pEntry->initFromCDE(mZipFp); 3143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (result != NO_ERROR) { 31515fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("initFromCDE failed\n"); 3163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian delete pEntry; 3173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 3183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 3193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEntries.add(pEntry); 3213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 3223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 3253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * If all went well, we should now be back at the EOCD. 3263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 3273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian { 3283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian unsigned char checkBuf[4]; 3293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fread(checkBuf, 1, 4, mZipFp) != 4) { 33015fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("EOCD check read failed\n"); 3313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = INVALID_OPERATION; 3323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 3333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 3343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) { 33515fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("EOCD read check failed\n"); 3363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = UNKNOWN_ERROR; 3373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 3383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 3392da72c6265bab1322876fa9702f7580bff7fd8beSteve Block ALOGV("+++ EOCD read check passed\n"); 3403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 3413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbail: 3433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian delete[] buf; 3443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return result; 3453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 3463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 3493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Add a new file to the archive. 3503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 3513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * This requires creating and populating a ZipEntry structure, and copying 3523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * the data into the file at the appropriate position. The "appropriate 3533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * position" is the current location of the central directory, which we 3543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * casually overwrite (we can put it back later). 3553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 3563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * If we were concerned about safety, we would want to make all changes 3573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * in a temp file and then overwrite the original after everything was 3583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * safely written. Not really a concern for us. 3593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 3603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::addCommon(const char* fileName, const void* data, size_t size, 3613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian const char* storageName, int sourceType, int compressionMethod, 3623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry** ppEntry) 3633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 3643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry* pEntry = NULL; 3653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian status_t result = NO_ERROR; 3663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian long lfhPosn, startPosn, endPosn, uncompressedLen; 3673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian FILE* inputFp = NULL; 3683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian unsigned long crc; 3693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian time_t modWhen; 3703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (mReadOnly) 3723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return INVALID_OPERATION; 3733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(compressionMethod == ZipEntry::kCompressDeflated || 3753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian compressionMethod == ZipEntry::kCompressStored); 3763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* make sure we're in a reasonable state */ 3783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(mZipFp != NULL); 3793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(mEntries.size() == mEOCD.mTotalNumEntries); 3803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* make sure it doesn't already exist */ 3823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (getEntryByName(storageName) != NULL) 3833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return ALREADY_EXISTS; 3843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (!data) { 3863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian inputFp = fopen(fileName, FILE_OPEN_RO); 3873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (inputFp == NULL) 3883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return errnoToStatus(errno); 3893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 3903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { 3923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = UNKNOWN_ERROR; 3933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 3943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 3953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry = new ZipEntry; 3973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->initNew(storageName, NULL); 3983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 3993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 4003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * From here on out, failures are more interesting. 4013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 4023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mNeedCDRewrite = true; 4033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 4043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 4053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Write the LFH, even though it's still mostly blank. We need it 4063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * as a place-holder. In theory the LFH isn't necessary, but in 4073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * practice some utilities demand it. 4083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 4093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian lfhPosn = ftell(mZipFp); 4103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->mLFH.write(mZipFp); 4113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian startPosn = ftell(mZipFp); 4123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 4133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 4143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Copy the data in, possibly compressing it as we go. 4153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 4163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (sourceType == ZipEntry::kCompressStored) { 4173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (compressionMethod == ZipEntry::kCompressDeflated) { 4183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian bool failed = false; 4193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = compressFpToFp(mZipFp, inputFp, data, size, &crc); 4203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (result != NO_ERROR) { 42115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("compression failed, storing\n"); 4223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian failed = true; 4233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } else { 4243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 4253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Make sure it has compressed "enough". This probably ought 4263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * to be set through an API call, but I don't expect our 4273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * criteria to change over time. 4283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 4293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian long src = inputFp ? ftell(inputFp) : size; 4303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian long dst = ftell(mZipFp) - startPosn; 4313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (dst + (dst / 10) > src) { 43215fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("insufficient compression (src=%ld dst=%ld), storing\n", 4333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian src, dst); 4343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian failed = true; 4353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 4363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 4373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 4383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (failed) { 4393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian compressionMethod = ZipEntry::kCompressStored; 4403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (inputFp) rewind(inputFp); 4413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian fseek(mZipFp, startPosn, SEEK_SET); 4423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* fall through to kCompressStored case */ 4433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 4443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 4453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* handle "no compression" request, or failed compression from above */ 4463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (compressionMethod == ZipEntry::kCompressStored) { 4473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (inputFp) { 4483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = copyFpToFp(mZipFp, inputFp, &crc); 4493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } else { 4503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = copyDataToFp(mZipFp, data, size, &crc); 4513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 4523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (result != NO_ERROR) { 4533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian // don't need to truncate; happens in CDE rewrite 45415fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("failed copying data in\n"); 4553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 4563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 4573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 4583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 4593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian // currently seeked to end of file 4603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian uncompressedLen = inputFp ? ftell(inputFp) : size; 4613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } else if (sourceType == ZipEntry::kCompressDeflated) { 4623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* we should support uncompressed-from-compressed, but it's not 4633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * important right now */ 4643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(compressionMethod == ZipEntry::kCompressDeflated); 4653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 4663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian bool scanResult; 4673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian int method; 4683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian long compressedLen; 4693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 4703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen, 4713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian &compressedLen, &crc); 4723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (!scanResult || method != ZipEntry::kCompressDeflated) { 47315fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("this isn't a deflated gzip file?"); 4743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = UNKNOWN_ERROR; 4753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 4763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 4773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 4783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL); 4793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (result != NO_ERROR) { 48015fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("failed copying gzip data in\n"); 4813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 4823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 4833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } else { 4843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(false); 4853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = UNKNOWN_ERROR; 4863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 4873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 4883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 4893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 4903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * We could write the "Data Descriptor", but there doesn't seem to 4913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * be any point since we're going to go back and write the LFH. 4923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 4933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Update file offsets. 4943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 4953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian endPosn = ftell(mZipFp); // seeked to end of compressed data 4963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 4973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 4983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Success! Fill out new values. 4993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 5003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc, 5013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian compressionMethod); 5023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp)); 5033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->setModWhen(modWhen); 5043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->setLFHOffset(lfhPosn); 5053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mNumEntries++; 5063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mTotalNumEntries++; 5073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() 5083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mCentralDirOffset = endPosn; 5093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 5113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Go back and write the LFH. 5123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 5133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) { 5143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = UNKNOWN_ERROR; 5153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 5163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 5173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->mLFH.write(mZipFp); 5183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 5203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Add pEntry to the list. 5213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 5223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEntries.add(pEntry); 5233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (ppEntry != NULL) 5243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *ppEntry = pEntry; 5253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry = NULL; 5263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbail: 5283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (inputFp != NULL) 5293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian fclose(inputFp); 5303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian delete pEntry; 5313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return result; 5323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 5333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 5353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Add an entry by copying it from another zip file. If "padding" is 5363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * nonzero, the specified number of bytes will be added to the "extra" 5373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * field in the header. 5383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 5393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. 5403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 5413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry, 5423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian int padding, ZipEntry** ppEntry) 5433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 5443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry* pEntry = NULL; 5453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian status_t result; 5463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian long lfhPosn, endPosn; 5473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (mReadOnly) 5493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return INVALID_OPERATION; 5503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* make sure we're in a reasonable state */ 5523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(mZipFp != NULL); 5533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(mEntries.size() == mEOCD.mTotalNumEntries); 5543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { 5563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = UNKNOWN_ERROR; 5573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 5583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 5593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry = new ZipEntry; 5613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (pEntry == NULL) { 5623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = NO_MEMORY; 5633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 5643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 5653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = pEntry->initFromExternal(pSourceZip, pSourceEntry); 5673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (result != NO_ERROR) 5683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 5693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (padding != 0) { 5703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = pEntry->addPadding(padding); 5713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (result != NO_ERROR) 5723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 5733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 5743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 5763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * From here on out, failures are more interesting. 5773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 5783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mNeedCDRewrite = true; 5793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 5813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Write the LFH. Since we're not recompressing the data, we already 5823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * have all of the fields filled out. 5833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 5843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian lfhPosn = ftell(mZipFp); 5853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->mLFH.write(mZipFp); 5863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 5873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 5883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Copy the data over. 5893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 5903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * If the "has data descriptor" flag is set, we want to copy the DD 5913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * fields as well. This is a fixed-size area immediately following 5923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * the data. 5933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 5943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0) 5953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian { 5963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = UNKNOWN_ERROR; 5973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 5983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 5993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 6003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian off_t copyLen; 6013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian copyLen = pSourceEntry->getCompressedLen(); 6023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0) 6033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian copyLen += ZipEntry::kDataDescriptorLen; 6043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 6053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL) 6063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian != NO_ERROR) 6073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian { 608c0b74df335aa99e3c3f6f752de531836faa0c7c5Steve Block ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName); 6093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = UNKNOWN_ERROR; 6103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 6113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 6123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 6133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 6143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Update file offsets. 6153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 6163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian endPosn = ftell(mZipFp); 6173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 6183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 6193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Success! Fill out new values. 6203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 6213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->setLFHOffset(lfhPosn); // sets mCDE.mLocalHeaderRelOffset 6223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mNumEntries++; 6233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mTotalNumEntries++; 6243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() 6253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mCentralDirOffset = endPosn; 6263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 6273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 6283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Add pEntry to the list. 6293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 6303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEntries.add(pEntry); 6313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (ppEntry != NULL) 6323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *ppEntry = pEntry; 6333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry = NULL; 6343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 6353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = NO_ERROR; 6363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 6373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbail: 6383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian delete pEntry; 6393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return result; 6403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 6413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 6423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 643093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Add an entry by copying it from another zip file, recompressing with 644093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Zopfli if already compressed. 645093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * 646093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. 647093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien */ 648093d04c631aa2a4af3317912e9561672c5642bb8Raph Levienstatus_t ZipFile::addRecompress(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry, 649093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien ZipEntry** ppEntry) 650093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien{ 651093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien ZipEntry* pEntry = NULL; 652093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien status_t result; 653093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien long lfhPosn, startPosn, endPosn, uncompressedLen; 654093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 655093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (mReadOnly) 656093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien return INVALID_OPERATION; 657093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 658093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien /* make sure we're in a reasonable state */ 659093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien assert(mZipFp != NULL); 660093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien assert(mEntries.size() == mEOCD.mTotalNumEntries); 661093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 662093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { 663093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien result = UNKNOWN_ERROR; 664093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien goto bail; 665093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } 666093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 667093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien pEntry = new ZipEntry; 668093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (pEntry == NULL) { 669093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien result = NO_MEMORY; 670093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien goto bail; 671093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } 672093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 673093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien result = pEntry->initFromExternal(pSourceZip, pSourceEntry); 674093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (result != NO_ERROR) 675093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien goto bail; 676093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 677093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien /* 678093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * From here on out, failures are more interesting. 679093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien */ 680093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien mNeedCDRewrite = true; 681093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 682093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien /* 683093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Write the LFH, even though it's still mostly blank. We need it 684093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * as a place-holder. In theory the LFH isn't necessary, but in 685093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * practice some utilities demand it. 686093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien */ 687093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien lfhPosn = ftell(mZipFp); 688093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien pEntry->mLFH.write(mZipFp); 689093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien startPosn = ftell(mZipFp); 690093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 691093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien /* 692093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Copy the data over. 693093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * 694093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * If the "has data descriptor" flag is set, we want to copy the DD 695093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * fields as well. This is a fixed-size area immediately following 696093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * the data. 697093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien */ 698093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0) 699093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien { 700093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien result = UNKNOWN_ERROR; 701093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien goto bail; 702093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } 703093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 704093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien uncompressedLen = pSourceEntry->getUncompressedLen(); 705093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 706093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (pSourceEntry->isCompressed()) { 707093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien void *buf = pSourceZip->uncompress(pSourceEntry); 708093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (buf == NULL) { 709093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien result = NO_MEMORY; 710093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien goto bail; 711093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } 712093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien long startPosn = ftell(mZipFp); 713093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien unsigned long crc; 714093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (compressFpToFp(mZipFp, NULL, buf, uncompressedLen, &crc) != NO_ERROR) { 715093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien ALOGW("recompress of '%s' failed\n", pEntry->mCDE.mFileName); 716093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien result = UNKNOWN_ERROR; 717093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien free(buf); 718093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien goto bail; 719093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } 720093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien long endPosn = ftell(mZipFp); 721093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, 722093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien pSourceEntry->getCRC32(), ZipEntry::kCompressDeflated); 723093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien free(buf); 724093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } else { 725093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien off_t copyLen; 726093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien copyLen = pSourceEntry->getCompressedLen(); 727093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0) 728093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien copyLen += ZipEntry::kDataDescriptorLen; 729093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 730093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL) 731093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien != NO_ERROR) 732093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien { 733093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName); 734093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien result = UNKNOWN_ERROR; 735093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien goto bail; 736093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } 737093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } 738093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 739093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien /* 740093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Update file offsets. 741093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien */ 742093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien endPosn = ftell(mZipFp); 743093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 744093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien /* 745093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Success! Fill out new values. 746093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien */ 747093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien pEntry->setLFHOffset(lfhPosn); 748093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien mEOCD.mNumEntries++; 749093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien mEOCD.mTotalNumEntries++; 750093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() 751093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien mEOCD.mCentralDirOffset = endPosn; 752093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 753093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien /* 754093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Go back and write the LFH. 755093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien */ 756093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) { 757093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien result = UNKNOWN_ERROR; 758093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien goto bail; 759093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } 760093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien pEntry->mLFH.write(mZipFp); 761093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 762093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien /* 763093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Add pEntry to the list. 764093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien */ 765093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien mEntries.add(pEntry); 766093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (ppEntry != NULL) 767093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien *ppEntry = pEntry; 768093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien pEntry = NULL; 769093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 770093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien result = NO_ERROR; 771093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 772093d04c631aa2a4af3317912e9561672c5642bb8Raph Levienbail: 773093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien delete pEntry; 774093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien return result; 775093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien} 776093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 777093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien/* 7783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Copy all of the bytes in "src" to "dst". 7793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 7803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" 7813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * will be seeked immediately past the data. 7823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 7833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32) 7843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 7853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian unsigned char tmpBuf[32768]; 7863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian size_t count; 7873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 7883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *pCRC32 = crc32(0L, Z_NULL, 0); 7893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 7903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian while (1) { 7913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp); 7923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (ferror(srcFp) || ferror(dstFp)) 7933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return errnoToStatus(errno); 7943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (count == 0) 7953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian break; 7963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 7973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *pCRC32 = crc32(*pCRC32, tmpBuf, count); 7983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 7993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fwrite(tmpBuf, 1, count, dstFp) != count) { 80015fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("fwrite %d bytes failed\n", (int) count); 8013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 8023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 8033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 8043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NO_ERROR; 8063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 8073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 8093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Copy all of the bytes in "src" to "dst". 8103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 8113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * On exit, "dstFp" will be seeked immediately past the data. 8123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 8133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::copyDataToFp(FILE* dstFp, 8143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian const void* data, size_t size, unsigned long* pCRC32) 8153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 8163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian size_t count; 8173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *pCRC32 = crc32(0L, Z_NULL, 0); 8193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (size > 0) { 8203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size); 8213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fwrite(data, 1, size, dstFp) != size) { 82215fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("fwrite %d bytes failed\n", (int) size); 8233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 8243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 8253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 8263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NO_ERROR; 8283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 8293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 8313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Copy some of the bytes in "src" to "dst". 8323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 8333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * If "pCRC32" is NULL, the CRC will not be computed. 8343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 8353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" 8363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * will be seeked immediately past the data just written. 8373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 8383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length, 8393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian unsigned long* pCRC32) 8403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 8413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian unsigned char tmpBuf[32768]; 8423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian size_t count; 8433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (pCRC32 != NULL) 8453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *pCRC32 = crc32(0L, Z_NULL, 0); 8463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian while (length) { 8483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian long readSize; 8493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian readSize = sizeof(tmpBuf); 8513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (readSize > length) 8523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian readSize = length; 8533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian count = fread(tmpBuf, 1, readSize, srcFp); 8553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if ((long) count != readSize) { // error or unexpected EOF 85615fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("fread %d bytes failed\n", (int) readSize); 8573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 8583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 8593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (pCRC32 != NULL) 8613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *pCRC32 = crc32(*pCRC32, tmpBuf, count); 8623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fwrite(tmpBuf, 1, count, dstFp) != count) { 86415fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("fwrite %d bytes failed\n", (int) count); 8653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 8663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 8673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian length -= readSize; 8693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 8703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NO_ERROR; 8723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 8733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 8753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Compress all of the data in "srcFp" and write it to "dstFp". 8763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 8773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" 8783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * will be seeked immediately past the compressed data. 8793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 8803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp, 8813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian const void* data, size_t size, unsigned long* pCRC32) 8823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 8833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian status_t result = NO_ERROR; 884093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien const size_t kBufSize = 1024 * 1024; 8853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian unsigned char* inBuf = NULL; 8863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian unsigned char* outBuf = NULL; 887093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien size_t outSize = 0; 8883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian bool atEof = false; // no feof() aviailable yet 8893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian unsigned long crc; 890093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien ZopfliOptions options; 891093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien unsigned char bp = 0; 8923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 893093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien ZopfliInitOptions(&options); 8943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 8953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian crc = crc32(0L, Z_NULL, 0); 8963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 897093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (data) { 898093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien crc = crc32(crc, (const unsigned char*)data, size); 899093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien ZopfliDeflate(&options, 2, true, (const unsigned char*)data, size, &bp, 900093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien &outBuf, &outSize); 901093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } else { 902093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien /* 903093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Create an input buffer and an output buffer. 904093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien */ 905093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien inBuf = new unsigned char[kBufSize]; 906093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (inBuf == NULL) { 907093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien result = NO_MEMORY; 908093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien goto bail; 909093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } 910093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien 911093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien /* 912093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Loop while we have data. 913093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien */ 914093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien do { 915093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien size_t getSize; 916093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien getSize = fread(inBuf, 1, kBufSize, srcFp); 917093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (ferror(srcFp)) { 918093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien ALOGD("deflate read failed (errno=%d)\n", errno); 919093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien delete[] inBuf; 920093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien goto bail; 9213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 9223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (getSize < kBufSize) { 9232da72c6265bab1322876fa9702f7580bff7fd8beSteve Block ALOGV("+++ got %d bytes, EOF reached\n", 9243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian (int)getSize); 9253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian atEof = true; 9263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 9273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian crc = crc32(crc, inBuf, getSize); 929093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien ZopfliDeflate(&options, 2, atEof, inBuf, getSize, &bp, &outBuf, &outSize); 930093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } while (!atEof); 931093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien delete[] inBuf; 932093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } 9333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 934093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien ALOGV("+++ writing %d bytes\n", (int)outSize); 935093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien if (fwrite(outBuf, 1, outSize, dstFp) != outSize) { 936093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien ALOGD("write %d failed in deflate\n", (int)outSize); 937093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien goto bail; 938093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien } 9393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *pCRC32 = crc; 9413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbail: 943093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien free(outBuf); 9443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return result; 9463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 9473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 9493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Mark an entry as deleted. 9503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 9513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * We will eventually need to crunch the file down, but if several files 9523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * are being removed (perhaps as part of an "update" process) we can make 9533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * things considerably faster by deferring the removal to "flush" time. 9543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 9553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::remove(ZipEntry* pEntry) 9563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 9573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 9583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Should verify that pEntry is actually part of this archive, and 9593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * not some stray ZipEntry from a different file. 9603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 9613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* mark entry as deleted, and mark archive as dirty */ 9633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->setDeleted(); 9643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mNeedCDRewrite = true; 9653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NO_ERROR; 9663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 9673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 9693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Flush any pending writes. 9703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 9713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * In particular, this will crunch out deleted entries, and write the 9723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Central Directory and EOCD if we have stomped on them. 9733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 9743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::flush(void) 9753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 9763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian status_t result = NO_ERROR; 9773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian long eocdPosn; 9783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian int i, count; 9793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (mReadOnly) 9813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return INVALID_OPERATION; 9823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (!mNeedCDRewrite) 9833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NO_ERROR; 9843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(mZipFp != NULL); 9863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = crunchArchive(); 9883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (result != NO_ERROR) 9893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return result; 9903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) 9923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 9933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 9943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian count = mEntries.size(); 9953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian for (i = 0; i < count; i++) { 9963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry* pEntry = mEntries[i]; 9973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->mCDE.write(mZipFp); 9983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 9993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian eocdPosn = ftell(mZipFp); 10013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset; 10023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.write(mZipFp); 10043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 10063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * If we had some stuff bloat up during compression and get replaced 10073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * with plain files, or if we deleted some entries, there's a lot 10083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * of wasted space at the end of the file. Remove it now. 10093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 10103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) { 1011c0b74df335aa99e3c3f6f752de531836faa0c7c5Steve Block ALOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno)); 10123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian // not fatal 10133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 10143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* should we clear the "newly added" flag in all entries now? */ 10163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mNeedCDRewrite = false; 10183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NO_ERROR; 10193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 10203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 10223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Crunch deleted files out of an archive by shifting the later files down. 10233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 10243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Because we're not using a temp file, we do the operation inside the 10253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * current file. 10263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 10273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::crunchArchive(void) 10283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 10293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian status_t result = NO_ERROR; 10303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian int i, count; 10313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian long delCount, adjust; 10323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#if 0 10343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian printf("CONTENTS:\n"); 10353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian for (i = 0; i < (int) mEntries.size(); i++) { 10363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian printf(" %d: lfhOff=%ld del=%d\n", 10373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted()); 10383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 10393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian printf(" END is %ld\n", (long) mEOCD.mCentralDirOffset); 10403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#endif 10413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 10433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Roll through the set of files, shifting them as appropriate. We 10443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * could probably get a slight performance improvement by sliding 10453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * multiple files down at once (because we could use larger reads 10463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * when operating on batches of small files), but it's not that useful. 10473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 10483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian count = mEntries.size(); 10493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian delCount = adjust = 0; 10503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian for (i = 0; i < count; i++) { 10513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry* pEntry = mEntries[i]; 10523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian long span; 10533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (pEntry->getLFHOffset() != 0) { 10553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian long nextOffset; 10563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* Get the length of this entry by finding the offset 10583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * of the next entry. Directory entries don't have 10593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * file offsets, so we need to find the next non-directory 10603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * entry. 10613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 10623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian nextOffset = 0; 10633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian for (int ii = i+1; nextOffset == 0 && ii < count; ii++) 10643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian nextOffset = mEntries[ii]->getLFHOffset(); 10653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (nextOffset == 0) 10663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian nextOffset = mEOCD.mCentralDirOffset; 10673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian span = nextOffset - pEntry->getLFHOffset(); 10683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(span >= ZipEntry::LocalFileHeader::kLFHLen); 10703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } else { 10713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* This is a directory entry. It doesn't have 10723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * any actual file contents, so there's no need to 10733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * move anything. 10743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 10753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian span = 0; 10763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 10773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n", 10793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian // i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count); 10803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (pEntry->getDeleted()) { 10823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian adjust += span; 10833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian delCount++; 10843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian delete pEntry; 10863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEntries.removeAt(i); 10873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 10883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* adjust loop control */ 10893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian count--; 10903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian i--; 10913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } else if (span != 0 && adjust > 0) { 10923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* shuffle this entry back */ 10933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian //printf("+++ Shuffling '%s' back %ld\n", 10943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian // pEntry->getFileName(), adjust); 10953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian result = filemove(mZipFp, pEntry->getLFHOffset() - adjust, 10963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->getLFHOffset(), span); 10973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (result != NO_ERROR) { 10983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* this is why you use a temp file */ 1099ca1df5a380069163bbabc7cfed1d48829b8e135eSteve Block ALOGE("error during crunch - archive is toast\n"); 11003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return result; 11013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 11023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust); 11043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 11053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 11063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* 11083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Fix EOCD info. We have to wait until the end to do some of this 11093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * because we use mCentralDirOffset to determine "span" for the 11103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * last entry. 11113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 11123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mCentralDirOffset -= adjust; 11133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mNumEntries -= delCount; 11143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mTotalNumEntries -= delCount; 11153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() 11163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries); 11183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(mEOCD.mNumEntries == count); 11193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return result; 11213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 11223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 11243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Works like memmove(), but on pieces of a file. 11253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 11263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n) 11273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 11283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (dst == src || n <= 0) 11293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NO_ERROR; 11303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian unsigned char readBuf[32768]; 11323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (dst < src) { 11343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* shift stuff toward start of file; must read from start */ 11353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian while (n != 0) { 11363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian size_t getSize = sizeof(readBuf); 11373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (getSize > n) 11383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian getSize = n; 11393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fseek(fp, (long) src, SEEK_SET) != 0) { 114115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("filemove src seek %ld failed\n", (long) src); 11423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 11433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 11443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fread(readBuf, 1, getSize, fp) != getSize) { 114615fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("filemove read %ld off=%ld failed\n", 11473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian (long) getSize, (long) src); 11483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 11493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 11503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fseek(fp, (long) dst, SEEK_SET) != 0) { 115215fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("filemove dst seek %ld failed\n", (long) dst); 11533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 11543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 11553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fwrite(readBuf, 1, getSize, fp) != getSize) { 115715fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("filemove write %ld off=%ld failed\n", 11583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian (long) getSize, (long) dst); 11593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 11603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 11613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian src += getSize; 11633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian dst += getSize; 11643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian n -= getSize; 11653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 11663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } else { 11673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* shift stuff toward end of file; must read from end */ 11683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(false); // write this someday, maybe 11693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 11703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 11713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NO_ERROR; 11733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 11743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 11773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Get the modification time from a file descriptor. 11783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 11793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopiantime_t ZipFile::getModTime(int fd) 11803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 11813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian struct stat sb; 11823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fstat(fd, &sb) < 0) { 118415fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("HEY: fstat on fd %d failed\n", fd); 11853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return (time_t) -1; 11863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 11873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return sb.st_mtime; 11893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 11903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 11923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#if 0 /* this is a bad idea */ 11933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 11943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Get a copy of the Zip file descriptor. 11953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 11963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * We don't allow this if the file was opened read-write because we tend 11973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * to leave the file contents in an uncertain state between calls to 11983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * flush(). The duplicated file descriptor should only be valid for reads. 11993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 12003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianint ZipFile::getZipFd(void) const 12013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 12023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (!mReadOnly) 12033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return INVALID_OPERATION; 12043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(mZipFp != NULL); 12053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian int fd; 12073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian fd = dup(fileno(mZipFp)); 12083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fd < 0) { 120915fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("didn't work, errno=%d\n", errno); 12103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 12113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return fd; 12133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 12143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#endif 12153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#if 0 12183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 12193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Expand data. 12203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 12213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const 12223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 12233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return false; 12243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 12253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#endif 12263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian// free the memory when you're done 1228093d04c631aa2a4af3317912e9561672c5642bb8Raph Levienvoid* ZipFile::uncompress(const ZipEntry* entry) const 12293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 12303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian size_t unlen = entry->getUncompressedLen(); 12313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian size_t clen = entry->getCompressedLen(); 12323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian void* buf = malloc(unlen); 12343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (buf == NULL) { 12353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NULL; 12363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 12373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian fseek(mZipFp, 0, SEEK_SET); 12393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian off_t offset = entry->getFileOffset(); 12413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fseek(mZipFp, offset, SEEK_SET) != 0) { 12423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 12433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 12443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian switch (entry->getCompressionMethod()) 12463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian { 12473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian case ZipEntry::kCompressStored: { 12483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ssize_t amt = fread(buf, 1, unlen, mZipFp); 12493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (amt != (ssize_t)unlen) { 12503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 12513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 12523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#if 0 12533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian printf("data...\n"); 12543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian const unsigned char* p = (unsigned char*)buf; 12553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian const unsigned char* end = p+unlen; 12563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian for (int i=0; i<32 && p < end; i++) { 12573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian printf("0x%08x ", (int)(offset+(i*0x10))); 12583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian for (int j=0; j<0x10 && p < end; j++) { 12593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian printf(" %02x", *p); 12603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian p++; 12613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 12623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian printf("\n"); 12633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 12643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#endif 12653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 12673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian break; 12683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian case ZipEntry::kCompressDeflated: { 12693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) { 12703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 12713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 12723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 12733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian break; 12743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian default: 12753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian goto bail; 12763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 12773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return buf; 12783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbail: 12803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian free(buf); 12813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NULL; 12823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 12833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 12863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * =========================================================================== 12873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * ZipFile::EndOfCentralDir 12883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * =========================================================================== 12893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 12903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 12913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 12923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Read the end-of-central-dir fields. 12933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * 12943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * "buf" should be positioned at the EOCD signature, and should contain 12953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * the entire EOCD area including the comment. 12963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 12973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len) 12983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 12993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* don't allow re-use */ 13003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(mComment == NULL); 13013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 13023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (len < kEOCDLen) { 13033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* looks like ZIP file got truncated */ 130415fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD(" Zip EOCD: expected >= %d bytes, found %d\n", 13053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian kEOCDLen, len); 13063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return INVALID_OPERATION; 13073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 13083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 13093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian /* this should probably be an assert() */ 13103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) 13113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 13123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 13133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mDiskNumber = ZipEntry::getShortLE(&buf[0x04]); 13143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]); 13153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mNumEntries = ZipEntry::getShortLE(&buf[0x08]); 13163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]); 13173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]); 13183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]); 13193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mCommentLen = ZipEntry::getShortLE(&buf[0x14]); 13203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 13213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian // TODO: validate mCentralDirOffset 13223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 13233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (mCommentLen > 0) { 13243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (kEOCDLen + mCommentLen > len) { 132515fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n", 13263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian kEOCDLen, mCommentLen, len); 13273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 13283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 13293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mComment = new unsigned char[mCommentLen]; 13303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian memcpy(mComment, buf + kEOCDLen, mCommentLen); 13313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 13323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 13333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NO_ERROR; 13343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 13353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 13363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 13373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Write an end-of-central-directory section. 13383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 13393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::EndOfCentralDir::write(FILE* fp) 13403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 13413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian unsigned char buf[kEOCDLen]; 13423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 13433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry::putLongLE(&buf[0x00], kSignature); 13443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry::putShortLE(&buf[0x04], mDiskNumber); 13453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir); 13463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry::putShortLE(&buf[0x08], mNumEntries); 13473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries); 13483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize); 13493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset); 13503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian ZipEntry::putShortLE(&buf[0x14], mCommentLen); 13513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 13523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen) 13533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 13543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (mCommentLen > 0) { 13553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian assert(mComment != NULL); 13563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen) 13573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return UNKNOWN_ERROR; 13583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian } 13593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 13603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian return NO_ERROR; 13613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 13623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 13633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* 13643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Dump the contents of an EndOfCentralDir object. 13653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */ 13663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianvoid ZipFile::EndOfCentralDir::dump(void) const 13673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{ 136815fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD(" EndOfCentralDir contents:\n"); 136915fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n", 13703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries); 137115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block ALOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n", 13723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian mCentralDirSize, mCentralDirOffset, mCommentLen); 13733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian} 13743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian 1375