Skip to content

Commit

Permalink
Proposal: Opening/Closing Mechanism for Zip Files
Browse files Browse the repository at this point in the history
The Eclipse IDE has no built in functionality to open Zip Files and read or manipulate their content. Because of this, other operations like searching inside of Zip Files or comparing two Zip Files were also not possible.

This pull request introduces a mechanism for handling Zip Files within the Eclipse workspace, enhancing the functionality to read and write Zip files. The primary goal is to provide a seamless experience for developers working with zip archives directly within Eclipse.

Zip files must be opened manually within the workspace by using the new command "Open Zip File" in the menu when right clicking the zip file. It is also possible to open nested zip files.

Zip Files are opened by replacing the file in the workspace with a linked folder that reads and writes the Zip File in the file system. By closing the Zip FIle, the linked folder will be deleted and the file can be seen in the workspace again.

Please note that only ZIP Archives are supported in this current implementation. Other archive types can be added in future improvements. Also linked Zip Files can not be opened with this implementation because the Zip File must be local.

An additional PR for the repository **eclipse.platform.ui** that grants access to the open/close mechanism for zip files over UI can be found in the following:

eclipse-platform/eclipse.platform.ui#1947

Co-Authored-By: David <David.Erdoes @vector.com>
  • Loading branch information
2 people authored and Michael5601 committed Jun 10, 2024
1 parent 309a7f0 commit ff816b0
Show file tree
Hide file tree
Showing 36 changed files with 2,308 additions and 571 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.core.filesystem; singleton:=true
Bundle-Version: 1.10.400.qualifier
Bundle-Version: 1.11.0.qualifier
Bundle-Localization: plugin
Require-Bundle: org.eclipse.equinox.common;bundle-version="[3.18.0,4.0.0)",
org.eclipse.equinox.registry;bundle-version="[3.2.0,4.0.0)",
Expand Down
7 changes: 7 additions & 0 deletions resources/bundles/org.eclipse.core.filesystem/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,11 @@
<run class="org.eclipse.core.internal.filesystem.NullFileSystem"/>
</filesystem>
</extension>
<extension
id="org.eclipse.core.filesystem.zip"
point="org.eclipse.core.filesystem.filesystems">
<filesystem scheme="zip">
<run class="org.eclipse.core.internal.filesystem.zip.ZipFileSystem"/>
</filesystem>
</extension>
</plugin>
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*******************************************************************************
* Copyright (c) 2024 Vector Informatik GmbH and others.
*
* This program and the accompanying materials are made available under the terms of the Eclipse
* Public License 2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors: Vector Informatik GmbH - initial API and implementation
*******************************************************************************/

package org.eclipse.core.filesystem;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.internal.filesystem.zip.ZipFileStore;
import org.eclipse.core.runtime.CoreException;

/**
* Utility class to determine if a file is an archive based on file header information.
* This class checks for known file signatures to identify if a given file is a ZIP archive
* or a format based on ZIP, such as EPUB, JAR, ODF, and OOXML.
*
* @since 1.11
*/
public class ZipFileUtil {

private static final Set<Integer> ARCHIVE_FILE_SIGNATURES = new HashSet<>();

static {
// Initializes known archive file signatures from Wikipedia's list of file signatures
// (https://en.wikipedia.org/wiki/List_of_file_signatures)
ARCHIVE_FILE_SIGNATURES.add(0x504B0304); // Standard ZIP file
ARCHIVE_FILE_SIGNATURES.add(0x504B0506); // Empty archive
ARCHIVE_FILE_SIGNATURES.add(0x504B0708); // Spanned archive
}

/**
* Determines if the given {@link IFileStore} represents an open ZIP file.
* This can be used to check if operations on a ZIP file should be allowed or handled differently.
*
* @param store The file store to check.
* @return true if the store is an instance of {@link ZipFileStore}, false otherwise.
*/
public static boolean isInsideOpenZipFile(IFileStore store) {
return store instanceof ZipFileStore;
}

public static boolean isInsideOpenZipFile(URI locationURI) {
IFileStore store;
try {
store = EFS.getStore(locationURI);
} catch (CoreException e) {
return false;
}
return isInsideOpenZipFile(store);
}

//TODO Implement this method
public static boolean isOpenZipFile(IFileStore store) {
if (isInsideOpenZipFile(store)) {
ZipFileStore zipStore = (ZipFileStore) store;
return zipStore.getPath().isEmpty(); //if path is empty its the root
}
return false;
}

public static boolean isOpenZipFile(URI locationURI) {
IFileStore store;
try {
store = EFS.getStore(locationURI);
} catch (CoreException e) {
return false;
}
return isOpenZipFile(store);
}

public static boolean isNested(URI fileURI) {
if (fileURI.getScheme().contains("zip")) { //$NON-NLS-1$
return true;
}
return false;
}

/**
* Checks if the provided {@link InputStream} represents a ZIP archive
* by reading its first four bytes and comparing them against known ZIP file signatures.
* This method throws {@link IOException} if the file signature does not match any known ZIP archive signatures.
*
* @param fis The {@link InputStream} of the file to check.
* @throws IOException If the file signature does not match known ZIP archive signatures
* or an I/O error occurs during reading from the stream.
*/
public static void checkFileForZipHeader(InputStream fis) throws IOException {
byte[] bytes = new byte[4];
if (fis.read(bytes) == bytes.length) {
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
int header = buffer.getInt();

if (!ARCHIVE_FILE_SIGNATURES.contains(header)) {
throw new IOException("Invalid archive file signature."); // Throws IOException if header is not recognized //$NON-NLS-1$
}
} else {
// Handle the case where not enough bytes are read
throw new IOException("Could not read enough data to check ZIP file header."); //$NON-NLS-1$
}
}
}
Loading

0 comments on commit ff816b0

Please sign in to comment.