1 /* 2 * Copyright (C) 2019 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 package com.android.tradefed.util.zip; 18 19 import com.android.tradefed.util.ByteArrayUtil; 20 21 import java.io.File; 22 import java.io.FileInputStream; 23 import java.io.IOException; 24 import java.util.Arrays; 25 26 /** 27 * LocalFileHeader is a class containing the information of a file/folder inside a zip file. The 28 * block of data is at the beginning part of each file entry. 29 * 30 * <p>Overall zipfile format: [Local file header + Compressed data [+ Extended local header]?]* 31 * [Central directory]* [End of central directory record] 32 * 33 * <p>Refer to following link for more details: https://en.wikipedia.org/wiki/Zip_(file_format) 34 */ 35 public final class LocalFileHeader { 36 37 public static final int LOCAL_FILE_HEADER_SIZE = 30; 38 private static final byte[] LOCAL_FILE_HEADER_SIGNATURE = {0x50, 0x4b, 0x03, 0x04}; 39 40 private int mCompressionMethod; 41 private long mCrc; 42 private long mCompressedSize; 43 private long mUncompressedSize; 44 private int mFileNameLength; 45 private int mExtraFieldLength; 46 getCompressionMethod()47 public int getCompressionMethod() { 48 return mCompressionMethod; 49 } 50 getCrc()51 public long getCrc() { 52 return mCrc; 53 } 54 getCompressedSize()55 public long getCompressedSize() { 56 return mCompressedSize; 57 } 58 getUncompressedSize()59 public long getUncompressedSize() { 60 return mUncompressedSize; 61 } 62 getFileNameLength()63 public int getFileNameLength() { 64 return mFileNameLength; 65 } 66 getExtraFieldLength()67 public int getExtraFieldLength() { 68 return mExtraFieldLength; 69 } 70 getHeaderSize()71 public int getHeaderSize() { 72 return LOCAL_FILE_HEADER_SIZE + mFileNameLength + mExtraFieldLength; 73 } 74 LocalFileHeader(File partialZipFile)75 public LocalFileHeader(File partialZipFile) throws IOException { 76 this(partialZipFile, 0); 77 } 78 79 /** 80 * Constructor to collect local file header information of a file entry in a zip file. 81 * 82 * @param partialZipFile a {@link File} contains the local file header information. 83 * @param startOffset the start offset of the block of data for a local file header. 84 * @throws IOException 85 */ LocalFileHeader(File partialZipFile, int startOffset)86 public LocalFileHeader(File partialZipFile, int startOffset) throws IOException { 87 // Local file header: 88 // Offset Length Contents 89 // 0 4 bytes Local file header signature (0x04034b50) 90 // 4 2 bytes Version needed to extract 91 // 6 2 bytes General purpose bit flag 92 // 8 2 bytes Compression method 93 // 10 2 bytes Last mod file time 94 // 12 2 bytes Last mod file date 95 // 14 4 bytes CRC-32 96 // 18 4 bytes Compressed size (n) 97 // 22 4 bytes Uncompressed size 98 // 26 2 bytes Filename length (f) 99 // 28 2 bytes Extra field length (e) 100 // (f)bytes Filename 101 // (e)bytes Extra field 102 // (n)bytes Compressed data 103 byte[] data; 104 try (FileInputStream stream = new FileInputStream(partialZipFile)) { 105 stream.skip(startOffset); 106 data = new byte[LOCAL_FILE_HEADER_SIZE]; 107 stream.read(data); 108 } 109 110 // Check signature 111 if (!Arrays.equals(LOCAL_FILE_HEADER_SIGNATURE, Arrays.copyOfRange(data, 0, 4))) { 112 throw new IOException("Invalid local file header for zip file is found."); 113 } 114 mCompressionMethod = ByteArrayUtil.getInt(data, 8, 2); 115 mCrc = ByteArrayUtil.getLong(data, 14, 4); 116 mCompressedSize = ByteArrayUtil.getLong(data, 18, 2); 117 mUncompressedSize = ByteArrayUtil.getLong(data, 22, 2); 118 mFileNameLength = ByteArrayUtil.getInt(data, 26, 2); 119 mExtraFieldLength = ByteArrayUtil.getInt(data, 28, 2); 120 } 121 } 122