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 * updateLength 118 */ updateLength()119 public void updateLength() { 120 length = HEADER_LENGTH + fileNameLength + extraLength; 121 } 122 123 /** 124 * get Zip Entry Header 125 * 126 * @param bytes ZipEntryHeader bytes 127 * @return ZipEntryHeader 128 * @throws ZipException read entry header exception 129 */ getZipEntryHeader(byte[] bytes)130 public static ZipEntryHeader getZipEntryHeader(byte[] bytes) throws ZipException { 131 ZipEntryHeader entryHeader = new ZipEntryHeader(); 132 ByteBuffer bf = ByteBuffer.wrap(bytes); 133 bf.order(ByteOrder.LITTLE_ENDIAN); 134 if (bf.getInt() != ZipEntryHeader.SIGNATURE) { 135 throw new ZipException("find zip entry head failed"); 136 } 137 entryHeader.setVersion(bf.getShort()); 138 entryHeader.setFlag(bf.getShort()); 139 entryHeader.setMethod(bf.getShort()); 140 entryHeader.setLastTime(bf.getShort()); 141 entryHeader.setLastDate(bf.getShort()); 142 entryHeader.setCrc32(bf.getInt()); 143 entryHeader.setCompressedSize(UnsignedDecimalUtil.getUnsignedInt(bf)); 144 entryHeader.setUnCompressedSize(UnsignedDecimalUtil.getUnsignedInt(bf)); 145 entryHeader.setFileNameLength(UnsignedDecimalUtil.getUnsignedShort(bf)); 146 entryHeader.setExtraLength(UnsignedDecimalUtil.getUnsignedShort(bf)); 147 entryHeader.updateLength(); 148 return entryHeader; 149 } 150 151 /** 152 * set entry header name 153 * 154 * @param bytes name bytes 155 */ readFileName(byte[] bytes)156 public void readFileName(byte[] bytes) { 157 ByteBuffer bf = ByteBuffer.wrap(bytes); 158 bf.order(ByteOrder.LITTLE_ENDIAN); 159 if (fileNameLength > 0) { 160 byte[] nameBytes = new byte[fileNameLength]; 161 bf.get(nameBytes); 162 this.fileName = new String(nameBytes, StandardCharsets.UTF_8); 163 } 164 } 165 166 /** 167 * set entry header extra 168 * 169 * @param bytes extra bytes 170 */ readExtra(byte[] bytes)171 public void readExtra(byte[] bytes) { 172 ByteBuffer bf = ByteBuffer.wrap(bytes); 173 bf.order(ByteOrder.LITTLE_ENDIAN); 174 if (extraLength > 0) { 175 byte[] extra = new byte[extraLength]; 176 bf.get(extra); 177 this.extraData = extra; 178 } 179 } 180 181 /** 182 * change Zip Entry Header to bytes 183 * 184 * @return bytes 185 */ toBytes()186 public byte[] toBytes() { 187 ByteBuffer bf = ByteBuffer.allocate(length).order(ByteOrder.LITTLE_ENDIAN); 188 bf.putInt(SIGNATURE); 189 bf.putShort(version); 190 bf.putShort(flag); 191 bf.putShort(method); 192 bf.putShort(lastTime); 193 bf.putShort(lastDate); 194 bf.putInt(crc32); 195 UnsignedDecimalUtil.setUnsignedInt(bf, compressedSize); 196 UnsignedDecimalUtil.setUnsignedInt(bf, unCompressedSize); 197 UnsignedDecimalUtil.setUnsignedShort(bf, fileNameLength); 198 UnsignedDecimalUtil.setUnsignedShort(bf, extraLength); 199 if (fileNameLength > 0) { 200 bf.put(fileName.getBytes(StandardCharsets.UTF_8)); 201 } 202 if (extraLength > 0) { 203 bf.put(extraData); 204 } 205 return bf.array(); 206 } 207 getHeaderLength()208 public static int getHeaderLength() { 209 return HEADER_LENGTH; 210 } 211 getSIGNATURE()212 public static int getSIGNATURE() { 213 return SIGNATURE; 214 } 215 getVersion()216 public short getVersion() { 217 return version; 218 } 219 setVersion(short version)220 public void setVersion(short version) { 221 this.version = version; 222 } 223 getFlag()224 public short getFlag() { 225 return flag; 226 } 227 setFlag(short flag)228 public void setFlag(short flag) { 229 this.flag = flag; 230 } 231 getMethod()232 public short getMethod() { 233 return method; 234 } 235 setMethod(short method)236 public void setMethod(short method) { 237 this.method = method; 238 } 239 getLastTime()240 public short getLastTime() { 241 return lastTime; 242 } 243 setLastTime(short lastTime)244 public void setLastTime(short lastTime) { 245 this.lastTime = lastTime; 246 } 247 getLastDate()248 public short getLastDate() { 249 return lastDate; 250 } 251 setLastDate(short lastDate)252 public void setLastDate(short lastDate) { 253 this.lastDate = lastDate; 254 } 255 getCrc32()256 public int getCrc32() { 257 return crc32; 258 } 259 setCrc32(int crc32)260 public void setCrc32(int crc32) { 261 this.crc32 = crc32; 262 } 263 getCompressedSize()264 public long getCompressedSize() { 265 return compressedSize; 266 } 267 setCompressedSize(long compressedSize)268 public void setCompressedSize(long compressedSize) { 269 this.compressedSize = compressedSize; 270 } 271 getUnCompressedSize()272 public long getUnCompressedSize() { 273 return unCompressedSize; 274 } 275 setUnCompressedSize(long unCompressedSize)276 public void setUnCompressedSize(long unCompressedSize) { 277 this.unCompressedSize = unCompressedSize; 278 } 279 getFileNameLength()280 public int getFileNameLength() { 281 return fileNameLength; 282 } 283 setFileNameLength(int fileNameLength)284 public void setFileNameLength(int fileNameLength) { 285 this.fileNameLength = fileNameLength; 286 } 287 getExtraLength()288 public int getExtraLength() { 289 return extraLength; 290 } 291 setExtraLength(int extraLength)292 public void setExtraLength(int extraLength) { 293 this.extraLength = extraLength; 294 } 295 getFileName()296 public String getFileName() { 297 return fileName; 298 } 299 setFileName(String fileName)300 public void setFileName(String fileName) { 301 this.fileName = fileName; 302 } 303 getExtraData()304 public byte[] getExtraData() { 305 return extraData; 306 } 307 setExtraData(byte[] extraData)308 public void setExtraData(byte[] extraData) { 309 this.extraData = extraData; 310 } 311 getLength()312 public int getLength() { 313 return length; 314 } 315 setLength(int length)316 public void setLength(int length) { 317 this.length = length; 318 } 319 }