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 java.nio.ByteBuffer; 19 import java.nio.ByteOrder; 20 import java.util.Optional; 21 22 /** 23 * resolve zip EndOfCentralDirectory data 24 * EndOfCentralDirectory format for: 25 * end of central dir signature 4 bytes (0x06054b50) 26 * number of this disk 2 bytes 27 * number of the disk with the 28 * start of the central directory 2 bytes 29 * total number of entries in the 30 * central directory on this disk 2 bytes 31 * total number of entries in 32 * the central directory 2 bytes 33 * size of the central directory 4 bytes 34 * offset of start of central 35 * directory with respect to 36 * the starting disk number 4 bytes 37 * .ZIP file comment length 2 bytes 38 * .ZIP file comment (variable size) 39 * 40 * @since 2023/12/04 41 */ 42 public class EndOfCentralDirectory { 43 /** 44 * EndOfCentralDirectory invariable bytes length 45 */ 46 public static final int EOCD_LENGTH = 22; 47 48 /** 49 * 4 bytes , central directory signature 50 */ 51 public static final int SIGNATURE = 0x06054b50; 52 53 /** 54 * 2 bytes 55 */ 56 private int diskNum; 57 58 /** 59 * 2 bytes 60 */ 61 private int cDStartDiskNum; 62 63 /** 64 * 2 bytes 65 */ 66 private int thisDiskCDNum; 67 68 /** 69 * 2 bytes 70 */ 71 private int cDTotal; 72 73 /** 74 * 4 bytes 75 */ 76 private long cDSize; 77 78 /** 79 * 4 bytes 80 */ 81 private long offset; 82 83 /** 84 * 2 bytes 85 */ 86 private int commentLength; 87 88 /** 89 * n bytes 90 */ 91 private byte[] comment; 92 93 private int length; 94 95 /** 96 * init End Of Central Directory, default offset is 0 97 * 98 * @param bytes End Of Central Directory bytes 99 * @return End Of Central Directory 100 */ getEOCDByBytes(byte[] bytes)101 public static Optional<EndOfCentralDirectory> getEOCDByBytes(byte[] bytes) { 102 return getEOCDByBytes(bytes, 0); 103 } 104 105 /** 106 * init End Of Central Directory 107 * 108 * @param bytes End Of Central Directory bytes 109 * @param offset offset 110 * @return End Of Central Directory 111 */ getEOCDByBytes(byte[] bytes, int offset)112 public static Optional<EndOfCentralDirectory> getEOCDByBytes(byte[] bytes, int offset) { 113 EndOfCentralDirectory eocd = new EndOfCentralDirectory(); 114 int remainingDataLen = bytes.length - offset; 115 if (remainingDataLen < EOCD_LENGTH) { 116 return Optional.empty(); 117 } 118 ByteBuffer bf = ByteBuffer.wrap(bytes, offset, remainingDataLen); 119 bf.order(ByteOrder.LITTLE_ENDIAN); 120 if (bf.getInt() != SIGNATURE) { 121 return Optional.empty(); 122 } 123 eocd.setDiskNum(UnsignedDecimalUtil.getUnsignedShort(bf)); 124 eocd.setcDStartDiskNum(UnsignedDecimalUtil.getUnsignedShort(bf)); 125 eocd.setThisDiskCDNum(UnsignedDecimalUtil.getUnsignedShort(bf)); 126 eocd.setCDTotal(UnsignedDecimalUtil.getUnsignedShort(bf)); 127 eocd.setCDSize(UnsignedDecimalUtil.getUnsignedInt(bf)); 128 eocd.setOffset(UnsignedDecimalUtil.getUnsignedInt(bf)); 129 eocd.setCommentLength(UnsignedDecimalUtil.getUnsignedShort(bf)); 130 if (bf.remaining() != eocd.getCommentLength()) { 131 return Optional.empty(); 132 } 133 if (eocd.getCommentLength() > 0) { 134 byte[] readComment = new byte[eocd.getCommentLength()]; 135 bf.get(readComment); 136 eocd.setComment(readComment); 137 } 138 eocd.setLength(EOCD_LENGTH + eocd.getCommentLength()); 139 if (bf.remaining() != 0) { 140 return Optional.empty(); 141 } 142 return Optional.of(eocd); 143 } 144 145 /** 146 * change End Of Central Directory to bytes 147 * 148 * @return bytes 149 */ toBytes()150 public byte[] toBytes() { 151 ByteBuffer bf = ByteBuffer.allocate(length).order(ByteOrder.LITTLE_ENDIAN); 152 bf.putInt(SIGNATURE); 153 UnsignedDecimalUtil.setUnsignedShort(bf, diskNum); 154 UnsignedDecimalUtil.setUnsignedShort(bf, cDStartDiskNum); 155 UnsignedDecimalUtil.setUnsignedShort(bf, thisDiskCDNum); 156 UnsignedDecimalUtil.setUnsignedShort(bf, cDTotal); 157 UnsignedDecimalUtil.setUnsignedInt(bf, cDSize); 158 UnsignedDecimalUtil.setUnsignedInt(bf, offset); 159 UnsignedDecimalUtil.setUnsignedShort(bf, commentLength); 160 if (commentLength > 0) { 161 bf.put(comment); 162 } 163 return bf.array(); 164 } 165 getEocdLength()166 public static int getEocdLength() { 167 return EOCD_LENGTH; 168 } 169 getSIGNATURE()170 public static int getSIGNATURE() { 171 return SIGNATURE; 172 } 173 getDiskNum()174 public int getDiskNum() { 175 return diskNum; 176 } 177 setDiskNum(int diskNum)178 public void setDiskNum(int diskNum) { 179 this.diskNum = diskNum; 180 } 181 getcDStartDiskNum()182 public int getcDStartDiskNum() { 183 return cDStartDiskNum; 184 } 185 setcDStartDiskNum(int cDStartDiskNum)186 public void setcDStartDiskNum(int cDStartDiskNum) { 187 this.cDStartDiskNum = cDStartDiskNum; 188 } 189 getThisDiskCDNum()190 public int getThisDiskCDNum() { 191 return thisDiskCDNum; 192 } 193 setThisDiskCDNum(int thisDiskCDNum)194 public void setThisDiskCDNum(int thisDiskCDNum) { 195 this.thisDiskCDNum = thisDiskCDNum; 196 } 197 getCDTotal()198 public int getCDTotal() { 199 return cDTotal; 200 } 201 setCDTotal(int cDTotal)202 public void setCDTotal(int cDTotal) { 203 this.cDTotal = cDTotal; 204 } 205 getCDSize()206 public long getCDSize() { 207 return cDSize; 208 } 209 setCDSize(long cDSize)210 public void setCDSize(long cDSize) { 211 this.cDSize = cDSize; 212 } 213 getOffset()214 public long getOffset() { 215 return offset; 216 } 217 setOffset(long offset)218 public void setOffset(long offset) { 219 this.offset = offset; 220 } 221 getCommentLength()222 public int getCommentLength() { 223 return commentLength; 224 } 225 setCommentLength(int commentLength)226 public void setCommentLength(int commentLength) { 227 this.commentLength = commentLength; 228 } 229 getComment()230 public byte[] getComment() { 231 return comment; 232 } 233 setComment(byte[] comment)234 public void setComment(byte[] comment) { 235 this.comment = comment; 236 } 237 getLength()238 public int getLength() { 239 return length; 240 } 241 setLength(int length)242 public void setLength(int length) { 243 this.length = length; 244 } 245 }