[2/2] New zip magic
This commit is contained in:
parent
3cc7496b55
commit
0c51939e6d
|
|
@ -152,7 +152,7 @@ public class CentralDirectoryHeader implements Cloneable {
|
||||||
file = zFile;
|
file = zFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CentralDirectoryHeader link(String name, byte[] encodedFileName, GPFlags flags) {
|
public CentralDirectoryHeader link(String name, byte[] encodedFileName, GPFlags flags, ZFile file) {
|
||||||
var newData = new CentralDirectoryHeader(name,
|
var newData = new CentralDirectoryHeader(name,
|
||||||
encodedFileName,
|
encodedFileName,
|
||||||
uncompressedSize,
|
uncompressedSize,
|
||||||
|
|
@ -162,7 +162,7 @@ public class CentralDirectoryHeader implements Cloneable {
|
||||||
lastModTime,
|
lastModTime,
|
||||||
lastModDate);
|
lastModDate);
|
||||||
newData.extraField = extraField;
|
newData.extraField = extraField;
|
||||||
newData.offset = offset;
|
newData.offset = -1;
|
||||||
newData.internalAttributes = internalAttributes;
|
newData.internalAttributes = internalAttributes;
|
||||||
newData.externalAttributes = externalAttributes;
|
newData.externalAttributes = externalAttributes;
|
||||||
newData.comment = comment;
|
newData.comment = comment;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.android.tools.build.apkzlib.zip;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class NestedZip extends ZFile {
|
||||||
|
final Map<StoredEntry, String> links;
|
||||||
|
final ZFile target;
|
||||||
|
final StoredEntry entry;
|
||||||
|
|
||||||
|
public NestedZip(String name, ZFile target, File src, boolean mayCompress) throws IOException {
|
||||||
|
super(src, new ZFileOptions(), true);
|
||||||
|
this.target = target;
|
||||||
|
this.entry = target.add(name, directOpen(0, directSize()), mayCompress);
|
||||||
|
this.links = Maps.newHashMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addFileLink(String srcName, String dstName) throws IOException {
|
||||||
|
var srcEntry = get(srcName);
|
||||||
|
if (entry == null)
|
||||||
|
throw new IOException("Entry " + srcEntry + " does not exist in nested zip");
|
||||||
|
var offset = srcEntry.getCentralDirectoryHeader().getOffset() + srcEntry.getLocalHeaderSize();
|
||||||
|
if (offset < MAX_LOCAL_EXTRA_FIELD_CONTENTS_SIZE) {
|
||||||
|
target.addNestedLink(srcName, entry, srcEntry, (int) offset);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
links.put(srcEntry, dstName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<StoredEntry, String> getLinks() {
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZFile getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StoredEntry getEntry() {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,6 @@ import com.google.common.base.Preconditions;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
import com.google.common.base.Verify;
|
import com.google.common.base.Verify;
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
|
|
@ -159,7 +158,7 @@ public class StoredEntry {
|
||||||
private final StoredEntry linkedEntry;
|
private final StoredEntry linkedEntry;
|
||||||
|
|
||||||
/** Offset of the nested link */
|
/** Offset of the nested link */
|
||||||
private final int nestedLinkOffset = 0;
|
private final int nestedOffset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new stored entry.
|
* Creates a new stored entry.
|
||||||
|
|
@ -177,30 +176,34 @@ public class StoredEntry {
|
||||||
@Nullable ProcessedAndRawByteSources source,
|
@Nullable ProcessedAndRawByteSources source,
|
||||||
ByteStorage storage)
|
ByteStorage storage)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
this(header, file, source, storage, null);
|
this(header, file, source, storage, null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
StoredEntry(
|
StoredEntry(
|
||||||
String name,
|
String name,
|
||||||
ZFile file,
|
ZFile file,
|
||||||
ByteStorage storage,
|
ByteStorage storage,
|
||||||
StoredEntry linkedEntry)
|
StoredEntry linkedEntry,
|
||||||
|
StoredEntry nestedEntry,
|
||||||
|
int nestedOffset)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
this(linkedEntry.linkingCentralDirectoryHeader(name), file, linkedEntry.getSource(), storage, linkedEntry);
|
this((nestedEntry == null ? linkedEntry: nestedEntry).linkingCentralDirectoryHeader(name, file),
|
||||||
|
file, linkedEntry.getSource(), storage, linkedEntry, nestedOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CentralDirectoryHeader linkingCentralDirectoryHeader(String name) {
|
private CentralDirectoryHeader linkingCentralDirectoryHeader(String name, ZFile file) {
|
||||||
boolean encodeWithUtf8 = !EncodeUtils.canAsciiEncode(name);
|
boolean encodeWithUtf8 = !EncodeUtils.canAsciiEncode(name);
|
||||||
GPFlags flags = GPFlags.make(encodeWithUtf8);
|
GPFlags flags = GPFlags.make(encodeWithUtf8);
|
||||||
return cdh.link(name, EncodeUtils.encode(name, flags), flags);
|
return cdh.link(name, EncodeUtils.encode(name, flags), flags, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
StoredEntry(
|
private StoredEntry(
|
||||||
CentralDirectoryHeader header,
|
CentralDirectoryHeader header,
|
||||||
ZFile file,
|
ZFile file,
|
||||||
@Nullable ProcessedAndRawByteSources source,
|
@Nullable ProcessedAndRawByteSources source,
|
||||||
ByteStorage storage,
|
ByteStorage storage,
|
||||||
StoredEntry linkedEntry)
|
StoredEntry linkedEntry,
|
||||||
|
int nestedOffset)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
cdh = header;
|
cdh = header;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
|
|
@ -208,6 +211,7 @@ public class StoredEntry {
|
||||||
verifyLog = file.makeVerifyLog();
|
verifyLog = file.makeVerifyLog();
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
this.linkedEntry = linkedEntry;
|
this.linkedEntry = linkedEntry;
|
||||||
|
this.nestedOffset = nestedOffset;
|
||||||
|
|
||||||
if (header.getOffset() >= 0) {
|
if (header.getOffset() >= 0) {
|
||||||
readLocalHeader();
|
readLocalHeader();
|
||||||
|
|
@ -725,7 +729,7 @@ public class StoredEntry {
|
||||||
F_COMPRESSED_SIZE.write(out, compressInfo.getCompressedSize());
|
F_COMPRESSED_SIZE.write(out, compressInfo.getCompressedSize());
|
||||||
F_UNCOMPRESSED_SIZE.write(out, cdh.getUncompressedSize());
|
F_UNCOMPRESSED_SIZE.write(out, cdh.getUncompressedSize());
|
||||||
F_FILE_NAME_LENGTH.write(out, cdh.getEncodedFileName().length);
|
F_FILE_NAME_LENGTH.write(out, cdh.getEncodedFileName().length);
|
||||||
F_EXTRA_LENGTH.write(out, localExtra.size() + extraOffset);
|
F_EXTRA_LENGTH.write(out, localExtra.size() + extraOffset + nestedOffset);
|
||||||
|
|
||||||
out.put(cdh.getEncodedFileName());
|
out.put(cdh.getEncodedFileName());
|
||||||
localExtra.write(out);
|
localExtra.write(out);
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ public class ZFile implements Closeable {
|
||||||
* Minimum size for the extra field when we have to add one. We rely on the alignment segment to
|
* Minimum size for the extra field when we have to add one. We rely on the alignment segment to
|
||||||
* do that so the minimum size for the extra field is the minimum size of an alignment segment.
|
* do that so the minimum size for the extra field is the minimum size of an alignment segment.
|
||||||
*/
|
*/
|
||||||
private static final int MINIMUM_EXTRA_FIELD_SIZE = ExtraField.AlignmentSegment.MINIMUM_SIZE;
|
protected static final int MINIMUM_EXTRA_FIELD_SIZE = ExtraField.AlignmentSegment.MINIMUM_SIZE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum size of the extra field.
|
* Maximum size of the extra field.
|
||||||
|
|
@ -231,10 +231,10 @@ public class ZFile implements Closeable {
|
||||||
* <p>Theoretically, this is (1 << 16) - 1 = 65535 and not (1 < 15) -1 = 32767. However, due to
|
* <p>Theoretically, this is (1 << 16) - 1 = 65535 and not (1 < 15) -1 = 32767. However, due to
|
||||||
* http://b.android.com/221703, we need to keep this limited.
|
* http://b.android.com/221703, we need to keep this limited.
|
||||||
*/
|
*/
|
||||||
private static final int MAX_LOCAL_EXTRA_FIELD_CONTENTS_SIZE = (1 << 15) - 1;
|
protected static final int MAX_LOCAL_EXTRA_FIELD_CONTENTS_SIZE = (1 << 15) - 1;
|
||||||
|
|
||||||
/** File zip file. */
|
/** File zip file. */
|
||||||
private final File file;
|
protected final File file;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The random access file used to access the zip file. This will be {@code null} if and only if
|
* The random access file used to access the zip file. This will be {@code null} if and only if
|
||||||
|
|
@ -1768,18 +1768,23 @@ public class ZFile implements Closeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addLink(String name, StoredEntry linkedEntry)
|
public void addLink(String name, StoredEntry linkedEntry)
|
||||||
throws CloneNotSupportedException,IOException {
|
throws IOException {
|
||||||
|
addNestedLink(name, linkedEntry, null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addNestedLink(String name, StoredEntry linkedEntry, StoredEntry nestedEntry, int nestedOffset)
|
||||||
|
throws IOException {
|
||||||
Preconditions.checkArgument(linkedEntry != null, "linkedEntry is null");
|
Preconditions.checkArgument(linkedEntry != null, "linkedEntry is null");
|
||||||
Preconditions.checkArgument(linkedEntry.getCentralDirectoryHeader().getOffset() < 0, "linkedEntry is not new file");
|
Preconditions.checkArgument(linkedEntry.getCentralDirectoryHeader().getOffset() < 0, "linkedEntry is not new file");
|
||||||
Preconditions.checkArgument(!linkedEntry.isLinkingEntry(), "linkedEntry is a linking entry");
|
Preconditions.checkArgument(!linkedEntry.isLinkingEntry(), "linkedEntry is a linking entry");
|
||||||
var linkingEntry = new StoredEntry(name, this, storage, linkedEntry);
|
var linkingEntry = new StoredEntry(name, this, storage, linkedEntry, nestedEntry, nestedOffset);
|
||||||
linkingEntries.add(linkingEntry);
|
linkingEntries.add(linkingEntry);
|
||||||
linkedEntry.setLocalExtraNoNotify(new ExtraField(ImmutableList.<ExtraField.Segment>builder().add(linkedEntry.getLocalExtra().getSegments().toArray(new ExtraField.Segment[0])).add(new ExtraField.LinkingEntrySegment(linkingEntry)).build()));
|
linkedEntry.setLocalExtraNoNotify(new ExtraField(ImmutableList.<ExtraField.Segment>builder().add(linkedEntry.getLocalExtra().getSegments().toArray(new ExtraField.Segment[0])).add(new ExtraField.LinkingEntrySegment(linkingEntry)).build()));
|
||||||
|
reAdd(linkedEntry, PositionHint.LOWEST_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addNestedZipWithLinks(Map<String, String> nameMapping)
|
public NestedZip addNestedZip(String name, File src, boolean mayCompress) throws IOException {
|
||||||
throws CloneNotSupportedException,IOException {
|
return new NestedZip(name, this, src, mayCompress);
|
||||||
// TODO: nested link
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.android.apksig.internal.util.Pair;
|
||||||
import com.android.tools.build.apkzlib.sign.SigningExtension;
|
import com.android.tools.build.apkzlib.sign.SigningExtension;
|
||||||
import com.android.tools.build.apkzlib.sign.SigningOptions;
|
import com.android.tools.build.apkzlib.sign.SigningOptions;
|
||||||
import com.android.tools.build.apkzlib.zip.AlignmentRules;
|
import com.android.tools.build.apkzlib.zip.AlignmentRules;
|
||||||
|
import com.android.tools.build.apkzlib.zip.NestedZip;
|
||||||
import com.android.tools.build.apkzlib.zip.StoredEntry;
|
import com.android.tools.build.apkzlib.zip.StoredEntry;
|
||||||
import com.android.tools.build.apkzlib.zip.ZFile;
|
import com.android.tools.build.apkzlib.zip.ZFile;
|
||||||
import com.android.tools.build.apkzlib.zip.ZFileOptions;
|
import com.android.tools.build.apkzlib.zip.ZFileOptions;
|
||||||
|
|
@ -20,7 +21,6 @@ import org.lsposed.lspatch.share.Constants;
|
||||||
import org.lsposed.patch.util.ApkSignatureHelper;
|
import org.lsposed.patch.util.ApkSignatureHelper;
|
||||||
import org.lsposed.patch.util.ManifestParser;
|
import org.lsposed.patch.util.ManifestParser;
|
||||||
import org.lsposed.patch.util.NestedZipLink;
|
import org.lsposed.patch.util.NestedZipLink;
|
||||||
import org.lsposed.patch.util.NestedZipLink.NestedZip;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
@ -159,10 +159,7 @@ public class LSPatch {
|
||||||
|
|
||||||
System.out.println("Parsing original apk...");
|
System.out.println("Parsing original apk...");
|
||||||
|
|
||||||
try (ZFile srcZFile = ZFile.openReadOnly(srcApkFile); ZFile dstZFile = ZFile.openReadWrite(tmpApk, Z_FILE_OPTIONS)) {
|
try (ZFile dstZFile = ZFile.openReadWrite(tmpApk, Z_FILE_OPTIONS); var srcZFile = dstZFile.addNestedZip(ORIGINAL_APK_ASSET_PATH, srcApkFile, false)) {
|
||||||
// copy origin apk to assets
|
|
||||||
dstZFile.add(ORIGINAL_APK_ASSET_PATH, new FileInputStream(srcApkFile), false);
|
|
||||||
|
|
||||||
if (sigbypassLevel > 0) {
|
if (sigbypassLevel > 0) {
|
||||||
// save the apk original signature info, to support crack signature.
|
// save the apk original signature info, to support crack signature.
|
||||||
String originalSignature = ApkSignatureHelper.getApkSignInfo(srcApkFile.getAbsolutePath());
|
String originalSignature = ApkSignatureHelper.getApkSignInfo(srcApkFile.getAbsolutePath());
|
||||||
|
|
@ -259,8 +256,6 @@ public class LSPatch {
|
||||||
|
|
||||||
var embedded = embedModules(dstZFile);
|
var embedded = embedModules(dstZFile);
|
||||||
|
|
||||||
dstZFile.realign();
|
|
||||||
|
|
||||||
// create zip link
|
// create zip link
|
||||||
if (verbose)
|
if (verbose)
|
||||||
System.out.println("Creating nested apk link...");
|
System.out.println("Creating nested apk link...");
|
||||||
|
|
@ -286,8 +281,6 @@ public class LSPatch {
|
||||||
}
|
}
|
||||||
|
|
||||||
NestedZipLink nestedZipLink = new NestedZipLink(dstZFile, signingExtension);
|
NestedZipLink nestedZipLink = new NestedZipLink(dstZFile, signingExtension);
|
||||||
StoredEntry originalZipEntry = dstZFile.get(ORIGINAL_APK_ASSET_PATH);
|
|
||||||
NestedZip nestedZip = new NestedZip(srcZFile, originalZipEntry);
|
|
||||||
for (StoredEntry entry : srcZFile.entries()) {
|
for (StoredEntry entry : srcZFile.entries()) {
|
||||||
String name = entry.getCentralDirectoryHeader().getName();
|
String name = entry.getCentralDirectoryHeader().getName();
|
||||||
if (name.startsWith("classes") && name.endsWith(".dex")) continue;
|
if (name.startsWith("classes") && name.endsWith(".dex")) continue;
|
||||||
|
|
@ -295,21 +288,21 @@ public class LSPatch {
|
||||||
if (name.equals("AndroidManifest.xml")) continue;
|
if (name.equals("AndroidManifest.xml")) continue;
|
||||||
if (name.startsWith("META-INF/CERT")) continue;
|
if (name.startsWith("META-INF/CERT")) continue;
|
||||||
if (name.equals("META-INF/MANIFEST.MF")) continue;
|
if (name.equals("META-INF/MANIFEST.MF")) continue;
|
||||||
nestedZip.addFileLink(name, name);
|
srcZFile.addFileLink(name, name);
|
||||||
}
|
}
|
||||||
nestedZipLink.nestedZips.add(nestedZip);
|
nestedZipLink.nestedZips.add(srcZFile);
|
||||||
|
|
||||||
for (var pair : embedded) {
|
// for (var pair : embedded) {
|
||||||
ZFile moduleZFile = ZFile.openReadOnly(pair.getFirst());
|
// ZFile moduleZFile = ZFile.openReadOnly(pair.getFirst());
|
||||||
StoredEntry moduleEntry = dstZFile.get("assets/modules/" + pair.getSecond() + ".bin");
|
// StoredEntry moduleEntry = dstZFile.get("assets/modules/" + pair.getSecond() + ".bin");
|
||||||
nestedZip = new NestedZip(moduleZFile, moduleEntry);
|
// nestedZip = new NestedZip(dstZFile, moduleZFile, moduleEntry);
|
||||||
for (var nestedEntry : moduleZFile.entries()) {
|
// for (var nestedEntry : moduleZFile.entries()) {
|
||||||
var name = nestedEntry.getCentralDirectoryHeader().getName();
|
// var name = nestedEntry.getCentralDirectoryHeader().getName();
|
||||||
if (name.startsWith("lib/"))
|
// if (name.startsWith("lib/"))
|
||||||
nestedZip.addFileLink(name, "assets/lib/" + pair.getSecond() + name.substring(3));
|
// nestedZip.addFileLink(name, "assets/lib/" + pair.getSecond() + name.substring(3));
|
||||||
}
|
// }
|
||||||
nestedZipLink.nestedZips.add(nestedZip);
|
// nestedZipLink.nestedZips.add(nestedZip);
|
||||||
}
|
// }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
nestedZipLink.register();
|
nestedZipLink.register();
|
||||||
|
|
@ -317,6 +310,8 @@ public class LSPatch {
|
||||||
throw new PatchError("Failed to create link", e);
|
throw new PatchError("Failed to create link", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dstZFile.realign();
|
||||||
|
|
||||||
System.out.println("Done. Output APK: " + outputFile.getAbsolutePath());
|
System.out.println("Done. Output APK: " + outputFile.getAbsolutePath());
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import com.android.tools.build.apkzlib.sign.SigningExtension;
|
||||||
import com.android.tools.build.apkzlib.utils.IOExceptionRunnable;
|
import com.android.tools.build.apkzlib.utils.IOExceptionRunnable;
|
||||||
import com.android.tools.build.apkzlib.zip.CentralDirectoryHeader;
|
import com.android.tools.build.apkzlib.zip.CentralDirectoryHeader;
|
||||||
import com.android.tools.build.apkzlib.zip.EncodeUtils;
|
import com.android.tools.build.apkzlib.zip.EncodeUtils;
|
||||||
|
import com.android.tools.build.apkzlib.zip.NestedZip;
|
||||||
import com.android.tools.build.apkzlib.zip.StoredEntry;
|
import com.android.tools.build.apkzlib.zip.StoredEntry;
|
||||||
import com.android.tools.build.apkzlib.zip.ZFile;
|
import com.android.tools.build.apkzlib.zip.ZFile;
|
||||||
import com.android.tools.build.apkzlib.zip.ZFileExtension;
|
import com.android.tools.build.apkzlib.zip.ZFileExtension;
|
||||||
|
|
@ -21,21 +22,6 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class NestedZipLink extends ZFileExtension {
|
public class NestedZipLink extends ZFileExtension {
|
||||||
public static class NestedZip {
|
|
||||||
final Set<Pair<String, String>> links;
|
|
||||||
final ZFile zip;
|
|
||||||
final StoredEntry entry;
|
|
||||||
|
|
||||||
public NestedZip(ZFile zip, StoredEntry entry) {
|
|
||||||
this.zip = zip;
|
|
||||||
this.entry = entry;
|
|
||||||
this.links = new HashSet<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addFileLink(String srcName, String dstName) {
|
|
||||||
links.add(Pair.of(srcName, dstName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final ZFile zFile;
|
public final ZFile zFile;
|
||||||
|
|
||||||
|
|
@ -61,11 +47,9 @@ public class NestedZipLink extends ZFileExtension {
|
||||||
var signer = (ApkSignerEngine) signerField.get(signingExtension);
|
var signer = (ApkSignerEngine) signerField.get(signingExtension);
|
||||||
|
|
||||||
for (var nestedZip : nestedZips) {
|
for (var nestedZip : nestedZips) {
|
||||||
for (var link : nestedZip.links) {
|
for (var link : nestedZip.getLinks().entrySet()) {
|
||||||
var entry = nestedZip.zip.get(link.getFirst());
|
var entry = link.getKey();
|
||||||
if (entry == null)
|
notifySigner(signer, link.getValue(), entry);
|
||||||
throw new IOException("Entry " + link + " does not exist in nested zip");
|
|
||||||
notifySigner(signer, link.getFirst(), entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,18 +103,16 @@ public class NestedZipLink extends ZFileExtension {
|
||||||
|
|
||||||
var entries = (Map<String, Object>) field_entries.get(zFile);
|
var entries = (Map<String, Object>) field_entries.get(zFile);
|
||||||
for (var nestedZip : nestedZips) {
|
for (var nestedZip : nestedZips) {
|
||||||
long nestedZipOffset = nestedZip.entry.getCentralDirectoryHeader().getOffset();
|
long nestedZipOffset = nestedZip.getEntry().getCentralDirectoryHeader().getOffset();
|
||||||
for (var link : nestedZip.links) {
|
for (var link : nestedZip.getLinks().entrySet()) {
|
||||||
var entry = nestedZip.zip.get(link.getFirst());
|
var entry = link.getKey();
|
||||||
if (entry == null)
|
|
||||||
throw new IOException("Entry " + link + " does not exist in nested zip");
|
|
||||||
CentralDirectoryHeader cdh = entry.getCentralDirectoryHeader();
|
CentralDirectoryHeader cdh = entry.getCentralDirectoryHeader();
|
||||||
field_entry_file.set(entry, zFile);
|
field_entry_file.set(entry, zFile);
|
||||||
field_cdh_file.set(cdh, zFile);
|
field_cdh_file.set(cdh, zFile);
|
||||||
field_cdh_encodedFileName.set(cdh, encodeFileName(link.getSecond()));
|
field_cdh_encodedFileName.set(cdh, encodeFileName(link.getValue()));
|
||||||
field_cdh_offset.set(cdh, nestedZipOffset + cdh.getOffset() + nestedZip.entry.getLocalHeaderSize());
|
field_cdh_offset.set(cdh, nestedZipOffset + cdh.getOffset() + nestedZip.getEntry().getLocalHeaderSize());
|
||||||
var newFileUseMapEntry = makeFree.invoke(null, 0, 1, entry);
|
var newFileUseMapEntry = makeFree.invoke(null, 0, 1, entry);
|
||||||
entries.put(link.getSecond(), newFileUseMapEntry);
|
entries.put(link.getValue(), newFileUseMapEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
computeCentralDirectory.invoke(zFile);
|
computeCentralDirectory.invoke(zFile);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue