1 /* 2 * Copyright (c) 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; 17 18 import java.io.File; 19 import java.io.FileOutputStream; 20 import java.io.IOException; 21 import java.io.InputStream; 22 import java.util.ArrayList; 23 import java.util.Collections; 24 import java.util.Enumeration; 25 import java.util.List; 26 import java.util.TimeZone; 27 import java.util.zip.ZipOutputStream; 28 import java.util.zip.ZipEntry; 29 import java.util.zip.ZipFile; 30 31 /** 32 * Zip align 33 * 34 * @since 2023-2-20 35 */ 36 public class ZipAlign { 37 private static final long TIMESTAMP = 1230768000000L; 38 private static final int COMPRESSION_MODE = 0; 39 private static final int STORED_ENTRY_SO_ALIGNMENT = 4096; 40 private static final int BUFFER_LENGTH = 4096; 41 private static final long INIT_OFFSET_LEN = 0L; 42 copyFileAndAlignment(File input, File tmpOutput, int alignment)43 private static void copyFileAndAlignment(File input, File tmpOutput, int alignment) throws IOException { 44 try (ZipFile inputZip = new ZipFile(input); 45 FileOutputStream outputFile = new FileOutputStream(tmpOutput); 46 ZipOutputStream outputZip = new ZipOutputStream(outputFile)) { 47 long timestamp = TIMESTAMP; 48 timestamp -= TimeZone.getDefault().getOffset(timestamp); 49 outputZip.setLevel(COMPRESSION_MODE); 50 List<String> entryNames = getEntryNamesFromZip(inputZip); 51 copyFiles(entryNames, inputZip, outputZip, timestamp, alignment); 52 } 53 } 54 copyFiles(List<String> entryNames, ZipFile in, ZipOutputStream out, long timestamp, int defaultAlignment)55 private static void copyFiles(List<String> entryNames, ZipFile in, ZipOutputStream out, long timestamp, 56 int defaultAlignment) throws IOException { 57 Collections.sort(entryNames); 58 long fileOffset = INIT_OFFSET_LEN; 59 for (String name : entryNames) { 60 ZipEntry inEntry = in.getEntry(name); 61 if (inEntry.getMethod() != ZipEntry.STORED) { 62 continue; 63 } 64 65 fileOffset += ZipFile.LOCHDR; 66 67 ZipEntry outEntry = new ZipEntry(inEntry); 68 outEntry.setTime(timestamp); 69 70 outEntry.setComment(null); 71 outEntry.setExtra(null); 72 73 fileOffset += outEntry.getName().length(); 74 75 int alignment = getStoredEntryDataAlignment(name, defaultAlignment); 76 if (alignment > 0 && (fileOffset % alignment != 0)) { 77 int needed = alignment - (int) (fileOffset % alignment); 78 outEntry.setExtra(new byte[needed]); 79 fileOffset += needed; 80 } 81 82 out.putNextEntry(outEntry); 83 byte[] buffer = new byte[BUFFER_LENGTH]; 84 try (InputStream data = in.getInputStream(inEntry)) { 85 int num; 86 while ((num = data.read(buffer)) > 0) { 87 out.write(buffer, 0, num); 88 fileOffset += num; 89 } 90 out.flush(); 91 } 92 } 93 } 94 getStoredEntryDataAlignment(String entryData, int defaultAlignment)95 private static int getStoredEntryDataAlignment(String entryData, int defaultAlignment) { 96 if (defaultAlignment <= 0) { 97 return 0; 98 } 99 if (entryData.endsWith(".so")) { 100 return STORED_ENTRY_SO_ALIGNMENT; 101 } 102 return defaultAlignment; 103 } 104 getEntryNamesFromZip(ZipFile zipFile)105 private static List<String> getEntryNamesFromZip(ZipFile zipFile) { 106 List<String> result = new ArrayList<String>(); 107 for (Enumeration e = zipFile.entries(); e.hasMoreElements();) { 108 Object nextEntry = e.nextElement(); 109 if (nextEntry instanceof ZipEntry) { 110 ZipEntry entry = (ZipEntry) nextEntry; 111 if (!entry.isDirectory()) { 112 result.add(entry.getName()); 113 } 114 } 115 } 116 return result; 117 } 118 main(String[] args)119 public static void main(String[] args) { 120 System.out.println("copyFileAndAlignment start"); 121 if (args.length != 3) { 122 System.out.println("input param error"); 123 return; 124 } 125 String inputFilePath = args[0]; 126 File inputFile = new File(inputFilePath); 127 String outputFilePath = args[1]; 128 File outputFile = new File(outputFilePath); 129 try { 130 int alignment = Integer.parseInt(args[2]); 131 copyFileAndAlignment(inputFile, outputFile, alignment); 132 } catch (NumberFormatException nfe) { 133 System.out.println("alignment parse error: " + args[2]); 134 } catch (IOException ioe) { 135 System.out.println(ioe.getMessage()); 136 } 137 System.out.println("copyFileAndAlignment success"); 138 } 139 }