ZipEntry.cpp revision 48a621c2779c74cba3555c96e3fbc7b1989ac90b
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17// 18// Access to entries in a Zip archive. 19// 20 21#include "ZipEntry.h" 22 23#include <stdio.h> 24#include <string.h> 25#include <assert.h> 26 27using namespace android; 28 29#define LOG(...) fprintf(stderr, __VA_ARGS__) 30 31/* Jan 01 2008 */ 32#define STATIC_DATE (28 << 9 | 1 << 5 | 1) 33#define STATIC_TIME 0 34 35/* 36 * Initialize a new ZipEntry structure from a FILE* positioned at a 37 * CentralDirectoryEntry. Rewrites the headers to remove the dynamic 38 * timestamps. 39 * 40 * On exit, the file pointer will be at the start of the next CDE or 41 * at the EOCD. 42 */ 43status_t ZipEntry::initAndRewriteFromCDE(FILE* fp) 44{ 45 status_t result; 46 long posn; 47 48 /* read the CDE */ 49 result = mCDE.rewrite(fp); 50 if (result != 0) { 51 LOG("mCDE.rewrite failed\n"); 52 return result; 53 } 54 55 /* using the info in the CDE, go load up the LFH */ 56 posn = ftell(fp); 57 if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) { 58 LOG("local header seek failed (%ld)\n", 59 mCDE.mLocalHeaderRelOffset); 60 return -1; 61 } 62 63 result = mLFH.rewrite(fp); 64 if (result != 0) { 65 LOG("mLFH.rewrite failed\n"); 66 return result; 67 } 68 69 if (fseek(fp, posn, SEEK_SET) != 0) 70 return -1; 71 72 return 0; 73} 74 75/* 76 * =========================================================================== 77 * ZipEntry::LocalFileHeader 78 * =========================================================================== 79 */ 80 81/* 82 * Rewrite a local file header. 83 * 84 * On entry, "fp" points to the signature at the start of the header. 85 */ 86status_t ZipEntry::LocalFileHeader::rewrite(FILE* fp) 87{ 88 status_t result = 0; 89 unsigned char buf[kLFHLen]; 90 91 if (fread(buf, 1, kLFHLen, fp) != kLFHLen) 92 return -1; 93 94 if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) { 95 LOG("whoops: didn't find expected signature\n"); 96 return -1; 97 } 98 99 ZipEntry::putShortLE(&buf[0x0a], STATIC_TIME); 100 ZipEntry::putShortLE(&buf[0x0c], STATIC_DATE); 101 102 if (fseek(fp, -kLFHLen, SEEK_CUR) != 0) 103 return -1; 104 105 if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen) 106 return -1; 107 108 return 0; 109} 110 111/* 112 * =========================================================================== 113 * ZipEntry::CentralDirEntry 114 * =========================================================================== 115 */ 116 117/* 118 * Read and rewrite the central dir entry that appears next in the file. 119 * 120 * On entry, "fp" should be positioned on the signature bytes for the 121 * entry. On exit, "fp" will point at the signature word for the next 122 * entry or for the EOCD. 123 */ 124status_t ZipEntry::CentralDirEntry::rewrite(FILE* fp) 125{ 126 status_t result = 0; 127 unsigned char buf[kCDELen]; 128 unsigned short fileNameLength, extraFieldLength, fileCommentLength; 129 130 if (fread(buf, 1, kCDELen, fp) != kCDELen) 131 return -1; 132 133 if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) { 134 LOG("Whoops: didn't find expected signature\n"); 135 return -1; 136 } 137 138 ZipEntry::putShortLE(&buf[0x0c], STATIC_TIME); 139 ZipEntry::putShortLE(&buf[0x0e], STATIC_DATE); 140 141 fileNameLength = ZipEntry::getShortLE(&buf[0x1c]); 142 extraFieldLength = ZipEntry::getShortLE(&buf[0x1e]); 143 fileCommentLength = ZipEntry::getShortLE(&buf[0x20]); 144 mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]); 145 146 if (fseek(fp, -kCDELen, SEEK_CUR) != 0) 147 return -1; 148 149 if (fwrite(buf, 1, kCDELen, fp) != kCDELen) 150 return -1; 151 152 if (fseek(fp, fileNameLength + extraFieldLength + fileCommentLength, SEEK_CUR) != 0) 153 return -1; 154 155 return 0; 156} 157