diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/CentralDirectory.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/CentralDirectory.java index 04adc9b4260579ab487baa6b3a972068313d03bd..37e8d1d02c8258fbbd222b7e51c735b45aec0c3f 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/CentralDirectory.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/CentralDirectory.java @@ -155,6 +155,13 @@ public class CentralDirectory { private int length; + /** + * updateLength + */ + public void updateLength() { + length = CD_LENGTH + fileNameLength + extraLength + commentLength; + } + /** * get Central Directory * @@ -199,7 +206,7 @@ public class CentralDirectory { bf.get(readComment); cd.setComment(readComment); } - cd.setLength(CD_LENGTH + cd.getFileNameLength() + cd.getExtraLength() + cd.getCommentLength()); + cd.updateLength(); return cd; } diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/EntryType.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/EntryType.java new file mode 100644 index 0000000000000000000000000000000000000000..46d44b136242b291b6fcbb3d9195558dc454a531 --- /dev/null +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/EntryType.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ohos.hapsigntool.zip; + +/** + * Entry Type + * + * @since 2024/06/25 + */ +public enum EntryType { + RunnableFile, + BitMap, + ResourceFile; +} diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/Zip.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/Zip.java index 7ab9bdc2ed2b9a31894b6837620bd6b1d93411f9..828543e8d3b8df1c44d5d3bb890f3dcf7d1a90a9 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/Zip.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/Zip.java @@ -43,7 +43,7 @@ public class Zip { /** * file is uncompress file flag */ - public static final int FILE_UNCOMPRESS_METHOD_FLAG = 0; + public static final short FILE_UNCOMPRESS_METHOD_FLAG = 0; /** * max comment length @@ -172,6 +172,12 @@ public class Zip { long fileSize = cd.getMethod() == FILE_UNCOMPRESS_METHOD_FLAG ? unCompressedSize : compressedSize; ZipEntryData zipEntryData = ZipEntryData.getZipEntry(file, offset, fileSize); + if (zipEntryData.getZipEntryHeader().getMethod() == FILE_UNCOMPRESS_METHOD_FLAG + && FileUtils.isRunnableFile(zipEntryData.getZipEntryHeader().getFileName())) { + zipEntryData.setType(EntryType.RunnableFile); + } else { + zipEntryData.setType(EntryType.ResourceFile); + } if (cDOffset - offset < zipEntryData.getLength()) { throw new ZipException("cd offset in front of entry end"); } @@ -189,8 +195,15 @@ public class Zip { for (ZipEntry entry : zipEntries) { ZipEntryData zipEntryData = entry.getZipEntryData(); FileUtils.writeByteToOutFile(zipEntryData.getZipEntryHeader().toBytes(), fos); - boolean isSuccess = FileUtils.appendWriteFileByOffsetToFile(file, fos, - zipEntryData.getFileOffset(), zipEntryData.getFileSize()); + boolean isSuccess; + if (entry.getZipEntryData().getType() == EntryType.BitMap) { + ByteBuffer bf = ByteBuffer.wrap(entry.getZipEntryData().getData()); + bf.order(ByteOrder.LITTLE_ENDIAN); + isSuccess = FileUtils.writeByteToOutFile(bf.array(), fos); + } else { + isSuccess = FileUtils.appendWriteFileByOffsetToFile(file, fos, + zipEntryData.getFileOffset(), zipEntryData.getFileSize()); + } if (!isSuccess) { throw new ZipException("write zip data failed"); } @@ -250,6 +263,16 @@ public class Zip { } } + public void addBitMap(byte[] data) throws ZipException { + ZipEntry entry = new ZipEntry.Builder().setMethod(FILE_UNCOMPRESS_METHOD_FLAG) + .setUncompressedSize(data.length) + .setCompressedSize(data.length) + .setFileName("pages.info") + .setData(data) + .build(); + zipEntries.add(entry); + } + /** * remove sign block */ @@ -262,22 +285,20 @@ public class Zip { * sort uncompress entry in the front. */ private void sort() { - // sort uncompress file (so, abc, an) - other uncompress file - compress file + // sort uncompress file (so, abc, an) - bitmap - other uncompress file - compress file zipEntries.sort((entry1, entry2) -> { + EntryType entry1Type = entry1.getZipEntryData().getType(); + EntryType entry2Type = entry2.getZipEntryData().getType(); + if (entry1Type != entry2Type) { + return entry1Type.compareTo(entry2Type); + } + short entry1Method = entry1.getZipEntryData().getZipEntryHeader().getMethod(); short entry2Method = entry2.getZipEntryData().getZipEntryHeader().getMethod(); String entry1FileName = entry1.getZipEntryData().getZipEntryHeader().getFileName(); String entry2FileName = entry2.getZipEntryData().getZipEntryHeader().getFileName(); if (entry1Method == FILE_UNCOMPRESS_METHOD_FLAG && entry2Method == FILE_UNCOMPRESS_METHOD_FLAG) { - boolean isRunnableFile1 = FileUtils.isRunnableFile(entry1FileName); - boolean isRunnableFile2 = FileUtils.isRunnableFile(entry2FileName); - if (isRunnableFile1 && isRunnableFile2) { - return entry1FileName.compareTo(entry2FileName); - } else if (isRunnableFile1) { - return -1; - } else if (isRunnableFile2) { - return 1; - } + return entry1FileName.compareTo(entry2FileName); } else if (entry1Method == FILE_UNCOMPRESS_METHOD_FLAG) { return -1; } else if (entry2Method == FILE_UNCOMPRESS_METHOD_FLAG) { @@ -292,6 +313,7 @@ public class Zip { long offset = 0L; long cdLength = 0L; for (ZipEntry entry : zipEntries) { + entry.updateLength(); entry.getCentralDirectory().setOffset(offset); offset += entry.getZipEntryData().getLength(); cdLength += entry.getCentralDirectory().getLength(); @@ -304,6 +326,8 @@ public class Zip { endOfCentralDirectory.setcDSize(cdLength); offset += cdLength; eOCDOffset = offset; + endOfCentralDirectory.setcDTotal(zipEntries.size()); + endOfCentralDirectory.setThisDiskCDNum(zipEntries.size()); } public List getZipEntries() { diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntry.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntry.java index ff66339ad690b1ddacba48b9ec301cb80c16dc5e..82d7a2fb693f16f8171a8352556046e7e79f0cf5 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntry.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntry.java @@ -18,6 +18,7 @@ package com.ohos.hapsigntool.zip; import com.ohos.hapsigntool.error.ZipException; import java.util.Arrays; +import java.util.zip.CRC32; /** * ZipEntry and CentralDirectory data @@ -27,7 +28,15 @@ import java.util.Arrays; public class ZipEntry { private ZipEntryData zipEntryData; - private CentralDirectory fileEntryIncentralDirectory; + private CentralDirectory fileEntryInCentralDirectory; + + /** + * updateLength + */ + public void updateLength() { + zipEntryData.updateLength(); + fileEntryInCentralDirectory.updateLength(); + } /** * alignment one entry @@ -40,7 +49,7 @@ public class ZipEntry { // if cd extra len bigger than entry extra len, make cd and entry extra length equals int padding = calZeroPaddingLengthForEntryExtra(); int remainder = (int) ((zipEntryData.getZipEntryHeader().getLength() - + fileEntryIncentralDirectory.getOffset()) % alignNum); + + fileEntryInCentralDirectory.getOffset()) % alignNum); if (remainder == 0) { return padding; @@ -58,7 +67,7 @@ public class ZipEntry { private int calZeroPaddingLengthForEntryExtra() throws ZipException { int entryExtraLen = zipEntryData.getZipEntryHeader().getExtraLength(); - int cdExtraLen = fileEntryIncentralDirectory.getExtraLength(); + int cdExtraLen = fileEntryInCentralDirectory.getExtraLength(); if (cdExtraLen > entryExtraLen) { setEntryHeaderNewExtraLength(cdExtraLen); return cdExtraLen - entryExtraLen; @@ -71,12 +80,12 @@ public class ZipEntry { } private void setCenterDirectoryNewExtraLength(int newLength) throws ZipException { - byte[] newCDExtra = getAlignmentNewExtra(newLength, fileEntryIncentralDirectory.getExtraData()); - fileEntryIncentralDirectory.setExtraData(newCDExtra); - fileEntryIncentralDirectory.setExtraLength(newLength); - fileEntryIncentralDirectory.setLength(CentralDirectory.CD_LENGTH - + fileEntryIncentralDirectory.getFileNameLength() - + fileEntryIncentralDirectory.getExtraLength() + fileEntryIncentralDirectory.getCommentLength()); + byte[] newCDExtra = getAlignmentNewExtra(newLength, fileEntryInCentralDirectory.getExtraData()); + fileEntryInCentralDirectory.setExtraData(newCDExtra); + fileEntryInCentralDirectory.setExtraLength(newLength); + fileEntryInCentralDirectory.setLength(CentralDirectory.CD_LENGTH + + fileEntryInCentralDirectory.getFileNameLength() + + fileEntryInCentralDirectory.getExtraLength() + fileEntryInCentralDirectory.getCommentLength()); } private void setEntryHeaderNewExtraLength(int newLength) throws ZipException { @@ -109,10 +118,143 @@ public class ZipEntry { } public CentralDirectory getCentralDirectory() { - return fileEntryIncentralDirectory; + return fileEntryInCentralDirectory; } public void setCentralDirectory(CentralDirectory centralDirectory) { - this.fileEntryIncentralDirectory = centralDirectory; + this.fileEntryInCentralDirectory = centralDirectory; + } + + public static class Builder { + private short version = 10; + + private short flag = 2048; + + private short method = 0; + + private long compressedSize; + + private long unCompressedSize; + + private String fileName; + + private byte[] extraData; + + private byte[] comment; + + private byte[] data; + + public Builder setVersion(short version) { + this.version = version; + return this; + } + + public Builder setFlag(short flag) { + this.flag = flag; + return this; + } + + public Builder setMethod(short method) { + this.method = method; + return this; + } + + public Builder setCompressedSize(long compressedSize) { + this.compressedSize = compressedSize; + return this; + } + + public Builder setUncompressedSize(long unCompressedSize) { + this.unCompressedSize = unCompressedSize; + return this; + } + + public Builder setFileName(String fileName) { + this.fileName = fileName; + return this; + } + + public Builder setExtraData(byte[] extraData) { + this.extraData = extraData; + return this; + } + + public Builder setComment(byte[] comment) { + this.comment = comment; + return this; + } + + public Builder setData(byte[] data) { + this.data = data; + return this; + } + + public ZipEntry build() throws ZipException { + ZipEntry entry = new ZipEntry(); + ZipEntryData zipEntryData = new ZipEntryData(); + zipEntryData.setData(data); + + ZipEntryHeader zipEntryHeader = new ZipEntryHeader(); + CentralDirectory cd = new CentralDirectory(); + + cd.setVersion(version); + cd.setVersionExtra(version); + zipEntryHeader.setVersion(version); + cd.setFlag(flag); + zipEntryHeader.setFlag(flag); + cd.setMethod(method); + zipEntryHeader.setMethod(method); + + cd.setLastTime((short) 0); + cd.setLastDate((short) 20001); + zipEntryHeader.setLastTime((short) 0); + zipEntryHeader.setLastDate((short) 20001); + + cd.setCompressedSize(compressedSize); + zipEntryHeader.setCompressedSize(compressedSize); + cd.setUnCompressedSize(unCompressedSize); + zipEntryHeader.setUnCompressedSize(unCompressedSize); + + cd.setFileName(fileName); + cd.setFileNameLength(fileName.length()); + zipEntryHeader.setFileName(fileName); + zipEntryHeader.setFileNameLength(fileName.length()); + + if (extraData != null) { + cd.setExtraData(extraData); + cd.setExtraLength(extraData.length); + zipEntryHeader.setExtraData(extraData); + zipEntryHeader.setExtraLength(extraData.length); + } else { + cd.setExtraLength(0); + zipEntryHeader.setExtraLength(0); + } + if (comment != null) { + cd.setComment(comment); + cd.setCommentLength(comment.length); + } else { + cd.setCommentLength(0); + } + cd.setDiskNumStart(0); + cd.setExternalFile(0); + + cd.updateLength(); + zipEntryHeader.updateLength(); + + if (data == null) { + throw new ZipException("can not find entry data"); + } + final CRC32 c = new CRC32(); + c.update(data); + final int crc32 = new Long(c.getValue()).intValue(); + cd.setCrc32(crc32); + zipEntryHeader.setCrc32(crc32); + + zipEntryData.setZipEntryHeader(zipEntryHeader); + entry.setZipEntryData(zipEntryData); + zipEntryData.setType(EntryType.BitMap); + entry.setCentralDirectory(cd); + return entry; + } } } \ No newline at end of file diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntryData.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntryData.java index 35b19e7ad5833b31343f479a92d321a808507651..4007be318c1eb3414a3f7aec41bdb53a4f8a6514 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntryData.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntryData.java @@ -51,6 +51,22 @@ public class ZipEntryData { return zipEntryHeader; } + private EntryType type; + + private byte[] data; + + /** + * updateLength + */ + public void updateLength() { + zipEntryHeader.updateLength(); + if (type == EntryType.BitMap) { + length = zipEntryHeader.getLength() + data.length + (dataDescriptor == null ? 0 : 16); + } else { + length = zipEntryHeader.getLength() + fileSize + (dataDescriptor == null ? 0 : 16); + } + } + /** * init zip entry by file * @@ -140,4 +156,20 @@ public class ZipEntryData { public void setLength(long length) { this.length = length; } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } + + public EntryType getType() { + return type; + } + + public void setType(EntryType type) { + this.type = type; + } } \ No newline at end of file diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntryHeader.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntryHeader.java index 7c880a6bea5a14cb38fa5da1a9e7a777a0ef890f..d020c8fa237577be67bf44f40af1b98852003f5b 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntryHeader.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/zip/ZipEntryHeader.java @@ -113,6 +113,13 @@ public class ZipEntryHeader { private int length; + /** + * updateLength + */ + public void updateLength() { + length = HEADER_LENGTH + fileNameLength + extraLength; + } + /** * get Zip Entry Header * @@ -137,7 +144,7 @@ public class ZipEntryHeader { entryHeader.setUnCompressedSize(UnsignedDecimalUtil.getUnsignedInt(bf)); entryHeader.setFileNameLength(UnsignedDecimalUtil.getUnsignedShort(bf)); entryHeader.setExtraLength(UnsignedDecimalUtil.getUnsignedShort(bf)); - entryHeader.setLength(HEADER_LENGTH + entryHeader.getFileNameLength() + entryHeader.getExtraLength()); + entryHeader.updateLength(); return entryHeader; }