3030import software .coley .recaf .info .properties .builtin .ZipCommentProperty ;
3131import software .coley .recaf .info .properties .builtin .ZipCompressionProperty ;
3232import software .coley .recaf .info .properties .builtin .ZipCreationTimeProperty ;
33+ import software .coley .recaf .info .properties .builtin .ZipEntryIndexProperty ;
3334import software .coley .recaf .info .properties .builtin .ZipMarkerProperty ;
3435import software .coley .recaf .info .properties .builtin .ZipModificationTimeProperty ;
3536import software .coley .recaf .info .properties .builtin .ZipPrefixDataProperty ;
@@ -214,7 +215,10 @@ private WorkspaceFileResource handleZip(@Nonnull WorkspaceFileResourceBuilder bu
214215 ThreadPoolFactory .newFixedThreadPool ("zip-import" ) :
215216 ThreadPoolFactory .newSingleThreadExecutor ("zip-import" )) {
216217 List <Callable <Void >> tasks = new ArrayList <>();
217- for (LocalFileHeader header : archive .getLocalFiles ()) {
218+ List <LocalFileHeader > localFiles = archive .getLocalFiles ();
219+ for (int i = 0 ; i < localFiles .size (); i ++) {
220+ int entryIndex = i ;
221+ LocalFileHeader header = localFiles .get (i );
218222 tasks .add (() -> {
219223 LocalFileHeaderSource headerSource = new LocalFileHeaderSource (header , isAndroid );
220224 String entryName = header .getFileNameAsString ();
@@ -229,6 +233,7 @@ private WorkspaceFileResource handleZip(@Nonnull WorkspaceFileResourceBuilder bu
229233 Info info ;
230234 try {
231235 info = infoImporter .readInfo (entryName , headerSource );
236+ ZipEntryIndexProperty .set (info , entryIndex );
232237 } catch (IOException ex ) {
233238 logger .error ("IO error reading ZIP entry '{}' - skipping" , entryName , ex );
234239 return null ;
@@ -339,7 +344,6 @@ public FileVisitResult visitFile(@Nonnull Path file, @Nonnull BasicFileAttribute
339344 .build ();
340345 }
341346
342- @ SuppressWarnings ("all" ) // Ignore synchronizing on parameter
343347 private void addInfo (@ Nonnull BasicJvmClassBundle classes ,
344348 @ Nonnull BasicFileBundle files ,
345349 @ Nonnull Map <String , AndroidClassBundle > androidClassBundles ,
@@ -348,8 +352,6 @@ private void addInfo(@Nonnull BasicJvmClassBundle classes,
348352 @ Nonnull ByteSource infoSource ,
349353 @ Nonnull String pathName ,
350354 @ Nonnull Info info ) {
351- // TODO: The synchronization here should be more narrow to when each respective bundle/map is interacted with.
352- // These are all concurrent maps (or sync
353355 if (info .isClass ()) {
354356 addClassInfo (classes , files , versionedJvmClassBundles , pathName , info );
355357 } else if (info .isFile ()) {
@@ -527,12 +529,19 @@ private void addFileInfo(@Nonnull BasicFileBundle files,
527529 // Warn if there are duplicate file entries.
528530 // Same cases for why this may occur are described above when handling classes.
529531 // The JVM will always use the last item for duplicate entries anyways.
530- if (files .containsKey (pathName )) {
531- logger .warn ("Multiple duplicate entries for file '{}', dropping older entry" , pathName );
532- }
532+ synchronized (files ) {
533+ FileInfo existingFile = files .get (pathName );
534+ if (existingFile != null ) {
535+ int existingIndex = ZipEntryIndexProperty .getOr (existingFile , -1 );
536+ int newIndex = ZipEntryIndexProperty .getOr (fileInfo , -1 );
537+ if (newIndex < existingIndex )
538+ return ;
539+ logger .warn ("Multiple duplicate entries for file '{}', dropping older entry" , pathName );
540+ }
533541
534- // Store in bundle.
535- files .initialPut (fileInfo );
542+ // Store in bundle.
543+ files .initialPut (fileInfo );
544+ }
536545 }
537546
538547 /**
0 commit comments