• 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      * get Central Directory
160      *
161      * @param bf ByteBuffer
162      * @return CentralDirectory
163      * @throws ZipException read Central Directory exception
164      */
getCentralDirectory(ByteBuffer bf)165     public static CentralDirectory getCentralDirectory(ByteBuffer bf) throws ZipException {
166         CentralDirectory cd = new CentralDirectory();
167         if (bf.getInt() != SIGNATURE) {
168             throw new ZipException("find zip central directory failed");
169         }
170 
171         cd.setVersion(bf.getShort());
172         cd.setVersionExtra(bf.getShort());
173         cd.setFlag(bf.getShort());
174         cd.setMethod(bf.getShort());
175         cd.setLastTime(bf.getShort());
176         cd.setLastDate(bf.getShort());
177         cd.setCrc32(bf.getInt());
178         cd.setCompressedSize(UnsignedDecimalUtil.getUnsignedInt(bf));
179         cd.setUnCompressedSize(UnsignedDecimalUtil.getUnsignedInt(bf));
180         cd.setFileNameLength(UnsignedDecimalUtil.getUnsignedShort(bf));
181         cd.setExtraLength(UnsignedDecimalUtil.getUnsignedShort(bf));
182         cd.setCommentLength(UnsignedDecimalUtil.getUnsignedShort(bf));
183         cd.setDiskNumStart(UnsignedDecimalUtil.getUnsignedShort(bf));
184         cd.setInternalFile(bf.getShort());
185         cd.setExternalFile(bf.getInt());
186         cd.setOffset(UnsignedDecimalUtil.getUnsignedInt(bf));
187         if (cd.getFileNameLength() > 0) {
188             byte[] readFileName = new byte[cd.getFileNameLength()];
189             bf.get(readFileName);
190             cd.setFileName(new String(readFileName, StandardCharsets.UTF_8));
191         }
192         if (cd.getExtraLength() > 0) {
193             byte[] extra = new byte[cd.getExtraLength()];
194             bf.get(extra);
195             cd.setExtraData(extra);
196         }
197         if (cd.getCommentLength() > 0) {
198             byte[] readComment = new byte[cd.getCommentLength()];
199             bf.get(readComment);
200             cd.setComment(readComment);
201         }
202         cd.setLength(CD_LENGTH + cd.getFileNameLength() + cd.getExtraLength() + cd.getCommentLength());
203         return cd;
204     }
205 
206     /**
207      * change Central Directory to bytes
208      *
209      * @return bytes
210      */
toBytes()211     public byte[] toBytes() {
212         ByteBuffer bf = ByteBuffer.allocate(length).order(ByteOrder.LITTLE_ENDIAN);
213         bf.putInt(SIGNATURE);
214         UnsignedDecimalUtil.setUnsignedShort(bf, version);
215         UnsignedDecimalUtil.setUnsignedShort(bf, versionExtra);
216         UnsignedDecimalUtil.setUnsignedShort(bf, flag);
217         UnsignedDecimalUtil.setUnsignedShort(bf, method);
218         UnsignedDecimalUtil.setUnsignedShort(bf, lastTime);
219         UnsignedDecimalUtil.setUnsignedShort(bf, lastDate);
220         UnsignedDecimalUtil.setUnsignedInt(bf, crc32);
221         UnsignedDecimalUtil.setUnsignedInt(bf, compressedSize);
222         UnsignedDecimalUtil.setUnsignedInt(bf, unCompressedSize);
223         UnsignedDecimalUtil.setUnsignedShort(bf, fileNameLength);
224         UnsignedDecimalUtil.setUnsignedShort(bf, extraLength);
225         UnsignedDecimalUtil.setUnsignedShort(bf, commentLength);
226         UnsignedDecimalUtil.setUnsignedShort(bf, diskNumStart);
227         UnsignedDecimalUtil.setUnsignedShort(bf, internalFile);
228         UnsignedDecimalUtil.setUnsignedInt(bf, externalFile);
229         UnsignedDecimalUtil.setUnsignedInt(bf, offset);
230         if (fileNameLength > 0) {
231             bf.put(fileName.getBytes(StandardCharsets.UTF_8));
232         }
233         if (extraLength > 0) {
234             bf.put(extraData);
235         }
236         if (commentLength > 0) {
237             bf.put(extraData);
238         }
239         return bf.array();
240     }
241 
getCdLength()242     public static int getCdLength() {
243         return CD_LENGTH;
244     }
245 
getSIGNATURE()246     public static int getSIGNATURE() {
247         return SIGNATURE;
248     }
249 
getVersion()250     public short getVersion() {
251         return version;
252     }
253 
setVersion(short version)254     public void setVersion(short version) {
255         this.version = version;
256     }
257 
getVersionExtra()258     public short getVersionExtra() {
259         return versionExtra;
260     }
261 
setVersionExtra(short versionExtra)262     public void setVersionExtra(short versionExtra) {
263         this.versionExtra = versionExtra;
264     }
265 
getFlag()266     public short getFlag() {
267         return flag;
268     }
269 
setFlag(short flag)270     public void setFlag(short flag) {
271         this.flag = flag;
272     }
273 
getMethod()274     public short getMethod() {
275         return method;
276     }
277 
setMethod(short method)278     public void setMethod(short method) {
279         this.method = method;
280     }
281 
getLastTime()282     public short getLastTime() {
283         return lastTime;
284     }
285 
setLastTime(short lastTime)286     public void setLastTime(short lastTime) {
287         this.lastTime = lastTime;
288     }
289 
getLastDate()290     public short getLastDate() {
291         return lastDate;
292     }
293 
setLastDate(short lastDate)294     public void setLastDate(short lastDate) {
295         this.lastDate = lastDate;
296     }
297 
getCrc32()298     public int getCrc32() {
299         return crc32;
300     }
301 
setCrc32(int crc32)302     public void setCrc32(int crc32) {
303         this.crc32 = crc32;
304     }
305 
getCompressedSize()306     public long getCompressedSize() {
307         return compressedSize;
308     }
309 
setCompressedSize(long compressedSize)310     public void setCompressedSize(long compressedSize) {
311         this.compressedSize = compressedSize;
312     }
313 
getUnCompressedSize()314     public long getUnCompressedSize() {
315         return unCompressedSize;
316     }
317 
setUnCompressedSize(long unCompressedSize)318     public void setUnCompressedSize(long unCompressedSize) {
319         this.unCompressedSize = unCompressedSize;
320     }
321 
getFileNameLength()322     public int getFileNameLength() {
323         return fileNameLength;
324     }
325 
setFileNameLength(int fileNameLength)326     public void setFileNameLength(int fileNameLength) {
327         this.fileNameLength = fileNameLength;
328     }
329 
getExtraLength()330     public int getExtraLength() {
331         return extraLength;
332     }
333 
setExtraLength(int extraLength)334     public void setExtraLength(int extraLength) {
335         this.extraLength = extraLength;
336     }
337 
getCommentLength()338     public int getCommentLength() {
339         return commentLength;
340     }
341 
setCommentLength(int commentLength)342     public void setCommentLength(int commentLength) {
343         this.commentLength = commentLength;
344     }
345 
getDiskNumStart()346     public int getDiskNumStart() {
347         return diskNumStart;
348     }
349 
setDiskNumStart(int diskNumStart)350     public void setDiskNumStart(int diskNumStart) {
351         this.diskNumStart = diskNumStart;
352     }
353 
getInternalFile()354     public short getInternalFile() {
355         return internalFile;
356     }
357 
setInternalFile(short internalFile)358     public void setInternalFile(short internalFile) {
359         this.internalFile = internalFile;
360     }
361 
getExternalFile()362     public int getExternalFile() {
363         return externalFile;
364     }
365 
setExternalFile(int externalFile)366     public void setExternalFile(int externalFile) {
367         this.externalFile = externalFile;
368     }
369 
getOffset()370     public long getOffset() {
371         return offset;
372     }
373 
setOffset(long offset)374     public void setOffset(long offset) {
375         this.offset = offset;
376     }
377 
getFileName()378     public String getFileName() {
379         return fileName;
380     }
381 
setFileName(String fileName)382     public void setFileName(String fileName) {
383         this.fileName = fileName;
384     }
385 
getExtraData()386     public byte[] getExtraData() {
387         return extraData;
388     }
389 
setExtraData(byte[] extraData)390     public void setExtraData(byte[] extraData) {
391         this.extraData = extraData;
392     }
393 
getComment()394     public byte[] getComment() {
395         return comment;
396     }
397 
setComment(byte[] comment)398     public void setComment(byte[] comment) {
399         this.comment = comment;
400     }
401 
getLength()402     public int getLength() {
403         return length;
404     }
405 
setLength(int length)406     public void setLength(int length) {
407         this.length = length;
408     }
409 }