• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 CentralDirectory data
26  * CentralDirectory format for:
27  * central file header signature   4 bytes  (0x02014b50)
28  * version made by                 2 bytes
29  * version needed to extract       2 bytes
30  * general purpose bit flag        2 bytes
31  * compression method              2 bytes
32  * last mod file time              2 bytes
33  * last mod file date              2 bytes
34  * crc-32                          4 bytes
35  * compressed size                 4 bytes
36  * uncompressed size               4 bytes
37  * file name length                2 bytes
38  * extra field length              2 bytes
39  * file comment length             2 bytes
40  * disk number start               2 bytes
41  * internal file attributes        2 bytes
42  * external file attributes        4 bytes
43  * relative offset of local header 4 bytes
44  * file name (variable size)
45  * extra field (variable size)
46  * file comment (variable size)
47  *
48  * @since 2023/12/02
49  */
50 public class CentralDirectory {
51     /**
52      * central directory invariable bytes length
53      */
54     public static final int CD_LENGTH = 46;
55 
56     /**
57      * 4 bytes , central directory signature
58      */
59     public static final int SIGNATURE = 0x02014b50;
60 
61     /**
62      * 2 bytes
63      */
64     private short version;
65 
66     /**
67      * 2 bytes
68      */
69     private short versionExtra;
70 
71     /**
72      * 2 bytes
73      */
74     private short flag;
75 
76     /**
77      * 2 bytes
78      */
79     private short method;
80 
81     /**
82      * 2 bytes
83      */
84     private short lastTime;
85 
86     /**
87      * 2 bytes
88      */
89     private short lastDate;
90 
91     /**
92      * 4 bytes
93      */
94     private int crc32;
95 
96     /**
97      * 4 bytes
98      */
99     private long compressedSize;
100 
101     /**
102      * 4 bytes
103      */
104     private long unCompressedSize;
105 
106     /**
107      * 2 bytes
108      */
109     private int fileNameLength;
110 
111     /**
112      * 2 bytes
113      */
114     private int extraLength;
115 
116     /**
117      * 2 bytes
118      */
119     private int commentLength;
120 
121     /**
122      * 2 bytes
123      */
124     private int diskNumStart;
125 
126     /**
127      * 2 bytes
128      */
129     private short internalFile;
130 
131     /**
132      * 4 bytes
133      */
134     private int externalFile;
135 
136     /**
137      * 4 bytes
138      */
139     private long offset;
140 
141     /**
142      * n bytes
143      */
144     private String fileName;
145 
146     /**
147      * n bytes
148      */
149     private byte[] extraData;
150 
151     /**
152      * n bytes
153      */
154     private byte[] comment;
155 
156     private int length;
157 
158     /**
159      * updateLength
160      */
updateLength()161     public void updateLength() {
162         length = CD_LENGTH + fileNameLength + extraLength + commentLength;
163     }
164 
165     /**
166      * get Central Directory
167      *
168      * @param bf ByteBuffer
169      * @return CentralDirectory
170      * @throws ZipException read Central Directory exception
171      */
getCentralDirectory(ByteBuffer bf)172     public static CentralDirectory getCentralDirectory(ByteBuffer bf) throws ZipException {
173         CentralDirectory cd = new CentralDirectory();
174         if (bf.getInt() != SIGNATURE) {
175             throw new ZipException("find zip central directory failed");
176         }
177 
178         cd.setVersion(bf.getShort());
179         cd.setVersionExtra(bf.getShort());
180         cd.setFlag(bf.getShort());
181         cd.setMethod(bf.getShort());
182         cd.setLastTime(bf.getShort());
183         cd.setLastDate(bf.getShort());
184         cd.setCrc32(bf.getInt());
185         cd.setCompressedSize(UnsignedDecimalUtil.getUnsignedInt(bf));
186         cd.setUnCompressedSize(UnsignedDecimalUtil.getUnsignedInt(bf));
187         cd.setFileNameLength(UnsignedDecimalUtil.getUnsignedShort(bf));
188         cd.setExtraLength(UnsignedDecimalUtil.getUnsignedShort(bf));
189         cd.setCommentLength(UnsignedDecimalUtil.getUnsignedShort(bf));
190         cd.setDiskNumStart(UnsignedDecimalUtil.getUnsignedShort(bf));
191         cd.setInternalFile(bf.getShort());
192         cd.setExternalFile(bf.getInt());
193         cd.setOffset(UnsignedDecimalUtil.getUnsignedInt(bf));
194         if (cd.getFileNameLength() > 0) {
195             byte[] readFileName = new byte[cd.getFileNameLength()];
196             bf.get(readFileName);
197             cd.setFileName(new String(readFileName, StandardCharsets.UTF_8));
198         }
199         if (cd.getExtraLength() > 0) {
200             byte[] extra = new byte[cd.getExtraLength()];
201             bf.get(extra);
202             cd.setExtraData(extra);
203         }
204         if (cd.getCommentLength() > 0) {
205             byte[] readComment = new byte[cd.getCommentLength()];
206             bf.get(readComment);
207             cd.setComment(readComment);
208         }
209         cd.updateLength();
210         return cd;
211     }
212 
213     /**
214      * change Central Directory to bytes
215      *
216      * @return bytes
217      */
toBytes()218     public byte[] toBytes() {
219         ByteBuffer bf = ByteBuffer.allocate(length).order(ByteOrder.LITTLE_ENDIAN);
220         bf.putInt(SIGNATURE);
221         UnsignedDecimalUtil.setUnsignedShort(bf, version);
222         UnsignedDecimalUtil.setUnsignedShort(bf, versionExtra);
223         UnsignedDecimalUtil.setUnsignedShort(bf, flag);
224         UnsignedDecimalUtil.setUnsignedShort(bf, method);
225         UnsignedDecimalUtil.setUnsignedShort(bf, lastTime);
226         UnsignedDecimalUtil.setUnsignedShort(bf, lastDate);
227         UnsignedDecimalUtil.setUnsignedInt(bf, crc32);
228         UnsignedDecimalUtil.setUnsignedInt(bf, compressedSize);
229         UnsignedDecimalUtil.setUnsignedInt(bf, unCompressedSize);
230         UnsignedDecimalUtil.setUnsignedShort(bf, fileNameLength);
231         UnsignedDecimalUtil.setUnsignedShort(bf, extraLength);
232         UnsignedDecimalUtil.setUnsignedShort(bf, commentLength);
233         UnsignedDecimalUtil.setUnsignedShort(bf, diskNumStart);
234         UnsignedDecimalUtil.setUnsignedShort(bf, internalFile);
235         UnsignedDecimalUtil.setUnsignedInt(bf, externalFile);
236         UnsignedDecimalUtil.setUnsignedInt(bf, offset);
237         if (fileNameLength > 0) {
238             bf.put(fileName.getBytes(StandardCharsets.UTF_8));
239         }
240         if (extraLength > 0) {
241             bf.put(extraData);
242         }
243         if (commentLength > 0) {
244             bf.put(extraData);
245         }
246         return bf.array();
247     }
248 
getCdLength()249     public static int getCdLength() {
250         return CD_LENGTH;
251     }
252 
getSIGNATURE()253     public static int getSIGNATURE() {
254         return SIGNATURE;
255     }
256 
getVersion()257     public short getVersion() {
258         return version;
259     }
260 
setVersion(short version)261     public void setVersion(short version) {
262         this.version = version;
263     }
264 
getVersionExtra()265     public short getVersionExtra() {
266         return versionExtra;
267     }
268 
setVersionExtra(short versionExtra)269     public void setVersionExtra(short versionExtra) {
270         this.versionExtra = versionExtra;
271     }
272 
getFlag()273     public short getFlag() {
274         return flag;
275     }
276 
setFlag(short flag)277     public void setFlag(short flag) {
278         this.flag = flag;
279     }
280 
getMethod()281     public short getMethod() {
282         return method;
283     }
284 
setMethod(short method)285     public void setMethod(short method) {
286         this.method = method;
287     }
288 
getLastTime()289     public short getLastTime() {
290         return lastTime;
291     }
292 
setLastTime(short lastTime)293     public void setLastTime(short lastTime) {
294         this.lastTime = lastTime;
295     }
296 
getLastDate()297     public short getLastDate() {
298         return lastDate;
299     }
300 
setLastDate(short lastDate)301     public void setLastDate(short lastDate) {
302         this.lastDate = lastDate;
303     }
304 
getCrc32()305     public int getCrc32() {
306         return crc32;
307     }
308 
setCrc32(int crc32)309     public void setCrc32(int crc32) {
310         this.crc32 = crc32;
311     }
312 
getCompressedSize()313     public long getCompressedSize() {
314         return compressedSize;
315     }
316 
setCompressedSize(long compressedSize)317     public void setCompressedSize(long compressedSize) {
318         this.compressedSize = compressedSize;
319     }
320 
getUnCompressedSize()321     public long getUnCompressedSize() {
322         return unCompressedSize;
323     }
324 
setUnCompressedSize(long unCompressedSize)325     public void setUnCompressedSize(long unCompressedSize) {
326         this.unCompressedSize = unCompressedSize;
327     }
328 
getFileNameLength()329     public int getFileNameLength() {
330         return fileNameLength;
331     }
332 
setFileNameLength(int fileNameLength)333     public void setFileNameLength(int fileNameLength) {
334         this.fileNameLength = fileNameLength;
335     }
336 
getExtraLength()337     public int getExtraLength() {
338         return extraLength;
339     }
340 
setExtraLength(int extraLength)341     public void setExtraLength(int extraLength) {
342         this.extraLength = extraLength;
343     }
344 
getCommentLength()345     public int getCommentLength() {
346         return commentLength;
347     }
348 
setCommentLength(int commentLength)349     public void setCommentLength(int commentLength) {
350         this.commentLength = commentLength;
351     }
352 
getDiskNumStart()353     public int getDiskNumStart() {
354         return diskNumStart;
355     }
356 
setDiskNumStart(int diskNumStart)357     public void setDiskNumStart(int diskNumStart) {
358         this.diskNumStart = diskNumStart;
359     }
360 
getInternalFile()361     public short getInternalFile() {
362         return internalFile;
363     }
364 
setInternalFile(short internalFile)365     public void setInternalFile(short internalFile) {
366         this.internalFile = internalFile;
367     }
368 
getExternalFile()369     public int getExternalFile() {
370         return externalFile;
371     }
372 
setExternalFile(int externalFile)373     public void setExternalFile(int externalFile) {
374         this.externalFile = externalFile;
375     }
376 
getOffset()377     public long getOffset() {
378         return offset;
379     }
380 
setOffset(long offset)381     public void setOffset(long offset) {
382         this.offset = offset;
383     }
384 
getFileName()385     public String getFileName() {
386         return fileName;
387     }
388 
setFileName(String fileName)389     public void setFileName(String fileName) {
390         this.fileName = fileName;
391     }
392 
getExtraData()393     public byte[] getExtraData() {
394         return extraData;
395     }
396 
setExtraData(byte[] extraData)397     public void setExtraData(byte[] extraData) {
398         this.extraData = extraData;
399     }
400 
getComment()401     public byte[] getComment() {
402         return comment;
403     }
404 
setComment(byte[] comment)405     public void setComment(byte[] comment) {
406         this.comment = comment;
407     }
408 
getLength()409     public int getLength() {
410         return length;
411     }
412 
setLength(int length)413     public void setLength(int length) {
414         this.length = length;
415     }
416 }