1 /* 2 * Copyright (c) 2023-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package com.ohos.hapsigntool.zip; 17 18 import com.ohos.hapsigntool.error.ZipException; 19 20 import java.nio.ByteBuffer; 21 import java.nio.ByteOrder; 22 import java.nio.charset.StandardCharsets; 23 24 /** 25 * resolve zip ZipEntryHeader data 26 * end of central dir signature 4 bytes (0x06054b50) 27 * number of this disk 2 bytes 28 * number of the disk with the 29 * start of the central directory 2 bytes 30 * total number of entries in the 31 * central directory on this disk 2 bytes 32 * total number of entries in 33 * the central directory 2 bytes 34 * size of the central directory 4 bytes 35 * offset of start of central 36 * directory with respect to 37 * the starting disk number 4 bytes 38 * .ZIP file comment length 2 bytes 39 * .ZIP file comment (variable size) 40 * 41 * @since 2023/12/02 42 */ 43 public class ZipEntryHeader { 44 /** 45 * ZipEntryHeader invariable bytes length 46 */ 47 public static final int HEADER_LENGTH = 30; 48 49 /** 50 * 4 bytes , entry header signature 51 */ 52 public static final int SIGNATURE = 0x04034b50; 53 54 /** 55 * 2 bytes 56 */ 57 private short version; 58 59 /** 60 * 2 bytes 61 */ 62 private short flag; 63 64 /** 65 * 2 bytes 66 */ 67 private short method; 68 69 /** 70 * 2 bytes 71 */ 72 private short lastTime; 73 74 /** 75 * 2 bytes 76 */ 77 private short lastDate; 78 79 /** 80 * 4 bytes 81 */ 82 private int crc32; 83 84 /** 85 * 4 bytes 86 */ 87 private long compressedSize; 88 89 /** 90 * 4 bytes 91 */ 92 private long unCompressedSize; 93 94 /** 95 * 2 bytes 96 */ 97 private int fileNameLength; 98 99 /** 100 * 2 bytes 101 */ 102 private int extraLength; 103 104 /** 105 * n bytes 106 */ 107 private String fileName; 108 109 /** 110 * n bytes 111 */ 112 private byte[] extraData; 113 114 private int length; 115 116 /** 117 * get Zip Entry Header 118 * 119 * @param bytes ZipEntryHeader bytes 120 * @return ZipEntryHeader 121 * @throws ZipException read entry header exception 122 */ getZipEntryHeader(byte[] bytes)123 public static ZipEntryHeader getZipEntryHeader(byte[] bytes) throws ZipException { 124 ZipEntryHeader entryHeader = new ZipEntryHeader(); 125 ByteBuffer bf = ByteBuffer.wrap(bytes); 126 bf.order(ByteOrder.LITTLE_ENDIAN); 127 if (bf.getInt() != ZipEntryHeader.SIGNATURE) { 128 throw new ZipException("find zip entry head failed"); 129 } 130 entryHeader.setVersion(bf.getShort()); 131 entryHeader.setFlag(bf.getShort()); 132 entryHeader.setMethod(bf.getShort()); 133 entryHeader.setLastTime(bf.getShort()); 134 entryHeader.setLastDate(bf.getShort()); 135 entryHeader.setCrc32(bf.getInt()); 136 entryHeader.setCompressedSize(UnsignedDecimalUtil.getUnsignedInt(bf)); 137 entryHeader.setUnCompressedSize(UnsignedDecimalUtil.getUnsignedInt(bf)); 138 entryHeader.setFileNameLength(UnsignedDecimalUtil.getUnsignedShort(bf)); 139 entryHeader.setExtraLength(UnsignedDecimalUtil.getUnsignedShort(bf)); 140 entryHeader.setLength(HEADER_LENGTH + entryHeader.getFileNameLength() + entryHeader.getExtraLength()); 141 return entryHeader; 142 } 143 144 /** 145 * set entry header name 146 * 147 * @param bytes name bytes 148 */ readFileName(byte[] bytes)149 public void readFileName(byte[] bytes) { 150 ByteBuffer bf = ByteBuffer.wrap(bytes); 151 bf.order(ByteOrder.LITTLE_ENDIAN); 152 if (fileNameLength > 0) { 153 byte[] nameBytes = new byte[fileNameLength]; 154 bf.get(nameBytes); 155 this.fileName = new String(nameBytes, StandardCharsets.UTF_8); 156 } 157 } 158 159 /** 160 * set entry header extra 161 * 162 * @param bytes extra bytes 163 */ readExtra(byte[] bytes)164 public void readExtra(byte[] bytes) { 165 ByteBuffer bf = ByteBuffer.wrap(bytes); 166 bf.order(ByteOrder.LITTLE_ENDIAN); 167 if (extraLength > 0) { 168 byte[] extra = new byte[extraLength]; 169 bf.get(extra); 170 this.extraData = extra; 171 } 172 } 173 174 /** 175 * change Zip Entry Header to bytes 176 * 177 * @return bytes 178 */ toBytes()179 public byte[] toBytes() { 180 ByteBuffer bf = ByteBuffer.allocate(length).order(ByteOrder.LITTLE_ENDIAN); 181 bf.putInt(SIGNATURE); 182 bf.putShort(version); 183 bf.putShort(flag); 184 bf.putShort(method); 185 bf.putShort(lastTime); 186 bf.putShort(lastDate); 187 bf.putInt(crc32); 188 UnsignedDecimalUtil.setUnsignedInt(bf, compressedSize); 189 UnsignedDecimalUtil.setUnsignedInt(bf, unCompressedSize); 190 UnsignedDecimalUtil.setUnsignedShort(bf, fileNameLength); 191 UnsignedDecimalUtil.setUnsignedShort(bf, extraLength); 192 if (fileNameLength > 0) { 193 bf.put(fileName.getBytes(StandardCharsets.UTF_8)); 194 } 195 if (extraLength > 0) { 196 bf.put(extraData); 197 } 198 return bf.array(); 199 } 200 getHeaderLength()201 public static int getHeaderLength() { 202 return HEADER_LENGTH; 203 } 204 getSIGNATURE()205 public static int getSIGNATURE() { 206 return SIGNATURE; 207 } 208 getVersion()209 public short getVersion() { 210 return version; 211 } 212 setVersion(short version)213 public void setVersion(short version) { 214 this.version = version; 215 } 216 getFlag()217 public short getFlag() { 218 return flag; 219 } 220 setFlag(short flag)221 public void setFlag(short flag) { 222 this.flag = flag; 223 } 224 getMethod()225 public short getMethod() { 226 return method; 227 } 228 setMethod(short method)229 public void setMethod(short method) { 230 this.method = method; 231 } 232 getLastTime()233 public short getLastTime() { 234 return lastTime; 235 } 236 setLastTime(short lastTime)237 public void setLastTime(short lastTime) { 238 this.lastTime = lastTime; 239 } 240 getLastDate()241 public short getLastDate() { 242 return lastDate; 243 } 244 setLastDate(short lastDate)245 public void setLastDate(short lastDate) { 246 this.lastDate = lastDate; 247 } 248 getCrc32()249 public int getCrc32() { 250 return crc32; 251 } 252 setCrc32(int crc32)253 public void setCrc32(int crc32) { 254 this.crc32 = crc32; 255 } 256 getCompressedSize()257 public long getCompressedSize() { 258 return compressedSize; 259 } 260 setCompressedSize(long compressedSize)261 public void setCompressedSize(long compressedSize) { 262 this.compressedSize = compressedSize; 263 } 264 getUnCompressedSize()265 public long getUnCompressedSize() { 266 return unCompressedSize; 267 } 268 setUnCompressedSize(long unCompressedSize)269 public void setUnCompressedSize(long unCompressedSize) { 270 this.unCompressedSize = unCompressedSize; 271 } 272 getFileNameLength()273 public int getFileNameLength() { 274 return fileNameLength; 275 } 276 setFileNameLength(int fileNameLength)277 public void setFileNameLength(int fileNameLength) { 278 this.fileNameLength = fileNameLength; 279 } 280 getExtraLength()281 public int getExtraLength() { 282 return extraLength; 283 } 284 setExtraLength(int extraLength)285 public void setExtraLength(int extraLength) { 286 this.extraLength = extraLength; 287 } 288 getFileName()289 public String getFileName() { 290 return fileName; 291 } 292 setFileName(String fileName)293 public void setFileName(String fileName) { 294 this.fileName = fileName; 295 } 296 getExtraData()297 public byte[] getExtraData() { 298 return extraData; 299 } 300 setExtraData(byte[] extraData)301 public void setExtraData(byte[] extraData) { 302 this.extraData = extraData; 303 } 304 getLength()305 public int getLength() { 306 return length; 307 } 308 setLength(int length)309 public void setLength(int length) { 310 this.length = length; 311 } 312 }