55import jakarta .inject .Inject ;
66import software .coley .collections .func .UncheckedFunction ;
77import software .coley .lljzip .ZipIO ;
8+ import software .coley .lljzip .format .ZipPatterns ;
89import software .coley .lljzip .format .model .CentralDirectoryFileHeader ;
910import software .coley .lljzip .format .model .LocalFileHeader ;
1011import software .coley .lljzip .format .model .ZipArchive ;
12+ import software .coley .lljzip .format .read .ForwardScanZipReader ;
1113import software .coley .lljzip .format .read .JvmZipReader ;
14+ import software .coley .lljzip .format .read .NaiveLocalFileZipReader ;
15+ import software .coley .lljzip .format .read .SimpleZipPartAllocator ;
16+ import software .coley .lljzip .format .read .ZipPartAllocator ;
17+ import software .coley .lljzip .util .MemorySegmentUtil ;
18+ import software .coley .lljzip .util .data .MemorySegmentData ;
19+ import software .coley .lljzip .util .data .StringData ;
1220import software .coley .observables .ObservableBoolean ;
1321import software .coley .observables .ObservableInteger ;
1422import software .coley .observables .ObservableObject ;
1725import software .coley .recaf .config .ConfigGroups ;
1826import software .coley .recaf .services .ServiceConfig ;
1927
20- import java .util .List ;
28+ import java .lang .foreign .MemorySegment ;
29+
30+ import static software .coley .lljzip .util .MemorySegmentUtil .readLongSlice ;
2131
2232/**
2333 * Config for {@link ResourceImporter}.
@@ -29,7 +39,8 @@ public class ResourceImporterConfig extends BasicConfigContainer implements Serv
2939 private final ObservableObject <ZipStrategy > zipStrategy = new ObservableObject <>(ZipStrategy .JVM );
3040 private final ObservableBoolean skipRevisitedCenToLocalLinks = new ObservableBoolean (true );
3141 private final ObservableBoolean allowBasicJvmBaseOffsetZeroCheck = new ObservableBoolean (true );
32- private final ObservableBoolean ignoreNaiveFileLengths = new ObservableBoolean (false );
42+ private final ObservableBoolean ignoreFileLengths = new ObservableBoolean (false );
43+ private final ObservableBoolean adoptStandardCenFileNames = new ObservableBoolean (false );
3344 private final ObservableInteger maxEmbeddedZipDepth = new ObservableInteger (3 );
3445
3546 @ Inject
@@ -39,7 +50,8 @@ public ResourceImporterConfig() {
3950 addValue (new BasicConfigValue <>("zip-strategy" , ZipStrategy .class , zipStrategy ));
4051 addValue (new BasicConfigValue <>("skip-revisited-cen-to-local-links" , boolean .class , skipRevisitedCenToLocalLinks ));
4152 addValue (new BasicConfigValue <>("allow-basic-base-offset-zero-check" , boolean .class , allowBasicJvmBaseOffsetZeroCheck ));
42- addValue (new BasicConfigValue <>("ignore-naive-file-lengths" , boolean .class , ignoreNaiveFileLengths ));
53+ addValue (new BasicConfigValue <>("ignore-file-lengths" , boolean .class , ignoreFileLengths ));
54+ addValue (new BasicConfigValue <>("adapt-standard-cen-file-names" , boolean .class , adoptStandardCenFileNames ));
4355 addValue (new BasicConfigValue <>("max-embedded-zip-depth" , int .class , maxEmbeddedZipDepth ));
4456 }
4557
@@ -96,8 +108,8 @@ public ObservableBoolean getAllowBasicJvmBaseOffsetZeroCheck() {
96108 * @return {@code true} to ignore the reported file lengths when using {@link ZipStrategy#NAIVE}.
97109 */
98110 @ Nonnull
99- public ObservableBoolean getIgnoreNaiveFileLengths () {
100- return ignoreNaiveFileLengths ;
111+ public ObservableBoolean getIgnoreFileLengths () {
112+ return ignoreFileLengths ;
101113 }
102114
103115 /**
@@ -116,28 +128,62 @@ public ObservableInteger getMaxEmbeddedZipDepth() {
116128 public UncheckedFunction <byte [], ZipArchive > mapping () {
117129 ZipStrategy strategy = zipStrategy .getValue ();
118130 if (strategy == ZipStrategy .JVM )
119- return input -> ZipIO .read (input , new JvmZipReader (skipRevisitedCenToLocalLinks .getValue (),
120- allowBasicJvmBaseOffsetZeroCheck .getValue ()));
131+ return newJvmMapping ();
121132 if (strategy == ZipStrategy .STANDARD )
122- return ZipIO ::readStandard ;
123- return input -> {
124- ZipArchive archive = ZipIO .readNaive (input );
125- if (ignoreNaiveFileLengths .getValue ()) {
126- List <LocalFileHeader > items = archive .getLocalFiles ();
127- for (int i = 0 ; i < items .size (); i ++) {
128- LocalFileHeader lfh = items .get (i );
129- long nextStart = i < items .size () - 1 ?
130- items .get (i + 1 ).offset () :
131- input .length ;
132- long expectedEnd = lfh .offset () + lfh .length ();
133- if (expectedEnd < nextStart ) {
134- // TODO: Subtract nextStart here if data-descriptor is present
135- lfh .setFileDataEndOffset (nextStart );
136- }
133+ return newStandardMapping ();
134+ return newNaiveMapping ();
135+ }
136+
137+ @ Nonnull
138+ private UncheckedFunction <byte [], ZipArchive > newNaiveMapping () {
139+ return input -> ZipIO .read (input , new NaiveLocalFileZipReader (newPartAllocator ()));
140+ }
141+
142+ @ Nonnull
143+ private UncheckedFunction <byte [], ZipArchive > newStandardMapping () {
144+ return input -> ZipIO .read (input , new ForwardScanZipReader (newPartAllocator ()) {
145+ @ Override
146+ public void postProcessLocalFileHeader (@ Nonnull LocalFileHeader file ) {
147+ if (adoptStandardCenFileNames .getValue ()) {
148+ CentralDirectoryFileHeader directoryFileHeader = file .getLinkedDirectoryFileHeader ();
149+ if (directoryFileHeader != null )
150+ file .setFileName (StringData .of (directoryFileHeader .getFileNameAsString ()));
137151 }
138152 }
139- return archive ;
140- };
153+ });
154+ }
155+
156+ @ Nonnull
157+ private UncheckedFunction <byte [], ZipArchive > newJvmMapping () {
158+ return input -> ZipIO .read (input , new JvmZipReader (skipRevisitedCenToLocalLinks .getValue (), allowBasicJvmBaseOffsetZeroCheck .getValue ()));
159+ }
160+
161+ /**
162+ * @return Part allocator for Naive/Standard strategies.
163+ */
164+ @ Nonnull
165+ private ZipPartAllocator newPartAllocator () {
166+ if (ignoreFileLengths .getValue ()) {
167+ return new SimpleZipPartAllocator () {
168+ @ Nonnull
169+ @ Override
170+ public LocalFileHeader newLocalFileHeader () {
171+ return new LocalFileHeader () {
172+ @ Nonnull
173+ @ Override
174+ protected MemorySegmentData readFileData (@ Nonnull MemorySegment data , long headerOffset ) {
175+ long localOffset = MIN_FIXED_SIZE + getFileNameLength () + getExtraFieldLength ();
176+ long nextStart = MemorySegmentUtil .indexOfQuad (data , headerOffset + localOffset , ZipPatterns .LOCAL_FILE_HEADER_QUAD );
177+ long fileDataLength = nextStart > headerOffset ?
178+ nextStart - (headerOffset + localOffset ) :
179+ data .byteSize () - (headerOffset + localOffset );
180+ return MemorySegmentData .of (readLongSlice (data , headerOffset , localOffset , fileDataLength ));
181+ }
182+ };
183+ }
184+ };
185+ }
186+ return new SimpleZipPartAllocator ();
141187 }
142188
143189 /**
0 commit comments