diff --git a/.project b/.project
new file mode 100644
index 0000000..6ecf8ba
--- /dev/null
+++ b/.project
@@ -0,0 +1,11 @@
+
+
+ zipeditor
+
+
+
+
+
+
+
+
diff --git a/CVSROOT/checkoutlist b/CVSROOT/checkoutlist
deleted file mode 100644
index 2921bff..0000000
--- a/CVSROOT/checkoutlist
+++ /dev/null
@@ -1,13 +0,0 @@
-# The "checkoutlist" file is used to support additional version controlled
-# administrative files in $CVSROOT/CVSROOT, such as template files.
-#
-# The first entry on a line is a filename which will be checked out from
-# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
-# The remainder of the line is an error message to use if the file cannot
-# be checked out.
-#
-# File format:
-#
-# [][]
-#
-# comment lines begin with '#'
diff --git a/CVSROOT/commitinfo b/CVSROOT/commitinfo
deleted file mode 100644
index b19e7b7..0000000
--- a/CVSROOT/commitinfo
+++ /dev/null
@@ -1,15 +0,0 @@
-# The "commitinfo" file is used to control pre-commit checks.
-# The filter on the right is invoked with the repository and a list
-# of files to check. A non-zero exit of the filter program will
-# cause the commit to be aborted.
-#
-# The first entry on a line is a regular expression which is tested
-# against the directory that the change is being committed to, relative
-# to the $CVSROOT. For the first match that is found, then the remainder
-# of the line is the name of the filter to run.
-#
-# If the repository name does not match any of the regular expressions in this
-# file, the "DEFAULT" line is used, if it is specified.
-#
-# If the name "ALL" appears as a regular expression it is always used
-# in addition to the first matching regex or "DEFAULT".
diff --git a/CVSROOT/config b/CVSROOT/config
deleted file mode 100644
index 92c150b..0000000
--- a/CVSROOT/config
+++ /dev/null
@@ -1,21 +0,0 @@
-# Set this to "no" if pserver shouldn't check system users/passwords
-#SystemAuth=no
-
-# Put CVS lock files in this directory rather than directly in the repository.
-#LockDir=/var/lock/cvs
-
-# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top
-# level of the new working directory when using the `cvs checkout'
-# command.
-#TopLevelAdmin=no
-
-# Set `LogHistory' to `all' or `TOEFWUPCGMAR' to log all transactions to the
-# history file, or a subset as needed (ie `TMAR' logs all write operations)
-#LogHistory=TOEFWUPCGMAR
-
-# Set `RereadLogAfterVerify' to `always' (the default) to allow the verifymsg
-# script to change the log message. Set it to `stat' to force CVS to verify# that the file has changed before reading it (this can take up to an extra
-# second per directory being committed, so it is not recommended for large
-# repositories. Set it to `never' (the previous CVS behavior) to prevent
-# verifymsg scripts from changing the log message.
-#RereadLogAfterVerify=always
diff --git a/CVSROOT/cvswrappers b/CVSROOT/cvswrappers
deleted file mode 100644
index e989b75..0000000
--- a/CVSROOT/cvswrappers
+++ /dev/null
@@ -1,19 +0,0 @@
-# This file affects handling of files based on their names.
-#
-# The -m option specifies whether CVS attempts to merge files.
-#
-# The -k option specifies keyword expansion (e.g. -kb for binary).
-#
-# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
-#
-# wildcard [option value][option value]...
-#
-# where option is one of
-# -f from cvs filter value: path to filter
-# -t to cvs filter value: path to filter
-# -m update methodology value: MERGE or COPY
-# -k expansion mode value: b, o, kkv, &c
-#
-# and value is a single-quote delimited value.
-# For example:
-#*.gif -k 'b'
diff --git a/CVSROOT/editinfo b/CVSROOT/editinfo
deleted file mode 100644
index d78886c..0000000
--- a/CVSROOT/editinfo
+++ /dev/null
@@ -1,21 +0,0 @@
-# The "editinfo" file is used to allow verification of logging
-# information. It works best when a template (as specified in the
-# rcsinfo file) is provided for the logging procedure. Given a
-# template with locations for, a bug-id number, a list of people who
-# reviewed the code before it can be checked in, and an external
-# process to catalog the differences that were code reviewed, the
-# following test can be applied to the code:
-#
-# Making sure that the entered bug-id number is correct.
-# Validating that the code that was reviewed is indeed the code being
-# checked in (using the bug-id number or a seperate review
-# number to identify this particular code set.).
-#
-# If any of the above test failed, then the commit would be aborted.
-#
-# Actions such as mailing a copy of the report to each reviewer are
-# better handled by an entry in the loginfo file.
-#
-# One thing that should be noted is the the ALL keyword is not
-# supported. There can be only one entry that matches a given
-# repository.
diff --git a/CVSROOT/loginfo b/CVSROOT/loginfo
deleted file mode 100644
index 537607d..0000000
--- a/CVSROOT/loginfo
+++ /dev/null
@@ -1,27 +0,0 @@
-# The "loginfo" file controls where "cvs commit" log information
-# is sent. The first entry on a line is a regular expression which must match
-# the directory that the change is being made to, relative to the
-# $CVSROOT. If a match is found, then the remainder of the line is a filter
-# program that should expect log information on its standard input.
-#
-# If the repository name does not match any of the regular expressions in this
-# file, the "DEFAULT" line is used, if it is specified.
-#
-# If the name ALL appears as a regular expression it is always used
-# in addition to the first matching regex or DEFAULT.
-#
-# You may specify a format string as part of the
-# filter. The string is composed of a `%' followed
-# by a single format character, or followed by a set of format
-# characters surrounded by `{' and `}' as separators. The format
-# characters are:
-#
-# s = file name
-# V = old version number (pre-checkin)
-# v = new version number (post-checkin)
-# t = tag or branch name
-#
-# For example:
-#DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog
-# or
-#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog
diff --git a/CVSROOT/modules b/CVSROOT/modules
deleted file mode 100644
index cb9e9ef..0000000
--- a/CVSROOT/modules
+++ /dev/null
@@ -1,26 +0,0 @@
-# Three different line formats are valid:
-# key -a aliases...
-# key [options] directory
-# key [options] directory files...
-#
-# Where "options" are composed of:
-# -i prog Run "prog" on "cvs commit" from top-level of module.
-# -o prog Run "prog" on "cvs checkout" of module.
-# -e prog Run "prog" on "cvs export" of module.
-# -t prog Run "prog" on "cvs rtag" of module.
-# -u prog Run "prog" on "cvs update" of module.
-# -d dir Place module in directory "dir" instead of module name.
-# -l Top-level directory only -- do not recurse.
-#
-# NOTE: If you change any of the "Run" options above, you'll have to
-# release and re-checkout any working directories of these modules.
-#
-# And "directory" is a path to a directory relative to $CVSROOT.
-#
-# The "-a" option specifies an alias. An alias is interpreted as if
-# everything on the right of the "-a" had been typed on the command line.
-#
-# You can encode a module within a module by using the special '&'
-# character to interpose another module into the current module. This
-# can be useful for creating a module that consists of many directories
-# spread out over the entire source repository.
diff --git a/CVSROOT/notify b/CVSROOT/notify
deleted file mode 100644
index 74ae6f9..0000000
--- a/CVSROOT/notify
+++ /dev/null
@@ -1,12 +0,0 @@
-# The "notify" file controls where notifications from watches set by
-# "cvs watch add" or "cvs edit" are sent. The first entry on a line is
-# a regular expression which is tested against the directory that the
-# change is being made to, relative to the $CVSROOT. If it matches,
-# then the remainder of the line is a filter program that should contain
-# one occurrence of %s for the user to notify, and information on its
-# standard input.
-#
-# "ALL" or "DEFAULT" can be used in place of the regular expression.
-#
-# For example:
-#ALL mail -s "CVS notification" %s
diff --git a/CVSROOT/rcsinfo b/CVSROOT/rcsinfo
deleted file mode 100644
index 49e59f4..0000000
--- a/CVSROOT/rcsinfo
+++ /dev/null
@@ -1,13 +0,0 @@
-# The "rcsinfo" file is used to control templates with which the editor
-# is invoked on commit and import.
-#
-# The first entry on a line is a regular expression which is tested
-# against the directory that the change is being made to, relative to the
-# $CVSROOT. For the first match that is found, then the remainder of the
-# line is the name of the file that contains the template.
-#
-# If the repository name does not match any of the regular expressions in this
-# file, the "DEFAULT" line is used, if it is specified.
-#
-# If the name "ALL" appears as a regular expression it is always used
-# in addition to the first matching regex or "DEFAULT".
diff --git a/CVSROOT/taginfo b/CVSROOT/taginfo
deleted file mode 100644
index 274a46d..0000000
--- a/CVSROOT/taginfo
+++ /dev/null
@@ -1,20 +0,0 @@
-# The "taginfo" file is used to control pre-tag checks.
-# The filter on the right is invoked with the following arguments:
-#
-# $1 -- tagname
-# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d
-# $3 -- repository
-# $4-> file revision [file revision ...]
-#
-# A non-zero exit of the filter program will cause the tag to be aborted.
-#
-# The first entry on a line is a regular expression which is tested
-# against the directory that the change is being committed to, relative
-# to the $CVSROOT. For the first match that is found, then the remainder
-# of the line is the name of the filter to run.
-#
-# If the repository name does not match any of the regular expressions in this
-# file, the "DEFAULT" line is used, if it is specified.
-#
-# If the name "ALL" appears as a regular expression it is always used
-# in addition to the first matching regex or "DEFAULT".
diff --git a/CVSROOT/verifymsg b/CVSROOT/verifymsg
deleted file mode 100644
index 86f747c..0000000
--- a/CVSROOT/verifymsg
+++ /dev/null
@@ -1,21 +0,0 @@
-# The "verifymsg" file is used to allow verification of logging
-# information. It works best when a template (as specified in the
-# rcsinfo file) is provided for the logging procedure. Given a
-# template with locations for, a bug-id number, a list of people who
-# reviewed the code before it can be checked in, and an external
-# process to catalog the differences that were code reviewed, the
-# following test can be applied to the code:
-#
-# Making sure that the entered bug-id number is correct.
-# Validating that the code that was reviewed is indeed the code being
-# checked in (using the bug-id number or a seperate review
-# number to identify this particular code set.).
-#
-# If any of the above test failed, then the commit would be aborted.
-#
-# Actions such as mailing a copy of the report to each reviewer are
-# better handled by an entry in the loginfo file.
-#
-# One thing that should be noted is the the ALL keyword is not
-# supported. There can be only one entry that matches a given
-# repository.
diff --git a/ZipEditor Feature/.cvsignore b/ZipEditor Feature/.cvsignore
deleted file mode 100644
index 32c5ac0..0000000
--- a/ZipEditor Feature/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*.jar
-build.xml
diff --git a/ZipEditor Feature/META-INF/MANIFEST.MF b/ZipEditor Feature/META-INF/MANIFEST.MF
deleted file mode 100644
index 59499bc..0000000
--- a/ZipEditor Feature/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,2 +0,0 @@
-Manifest-Version: 1.0
-
diff --git a/ZipEditor Feature/build.properties b/ZipEditor Feature/build.properties
deleted file mode 100644
index 4a89e32..0000000
--- a/ZipEditor Feature/build.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-bin.includes = feature.xml,\
- cpl10.txt,\
- feature.properties
diff --git a/ZipEditor Feature/feature.properties b/ZipEditor Feature/feature.properties
deleted file mode 100644
index ec2a5d1..0000000
--- a/ZipEditor Feature/feature.properties
+++ /dev/null
@@ -1,240 +0,0 @@
-providerName=Uwe Voigt
-featureName=ZipEditor
-descriptionUrl=http://zipeditor.sourceforge.net/
-description=An Eclipse editor to manipulate archives.\n\
-1.1.9\n\
----------------------\n\
-- Support search within non-archive files as well\n\
-1.1.8\n\
----------------------\n\
-- Replaced some references to deprecated types/methods\n\
-1.1.7\n\
----------------------\n\
-- https://sourceforge.net/p/zipeditor/bugs/14/ remove references to org.eclipse.jface.util.Assert\n\
-1.1.6\n\
----------------------\n\
-- https://sourceforge.net/p/zipeditor/bugs/11/ disable debug by default\n\
-- https://sourceforge.net/p/zipeditor/bugs/12/ don't log too much\n\
-- https://sourceforge.net/p/zipeditor/bugs/13/ late opening of files\n\
-1.1.5\n\
----------------------\n\
-- added RPM read functionality\n\
-- added method (compressed/stored) to zip entries\n\
-- save archive type specific editor settings\n\
-- general performance improvements\n\
-New in release 1.1.4\n\
----------------------\n\
-- Ctrl+O in the editor opens a quick outline\n\
-- "Open in Zip Editor" can be used on build path entries\n\
-- Editors opened on search results show marker annotations for occurrences now.\
-\n\
-New in release 1.1.3\n\
----------------------\n\
-- Use the Eclipse search to recursively search in archives.
-
-updateSiteName=ZipEditor Update Site
-
-copyright=© Uwe Voigt, 2006, 2007. All Rights Reserved.
-
-licenseURL=cpl10.txt
-
-license=\
-THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS \n\
-COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR \n\
-DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE \n\
-OF THIS AGREEMENT. \n\
-1. DEFINITIONS \n\
-"Contribution" means: \n\
-a) in the case of the initial Contributor, the initial code and \n\
-documentation distributed under this Agreement, and \n\
-b) in the case of each subsequent Contributor: \n\
-i) changes to the Program, and \n\
-ii) additions to the Program; \n\
-where such changes and/or additions to the Program originate \n\
-from and are distributed by that particular Contributor. A Contribution \n\
-'originates' from a Contributor if it was added to the Program \n\
-by such Contributor itself or anyone acting on such Contributor's \n\
-behalf. Contributions do not include additions to the Program \n\
-which:(i) are separate modules of software distributed in conjunction \n\
-with the Program under their own license agreement, and (ii) \n\
-are not derivative works of the Program. \n\
-"Contributor" means any person or entity that distributes the \n\
-Program. \n\
-"Licensed Patents " mean patent claims licensable by a Contributor \n\
-which are necessarily infringed by the use or sale of its Contribution \n\
-alone or when combined with the Program. \n\
-"Program" means the Contributions distributed in accordance with \n\
-this Agreement. \n\
-"Recipient" means anyone who receives the Program under this \n\
-Agreement, including all Contributors. \n\
-2. GRANT OF RIGHTS \n\
-a) Subject to the terms of this Agreement, each Contributor hereby \n\
-grants Recipient a non-exclusive, worldwide, royalty-free copyright \n\
-license to reproduce, prepare derivative works of, publicly display, \n\
-publicly perform, distribute and sublicense the Contribution \n\
-of such Contributor, if any, and such derivative works, in source \n\
-code and object code form. \n\
-b) Subject to the terms of this Agreement, each Contributor hereby \n\
-grants Recipient a non-exclusive, worldwide, royalty-free patent \n\
-license under Licensed Patents to make, use, sell, offer to sell, \n\
-import and otherwise transfer the Contribution of such Contributor, \n\
-if any, in source code and object code form. This patent license \n\
-shall apply to the combination of the Contribution and the Program \n\
-if, at the time the Contribution is added by the Contributor, \n\
-such addition of the Contribution causes such combination to \n\
-be covered by the Licensed Patents. The patent license shall \n\
-not apply to any other combinations which include the Contribution. \n\
-No hardware per se is licensed hereunder. \n\
-c) Recipient understands that although each Contributor grants \n\
-the licenses to its Contributions set forth herein, no assurances \n\
-are provided by any Contributor that the Program does not infringe \n\
-the patent or other intellectual property rights of any other \n\
-entity. Each Contributor disclaims any liability to Recipient \n\
-for claims brought by any other entity based on infringement \n\
-of intellectual property rights or otherwise. As a condition \n\
-to exercising the rights and licenses granted hereunder, each \n\
-Recipient hereby assumes sole responsibility to secure any other \n\
-intellectual property rights needed, if any. For example, if \n\
-a third party patent license is required to allow Recipient to \n\
-distribute the Program, it is Recipient's responsibility to acquire \n\
-that license before distributing the Program. \n\
-d) Each Contributor represents that to its knowledge it has sufficient \n\
-copyright rights in its Contribution, if any, to grant the copyright \n\
-license set forth in this Agreement. \n\
-3. REQUIREMENTS \n\
-A Contributor may choose to distribute the Program in object \n\
-code form under its own license agreement, provided that: \n\
-a) it complies with the terms and conditions of this Agreement; \n\
-and \n\
-b) its license agreement: \n\
-i) effectively disclaims on behalf of all Contributors all warranties \n\
-and conditions, express and implied, including warranties or \n\
-conditions of title and non-infringement, and implied warranties \n\
-or conditions of merchantability and fitness for a particular \n\
-purpose; \n\
-ii) effectively excludes on behalf of all Contributors all liability \n\
-for damages, including direct, indirect, special, incidental \n\
-and consequential damages, such as lost profits; \n\
-iii) states that any provisions which differ from this Agreement \n\
-are offered by that Contributor alone and not by any other party; \n\
-and \n\
-iv) states that source code for the Program is available from \n\
-such Contributor, and informs licensees how to obtain it in a \n\
-reasonable manner on or through a medium customarily used for \n\
-software exchange. \n\
-When the Program is made available in source code form: \n\
-a) it must be made available under this Agreement; and \n\
-b) a copy of this Agreement must be included with each copy of \n\
-the Program. \n\
-Contributors may not remove or alter any copyright notices contained \n\
-within the Program. \n\
-Each Contributor must identify itself as the originator of its \n\
-Contribution, if any, in a manner that reasonably allows subsequent \n\
-Recipients to identify the originator of the Contribution. \n\
-4. COMMERCIAL DISTRIBUTION \n\
-Commercial distributors of software may accept certain responsibilities \n\
-with respect to end users, business partners and the like. While \n\
-this license is intended to facilitate the commercial use of \n\
-the Program, the Contributor who includes the Program in a commercial \n\
-product offering should do so in a manner which does not create \n\
-potential liability for other Contributors. Therefore, if a Contributor \n\
-includes the Program in a commercial product offering, such Contributor \n\
-("Commercial Contributor") hereby agrees to defend and indemnify \n\
-every other Contributor ("Indemnified Contributor") against any \n\
-losses, damages and costs (collectively "Losses") arising from \n\
-claims, lawsuits and other legal actions brought by a third party \n\
-against the Indemnified Contributor to the extent caused by the \n\
-acts or omissions of such Commercial Contributor in connection \n\
-with its distribution of the Program in a commercial product \n\
-offering. The obligations in this section do not apply to any \n\
-claims or Losses relating to any actual or alleged intellectual \n\
-property infringement. In order to qualify, an Indemnified Contributor \n\
-must: a) promptly notify the Commercial Contributor in writing \n\
-of such claim, and b) allow the Commercial Contributor to control, \n\
-and cooperate with the Commercial Contributor in, the defense \n\
-and any related settlement negotiations. The Indemnified Contributor \n\
-may participate in any such claim at its own expense. \n\
-For example, a Contributor might include the Program in a commercial \n\
-product offering, Product X. That Contributor is then a Commercial \n\
-Contributor. If that Commercial Contributor then makes performance \n\
-claims, or offers warranties related to Product X, those performance \n\
-claims and warranties are such Commercial Contributor's responsibility \n\
-alone. Under this section, the Commercial Contributor would have \n\
-to defend claims against the other Contributors related to those \n\
-performance claims and warranties, and if a court requires any \n\
-other Contributor to pay any damages as a result, the Commercial \n\
-Contributor must pay those damages. \n\
-5. NO WARRANTY \n\
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM \n\
-IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS \n\
-OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, \n\
-ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY \n\
-OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely \n\
-responsible for determining the appropriateness of using and \n\
-distributing the Program and assumes all risks associated with \n\
-its exercise of rights under this Agreement, including but not \n\
-limited to the risks and costs of program errors, compliance \n\
-with applicable laws, damage to or loss of data, programs or \n\
-equipment, and unavailability or interruption of operations. \n\
-6. DISCLAIMER OF LIABILITY \n\
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT \n\
-NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, \n\
-INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES \n\
-(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND \n\
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, \n\
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY \n\
-OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE \n\
-OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY \n\
-OF SUCH DAMAGES. \n\
-7. GENERAL \n\
-If any provision of this Agreement is invalid or unenforceable \n\
-under applicable law, it shall not affect the validity or enforceability \n\
-of the remainder of the terms of this Agreement, and without \n\
-further action by the parties hereto, such provision shall be \n\
-reformed to the minimum extent necessary to make such provision \n\
-valid and enforceable. \n\
-If Recipient institutes patent litigation against a Contributor \n\
-with respect to a patent applicable to software (including a \n\
-cross-claim or counterclaim in a lawsuit), then any patent licenses \n\
-granted by that Contributor to such Recipient under this Agreement \n\
-shall terminate as of the date such litigation is filed. In addition, \n\
-if Recipient institutes patent litigation against any entity \n\
-(including a cross-claim or counterclaim in a lawsuit) alleging \n\
-that the Program itself (excluding combinations of the Program \n\
-with other software or hardware) infringes such Recipient's patent(s), \n\
-then such Recipient's rights granted under Section 2(b) shall \n\
-terminate as of the date such litigation is filed. \n\
-All Recipient's rights under this Agreement shall terminate if \n\
-it fails to comply with any of the material terms or conditions \n\
-of this Agreement and does not cure such failure in a reasonable \n\
-period of time after becoming aware of such noncompliance. If \n\
-all Recipient's rights under this Agreement terminate, Recipient \n\
-agrees to cease use and distribution of the Program as soon as \n\
-reasonably practicable. However, Recipient's obligations under \n\
-this Agreement and any licenses granted by Recipient relating \n\
-to the Program shall continue and survive. \n\
-Everyone is permitted to copy and distribute copies of this Agreement, \n\
-but in order to avoid inconsistency the Agreement is copyrighted \n\
-and may only be modified in the following manner. The Agreement \n\
-Steward reserves the right to publish new versions (including \n\
-revisions) of this Agreement from time to time. No one other \n\
-than the Agreement Steward has the right to modify this Agreement. \n\
-IBM is the initial Agreement Steward. IBM may assign the responsibility \n\
-to serve as the Agreement Steward to a suitable separate entity. \n\
-Each new version of the Agreement will be given a distinguishing \n\
-version number. The Program (including Contributions) may always \n\
-be distributed subject to the version of the Agreement under \n\
-which it was received. In addition, after a new version of the \n\
-Agreement is published, Contributor may elect to distribute the \n\
-Program (including its Contributions) under the new version. \n\
-Except as expressly stated in Sections 2(a) and 2(b) above, Recipient \n\
-receives no rights or licenses to the intellectual property of \n\
-any Contributor under this Agreement, whether expressly, by implication, \n\
-estoppel or otherwise. All rights in the Program not expressly \n\
-granted under this Agreement are reserved. \n\
-This Agreement is governed by the laws of the State of New York \n\
-and the intellectual property laws of the United States of America. \n\
-No party to this Agreement will bring a legal action under this \n\
-Agreement more than one year after the cause of action arose. \n\
-Each party waives its rights to a jury trial in any resulting \n\
-litigation. \n\
diff --git a/ZipEditor Feature/feature.xml b/ZipEditor Feature/feature.xml
deleted file mode 100644
index 88a0ce3..0000000
--- a/ZipEditor Feature/feature.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
- %description
-
-
-
- %copyright
-
-
-
- %license
-
-
-
-
-
-
-
-
-
diff --git a/ZipEditor Update Site/site.xml b/ZipEditor Update Site/site.xml
index e036dc6..302016e 100644
--- a/ZipEditor Update Site/site.xml
+++ b/ZipEditor Update Site/site.xml
@@ -3,7 +3,7 @@
ZipEditor list of features
-
+
diff --git a/ZipEditor-test/.classpath b/ZipEditor-test/.classpath
index 887e062..ff8b063 100644
--- a/ZipEditor-test/.classpath
+++ b/ZipEditor-test/.classpath
@@ -1,7 +1,7 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/ZipEditor-test/.settings/org.eclipse.jdt.core.prefs b/ZipEditor-test/.settings/org.eclipse.jdt.core.prefs
index 0c13c15..3b643fa 100644
--- a/ZipEditor-test/.settings/org.eclipse.jdt.core.prefs
+++ b/ZipEditor-test/.settings/org.eclipse.jdt.core.prefs
@@ -1,7 +1,12 @@
-#Sun Dec 04 11:24:59 CET 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=21
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=21
diff --git a/ZipEditor-test/META-INF/MANIFEST.MF b/ZipEditor-test/META-INF/MANIFEST.MF
index 0e8e546..32c3600 100644
--- a/ZipEditor-test/META-INF/MANIFEST.MF
+++ b/ZipEditor-test/META-INF/MANIFEST.MF
@@ -9,6 +9,11 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.filesystem,
org.eclipse.search,
ZipEditor,
- org.junit
+ org.junit,
+ org.apache.commons.commons-compress,
+ org.apache.commons.commons-io;bundle-version="2.16.1",
+ org.eclipse.ui;bundle-version="3.206.0"
+Import-Package: io.airlift.compress;version="[2.0.0,3.0.0)";resolution:=optional,
+ io.airlift.compress.zstd;version="[2.0.0,3.0.0)";resolution:=optional
Eclipse-LazyStart: false
Bundle-Vendor: %Bundle-Vendor.0
diff --git a/ZipEditor-test/resources/zstd.zip b/ZipEditor-test/resources/zstd.zip
new file mode 100644
index 0000000..292603f
Binary files /dev/null and b/ZipEditor-test/resources/zstd.zip differ
diff --git a/ZipEditor-test/src/zipeditor/model/AbstractModelTest.java b/ZipEditor-test/src/zipeditor/model/AbstractModelTest.java
index fd79602..e861b94 100644
--- a/ZipEditor-test/src/zipeditor/model/AbstractModelTest.java
+++ b/ZipEditor-test/src/zipeditor/model/AbstractModelTest.java
@@ -6,9 +6,12 @@
import java.io.FileInputStream;
import java.io.InputStream;
+import org.eclipse.jface.preference.IPreferenceStore;
import org.junit.Before;
import org.junit.Test;
+import zipeditor.PreferenceConstants;
+import zipeditor.ZipEditorPlugin;
import zipeditor.model.ZipContentDescriber.ContentTypeId;
public abstract class AbstractModelTest {
@@ -21,6 +24,9 @@ public abstract class AbstractModelTest {
@Before
public void before() throws Exception {
+ IPreferenceStore preferenceStore = ZipEditorPlugin.getDefault().getPreferenceStore();
+ preferenceStore.setValue(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.ACTIVATE_ZSTD_LIB, true);
+
File path = new File("resources/" + getArchiveName());
InputStream inputStream = new FileInputStream(path);
boolean readonly = false;
diff --git a/ZipEditor-test/src/zipeditor/model/ZipModelZstdTest.java b/ZipEditor-test/src/zipeditor/model/ZipModelZstdTest.java
new file mode 100644
index 0000000..09c4a3b
--- /dev/null
+++ b/ZipEditor-test/src/zipeditor/model/ZipModelZstdTest.java
@@ -0,0 +1,99 @@
+package zipeditor.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import io.airlift.compress.zstd.ZstdInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.commons.compress.archivers.zip.ZipMethod;
+import org.apache.commons.compress.compressors.zstandard.ZstdCompressorInputStream;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.junit.Test;
+
+import zipeditor.PreferenceConstants;
+import zipeditor.ZipEditorPlugin;
+import zipeditor.model.ZipContentDescriber.ContentTypeId;
+import zipeditor.preferences.PreferenceUtils;
+
+public class ZipModelZstdTest extends AbstractModelTest {
+
+ @Override
+ public String getArchiveName() {
+ return "zstd.zip";
+ }
+
+ @Override
+ public ContentTypeId getArchiveType() {
+ return ContentTypeId.ZIP_FILE;
+ }
+
+ @Override
+ public void shouldOpenNodes() throws Exception {
+ assertEquals(getArchiveType(), model.getType());
+ assertEquals("", model.getRoot().getPath());
+ assertEquals(2, model.getRoot().getChildren().length);
+
+ ZipNode childByName = (ZipNode) model.getRoot().getChildByName(".classpath", false);
+ assertEquals(".classpath", childByName.getName());
+ assertEquals(childByName.getMethod(), ZipMethod.ZSTD.getCode());
+
+ childByName = (ZipNode) model.getRoot().getChildByName(".project", false);
+ assertEquals(".project", childByName.getName());
+ assertEquals(childByName.getMethod(), ZipMethod.ZSTD.getCode());
+ }
+
+ @Test
+ public void extractZstdNode0() throws IOException {
+ File zipPath = model.getZipPath();
+ ZipFile zipFile = ZipFile.builder().setFile(zipPath).get();
+ ZipArchiveEntry entry = zipFile.getEntry(".project");
+ InputStream inputStream = zipFile.getInputStream(entry);
+ assertTrue(inputStream instanceof ZstdCompressorInputStream);
+
+ String string = new String(inputStream.readAllBytes());
+ String[] split = string.split("\n");
+ assertEquals("", split[0]);
+ assertEquals(23, split.length);
+ }
+
+ @Test
+ public void extractZstdNode1() throws IOException {
+ File zipPath = model.getZipPath();
+ ZipFile zipFile = ZipFile.builder().setZstdInputStreamFactory(ZstdInputStream::new).setFile(zipPath).get();
+ ZipArchiveEntry entry = zipFile.getEntry(".project");
+ InputStream inputStream = zipFile.getInputStream(entry);
+ assertTrue(inputStream instanceof ZstdInputStream);
+
+ String string = new String(inputStream.readAllBytes());
+ String[] split = string.split("\n");
+ assertEquals("", split[0]);
+ assertEquals(23, split.length);
+
+ ZipEditorPlugin.getDefault().getPreferenceStore()
+ .setValue(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.SELECTED_ZSTD_LIB, PreferenceUtils.AIRCOMPRESSOR);
+
+ assertTrue(PreferenceUtils.isAircompressorSelected());
+ assertFalse(PreferenceUtils.isJNIZstdSelected());
+ ZipEditorPlugin.getDefault().getPreferenceStore()
+ .setValue(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.SELECTED_ZSTD_LIB, PreferenceUtils.JNI_LIBRARY);
+ assertFalse(PreferenceUtils.isAircompressorSelected());
+ assertTrue(PreferenceUtils.isJNIZstdSelected());
+
+ zipPath = model.getZipPath();
+ zipFile = ZipFile.builder().setFile(zipPath).get();
+ entry = zipFile.getEntry(".project");
+ inputStream = zipFile.getInputStream(entry);
+ assertTrue(inputStream instanceof ZstdCompressorInputStream);
+
+ string = new String(inputStream.readAllBytes());
+ split = string.split("\n");
+ assertEquals("", split[0]);
+ assertEquals(23, split.length);
+ }
+}
diff --git a/ZipEditor.UpdateSite/.gitignore b/ZipEditor.UpdateSite/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/ZipEditor.UpdateSite/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/ZipEditor.UpdateSite/category.xml b/ZipEditor.UpdateSite/category.xml
new file mode 100644
index 0000000..37f3ffd
--- /dev/null
+++ b/ZipEditor.UpdateSite/category.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ZipEditor.UpdateSite/pom.xml b/ZipEditor.UpdateSite/pom.xml
new file mode 100644
index 0000000..d49ec3c
--- /dev/null
+++ b/ZipEditor.UpdateSite/pom.xml
@@ -0,0 +1,84 @@
+
+
+ 4.0.0
+
+ com.github
+ ZipEditor.parent
+ 1.0.0-SNAPSHOT
+ ..
+
+
+ ZipEditor.site
+ eclipse-repository
+
+
+
+ tycho-snapshots
+ https://repo.eclipse.org/content/repositories/tycho-snapshots
+
+
+ eclipse-maven-releases
+ https://repo.eclipse.org/content/repositories/releases
+
+
+ eclipse-cbi-releases
+ https://repo.eclipse.org/content/repositories/cbi-releases
+
+
+ maven-repository
+ https://repo1.maven.org/maven2
+
+
+ apache-repository
+ https://repository.apache.org/content/repositories/snapshots
+
+ true
+
+
+
+
+
+ localtarget
+ file:/${project.basedir}/../maven-bnd/site/target/repository/
+ p2
+
+
+ eclipse 2025-06
+ http://download.eclipse.org/releases/2025-06
+ p2
+
+
+ apache-repository
+ https://repository.apache.org/content/repositories/snapshots
+
+ true
+
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-p2-repository-plugin
+ ${tycho-version}
+
+ Zip Editor Repository
+ false
+ true
+ false
+ false
+
+
+
+ org.eclipse.tycho
+ tycho-maven-plugin
+ true
+
+
+
+
+
+
diff --git a/ZipEditor.targetPlatform/ZipEditor-Latest.target b/ZipEditor.targetPlatform/ZipEditor-Latest.target
new file mode 100644
index 0000000..e6aed6d
--- /dev/null
+++ b/ZipEditor.targetPlatform/ZipEditor-Latest.target
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+ io.airlift
+ aircompressor
+ 2.0.2
+ jar
+
+
+
+
+ Id1
+ https://repo1.maven.org/maven2/
+
+
+
+
+
+
+
+ org.apache.commons
+ commons-compress
+ 1.28.0-SNAPSHOT
+ jar
+
+
+ org.apache.commons
+ commons-lang3
+ 3.18.0-SNAPSHOT
+ jar
+
+
+
+
+ apache snapshot
+ https://repository.apache.org/content/repositories/snapshots/
+
+
+
+
+
+
+
+ com.github.luben
+ zstd-jni
+ 1.5.7-2
+ jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ZipEditor.targetPlatform/pom.xml b/ZipEditor.targetPlatform/pom.xml
new file mode 100644
index 0000000..c210e14
--- /dev/null
+++ b/ZipEditor.targetPlatform/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+ 4.0.0
+
+ com.github
+ ZipEditor.parent
+ 1.0.0-SNAPSHOT
+ ..
+
+ ZipEditor.targetPlatform
+ eclipse-target-definition
+
+
+
+
+ org.eclipse.tycho
+ tycho-maven-plugin
+ true
+
+
+
+
+
+
+ tycho-snapshots
+ https://repo.eclipse.org/content/repositories/tycho-snapshots
+
+
+
+ eclipse-maven-releases
+ https://repo.eclipse.org/content/repositories/releases
+
+
+
+ eclipse-cbi-releases
+ https://repo.eclipse.org/content/repositories/cbi-releases
+
+
+ maven-repository
+ https://repo1.maven.org/maven2
+
+
+ apache-repository
+ https://repository.apache.org/content/repositories/snapshots
+
+ true
+
+
+
+
diff --git a/ZipEditor/.classpath b/ZipEditor/.classpath
index 809a8f3..97bf0dc 100644
--- a/ZipEditor/.classpath
+++ b/ZipEditor/.classpath
@@ -1,11 +1,7 @@
-
-
-
-
-
+
diff --git a/ZipEditor/.gitignore b/ZipEditor/.gitignore
index ae3c172..09e3bc9 100644
--- a/ZipEditor/.gitignore
+++ b/ZipEditor/.gitignore
@@ -1 +1,2 @@
/bin/
+/target/
diff --git a/ZipEditor/.settings/org.eclipse.jdt.core.prefs b/ZipEditor/.settings/org.eclipse.jdt.core.prefs
index 7dae8f9..4fe4ac7 100644
--- a/ZipEditor/.settings/org.eclipse.jdt.core.prefs
+++ b/ZipEditor/.settings/org.eclipse.jdt.core.prefs
@@ -10,9 +10,9 @@ org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.compliance=21
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -24,6 +24,7 @@ org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
@@ -47,6 +48,7 @@ org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
@@ -69,4 +71,4 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disa
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.release=enabled
-org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.compiler.source=21
diff --git a/ZipEditor/META-INF/MANIFEST.MF b/ZipEditor/META-INF/MANIFEST.MF
index 0cd6c46..491f9b2 100644
--- a/ZipEditor/META-INF/MANIFEST.MF
+++ b/ZipEditor/META-INF/MANIFEST.MF
@@ -2,9 +2,11 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Automatic-Module-Name: %Bundle-Name.0
Bundle-Name: %Bundle-Name.0
+Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-SymbolicName: ZipEditor;singleton:=true
-Bundle-Version: 1.1.9.qualifier
+Bundle-Version: 1.2.1.qualifier
Bundle-Activator: zipeditor.ZipEditorPlugin
+Bundle-ClassPath: .
Bundle-Localization: plugin
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.resources,
@@ -18,10 +20,14 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.search,
org.apache.ant,
org.apache.commons.commons-io,
- org.apache.commons.commons-compress;bundle-version="1.27.1",
- org.apache.commons.lang3;bundle-version="3.17.0"
+ org.apache.commons.lang3;bundle-version="3.17.0",
+ org.apache.commons.commons-compress;bundle-version="1.28.0",
+ com.github.luben.zstd-jni;bundle-version="1.5.7";resolution:=optional
Bundle-ActivationPolicy: lazy
Bundle-Vendor: %Bundle-Vendor.0
Export-Package: zipeditor,
zipeditor.model,
+ zipeditor.preferences,
zipeditor.search
+Import-Package: io.airlift.compress;version="[2.0.0,3.0.0)";resolution:=optional,
+ io.airlift.compress.zstd;version="[2.0.0,3.0.0)";resolution:=optional
diff --git a/ZipEditor/build.properties b/ZipEditor/build.properties
index 6335005..c07148f 100644
--- a/ZipEditor/build.properties
+++ b/ZipEditor/build.properties
@@ -1,5 +1,5 @@
source.. = src/
-output.. = bin/
+output.. = target/
bin.includes = META-INF/,\
.,\
plugin.xml,\
diff --git a/ZipEditor/category.xml b/ZipEditor/category.xml
new file mode 100644
index 0000000..9bd4112
--- /dev/null
+++ b/ZipEditor/category.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ZipEditor/latest.target b/ZipEditor/latest.target
new file mode 100644
index 0000000..e1d4ee7
--- /dev/null
+++ b/ZipEditor/latest.target
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+ x86_64
+ linux
+ gtk
+ en_US
+
+
+ -Declipse.p2.max.threads=10 -Doomph.update.url=https://download.eclipse.org/oomph/updates/milestone/latest -Doomph.redirection.index.redirection=index:/->https://raw.githubusercontent.com/eclipse-oomph/oomph/master/setups/ -XX:CompileCommand=exclude org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer::getExtendedRange -Dorg.eclipse.ecf.provider.filetransfer.excludeContributors=org.eclipse.ecf.provider.filetransfer.httpclientjava -Dosgi.requiredJavaVersion=21 -Dosgi.instance.area.default=@user.home/eclipse-workspace -Dosgi.dataAreaRequiresExplicitInit=true -Dorg.eclipse.swt.graphics.Resource.reportNonDisposed=true -Declipse.e4.inject.javax.warning=false -Dorg.slf4j.simpleLogger.defaultLogLevel=off -Dsun.java.command=Eclipse -XX:+UseG1GC -XX:+UseStringDeduplication --add-modules=ALL-SYSTEM -Doomph.redirection.orbit.simrel.setup=https://raw.githubusercontent.com/eclipse-orbit/orbit-simrel/main/OrbitSimRel.setup->file:/home/mkaraman/eclipse/committers-2025-06/git/orbit-simrel/OrbitSimRel.setup -Xmx2048m
+
+
\ No newline at end of file
diff --git a/ZipEditor/plugin.xml b/ZipEditor/plugin.xml
index 303a656..c683bc0 100644
--- a/ZipEditor/plugin.xml
+++ b/ZipEditor/plugin.xml
@@ -320,5 +320,13 @@
menubarPath="group.open"/>
+
+
+
+
diff --git a/ZipEditor/pom.xml b/ZipEditor/pom.xml
new file mode 100644
index 0000000..11e05ed
--- /dev/null
+++ b/ZipEditor/pom.xml
@@ -0,0 +1,89 @@
+
+ 4.0.0
+
+
+ ZipEditor
+ eclipse-plugin
+ 1.2.1-SNAPSHOT
+
+ com.github
+ ../
+ 1.0.0-SNAPSHOT
+ ZipEditor.parent
+
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-source-plugin
+ ${tycho-version}
+
+
+ attach-sources
+
+ plugin-source
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-maven-plugin
+ true
+
+
+
+ true
+ ${project.basedir}/../maven-bnd/tp/MavenBND.target
+ include
+
+
+
+
+
+
+
+
+
+ eclipse 2025-06
+ http://download.eclipse.org/releases/2025-06
+ p2
+
+
+ localtarget
+ file:/${project.basedir}/../maven-bnd/site/target/repository/
+ p2
+
+
+ apache-repository
+ https://repository.apache.org/content/repositories/snapshots
+ true
+
+
+
+
+
+ tycho-snapshots
+ https://repo.eclipse.org/content/repositories/tycho-snapshots
+
+
+ eclipse-maven-releases
+ https://repo.eclipse.org/content/repositories/releases
+
+
+ eclipse-cbi-releases
+ https://repo.eclipse.org/content/repositories/cbi-releases
+
+
+ maven-repository
+ https://repo1.maven.org/maven2
+
+
+ apache-repository
+ https://repository.apache.org/content/repositories/snapshots
+ true
+
+
+
\ No newline at end of file
diff --git a/ZipEditor/src/zipeditor/LazyZipContentProvider.java b/ZipEditor/src/zipeditor/LazyZipContentProvider.java
index e005849..d450a29 100644
--- a/ZipEditor/src/zipeditor/LazyZipContentProvider.java
+++ b/ZipEditor/src/zipeditor/LazyZipContentProvider.java
@@ -21,6 +21,9 @@ public LazyZipContentProvider(int mode) {
}
public int findElement(Object element) {
+ if (fTableViewer == null) {
+ return -1;
+ }
IElementComparer comparer = fTableViewer.getComparer();
for (int i = 0; i < fRootChildren.length; i++) {
if (comparer.equals(fRootChildren[i], element))
diff --git a/ZipEditor/src/zipeditor/PreferenceConstants.java b/ZipEditor/src/zipeditor/PreferenceConstants.java
index bf7d477..9320353 100644
--- a/ZipEditor/src/zipeditor/PreferenceConstants.java
+++ b/ZipEditor/src/zipeditor/PreferenceConstants.java
@@ -26,6 +26,10 @@ public class PreferenceConstants {
public final static String SORT_ENABLED = "SORT_ENABLED"; //$NON-NLS-1$
+ public final static String ACTIVATE_ZSTD_LIB = "ACTIVE_ZSTD"; //$NON-NLS-1$
+
+ public static final String SELECTED_ZSTD_LIB = "selectedZstdLib"; //$NON-NLS-1$
+
public final static String EXTERNAL_EDITORS = "EXTERNAL_EDITORS"; //$NON-NLS-1$
public final static String PREFIX_EDITOR = "editor"; //$NON-NLS-1$
@@ -46,6 +50,10 @@ public class PreferenceConstants {
public final static String STORE_FOLDERS_IN_ARCHIVES = "storeFoldersInArchives"; //$NON-NLS-1$
+ public static final String USE_ZSTD_AS_DEFAULT = "useZstdDefault"; //$NON-NLS-1$
+
+ public static final String COMPRESSION_LEVEL = "compressionLevel"; //$NON-NLS-1$
+
public static String getPreferenceSuffix(ContentTypeId type) {
switch (type.getOrdinal()) {
case ContentTypeId.ZIP:
diff --git a/ZipEditor/src/zipeditor/PreferenceInitializer.java b/ZipEditor/src/zipeditor/PreferenceInitializer.java
index 9defd4b..d4fd9f2 100644
--- a/ZipEditor/src/zipeditor/PreferenceInitializer.java
+++ b/ZipEditor/src/zipeditor/PreferenceInitializer.java
@@ -13,6 +13,7 @@
import zipeditor.model.NodeProperty;
import zipeditor.model.ZipContentDescriber.ContentTypeId;
+import zipeditor.preferences.PreferenceUtils;
public class PreferenceInitializer extends AbstractPreferenceInitializer {
@@ -63,6 +64,9 @@ public void initializeDefaultPreferences() {
store.setDefault(PreferenceConstants.PREFIX_NAVIGATOR + PreferenceConstants.SORT_ENABLED, true);
store.setDefault(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.VIEW_MODE, PreferenceConstants.VIEW_MODE_FOLDERS_ONE_LAYER);
store.setDefault(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.SORT_ENABLED, true);
+ store.setDefault(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.ACTIVATE_ZSTD_LIB, false);
+ store.setDefault(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.COMPRESSION_LEVEL, 10);
+ store.setDefault(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.USE_ZSTD_AS_DEFAULT, false);
store.setDefault(PreferenceConstants.SORT_BY, defaultSortBy);
store.setDefault(PreferenceConstants.SORT_DIRECTION, SWT.UP);
store.setDefault(PreferenceConstants.VISIBLE_COLUMNS, defaultVisibleColumns);
diff --git a/ZipEditor/src/zipeditor/ZipContentProvider.java b/ZipEditor/src/zipeditor/ZipContentProvider.java
index 16edbad..cf39932 100644
--- a/ZipEditor/src/zipeditor/ZipContentProvider.java
+++ b/ZipEditor/src/zipeditor/ZipContentProvider.java
@@ -34,6 +34,9 @@ public Object[] getChildren(Object parentElement) {
}
protected Object[] getNodeChildren(Node node) {
+ if (node == null) {
+ return new Object[0];
+ }
if (fDisposeModel && fModel != node.getModel())
fModel = node.getModel();
if ((fMode & PreferenceConstants.VIEW_MODE_TREE) > 0)
diff --git a/ZipEditor/src/zipeditor/ZipEditor.java b/ZipEditor/src/zipeditor/ZipEditor.java
index 0e968b7..888cb8b 100644
--- a/ZipEditor/src/zipeditor/ZipEditor.java
+++ b/ZipEditor/src/zipeditor/ZipEditor.java
@@ -31,7 +31,9 @@
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
@@ -41,6 +43,8 @@
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
@@ -64,6 +68,7 @@
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
@@ -77,10 +82,12 @@
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
@@ -100,8 +107,10 @@
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionContext;
import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
@@ -113,7 +122,6 @@
import org.eclipse.ui.views.framelist.GoIntoAction;
import org.eclipse.ui.views.framelist.UpAction;
-import zipeditor.actions.ActionMessages;
import zipeditor.actions.CollapseAllAction;
import zipeditor.actions.NewFolderAction;
import zipeditor.actions.OpenActionGroup;
@@ -131,6 +139,7 @@
import zipeditor.model.NodeProperty;
import zipeditor.model.ZipContentDescriber;
import zipeditor.model.ZipContentDescriber.ContentTypeId;
+import zipeditor.model.ZipEditorZstdException;
import zipeditor.model.ZipModel;
import zipeditor.model.ZipModel.IErrorReporter;
import zipeditor.model.ZipNodeProperty;
@@ -356,6 +365,9 @@ public void widgetDisposed(DisposeEvent e) {
public final static String ACTION_GO_INTO = "GoInto"; //$NON-NLS-1$
public final static String ACTION_RENAME = "Rename"; //$NON-NLS-1$
public final static String ACTION_QUICK_OUTLINE = "QuickOutline"; //$NON-NLS-1$
+ private Composite fControl;
+ private Composite fInvalidContent;
+ private StackLayout fStackLayout;
public void doSave(IProgressMonitor monitor) {
IEditorInput input = doGetEditorInput();
@@ -569,6 +581,9 @@ private ZipModel createModel() {
public void reportError(IStatus message) {
ZipEditorActionBarContributor contributor = (ZipEditorActionBarContributor) getEditorSite().getActionBarContributor();
+ if (message.getException() instanceof ZipEditorZstdException) {
+ doShowErrorDialog(message.getException());
+ }
contributor.reportError(this, message);
}
@@ -639,11 +654,11 @@ public boolean isSaveAsAllowed() {
}
public void createPartControl(Composite parent) {
- Composite control = new Composite(parent, SWT.NONE);
+ fControl = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginWidth = layout.marginHeight = 0;
- control.setLayout(layout);
- createContent(control, getMode());
+ fControl.setLayout(layout);
+ createContent(fControl, getMode());
}
private void createContent(Composite parent, int mode) {
@@ -656,9 +671,65 @@ private void createContent(Composite parent, int mode) {
private void createControls(Composite parent, int mode) {
fToolBar = createToolBar(parent);
- fZipViewer = createZipViewer(parent, mode);
+ fStackLayout = new StackLayout();
+
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ composite.setLayout(fStackLayout);
+
+ fZipViewer = createZipViewer(composite, mode);
+ fInvalidContent = createErrorHint(composite);
+
+ handleStackLayout();
+ }
+
+ private void handleStackLayout() {
+ if (fModel.getType() == ContentTypeId.INVALID) {
+ fStackLayout.topControl = fInvalidContent;
+ fControl.layout();
+ setEnablementOfUI(false);
+
+ setEnabledOfControls(true, fInvalidContent);
+ } else {
+ fStackLayout.topControl = getViewer().getControl();
+ fControl.layout();
+ setEnablementOfUI(true);
+ }
}
+ private Composite createErrorHint(Composite composite) {
+ Composite fErrorHintComposite = new Composite(composite, SWT.NONE);
+ GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(fErrorHintComposite);
+ GridLayoutFactory.fillDefaults().applyTo(fErrorHintComposite);
+
+ Label label = new Label(fErrorHintComposite, SWT.WRAP | SWT.CENTER);
+ GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).grab(true, true).applyTo(label);
+ label.setText(Messages.getString("ZipEditor.15")); //$NON-NLS-1$
+
+ Button button = new Button(fErrorHintComposite, SWT.PUSH);
+ GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.TOP).grab(true, true).applyTo(button);
+ button.setText(Messages.getString("ZipEditor.16")); //$NON-NLS-1$
+ button.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ openZipEditorPrefPage();
+ }
+ });
+
+ return fErrorHintComposite;
+ }
+
+ public void openZipEditorPrefPage() {
+ Window dialog = PreferencesUtil.createPreferenceDialogOn(
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+ "zipeditor.preferences.ZipEditorPreferencePage", //$NON-NLS-1$
+ null,
+ null);
+ if (dialog != null) {
+ dialog.open();
+ }
+ }
+
private ToolBarManager createToolBar(Composite parent) {
ToolBarManager bar = new ToolBarManager(SWT.HORIZONTAL | SWT.FLAT);
Control control = bar.createControl(parent);
@@ -683,22 +754,36 @@ private void fillToolBar(IToolBarManager bar, int mode) {
bar.add(getAction(ACTION_COLLAPSE_ALL));
}
bar.update(false);
+ if (fModel.getType() == ContentTypeId.INVALID) {
+ IContributionItem[] items = bar.getItems();
+ for (IContributionItem iContributionItem : items) {
+ if (iContributionItem instanceof ActionContributionItem aci) {
+ aci.getAction().setEnabled(false);
+ }
+ }
+ }
}
public void updateView(int mode, boolean savePreferences) {
- Composite parent = fZipViewer.getControl().getParent();
+ Composite parent = fZipViewer.getControl().getParent().getParent();
ISelection selection = fZipViewer.getSelection();
((ZipContentProvider) fZipViewer.getContentProvider()).disposeModel(false);
Control[] children = parent.getChildren();
+ // Attention: The dispose listener is attached to the viewer control and has to be removed directly from it
+ // due the change from getParent() to getParent().getParent() it wasn't possible to remove the listener from
+ // children arrays controls.
+ if (!savePreferences)
+ fZipViewer.getControl().removeDisposeListener(fTableDisposeListener);
+
for (int i = 0; i < children.length; i++) {
- if (!savePreferences)
- children[i].removeDisposeListener(fTableDisposeListener);
children[i].dispose();
}
createContent(parent, mode);
fZipViewer.setSelection(selection);
fZipViewer.getControl().setFocus();
((ZipContentProvider) fZipViewer.getContentProvider()).disposeModel(true);
+
+ handleStackLayout();
}
private StructuredViewer createZipViewer(Composite parent, int mode) {
@@ -794,6 +879,10 @@ private void setViewerInput(final StructuredViewer viewer) {
} else {
input = fModel.getRoot();
}
+ if (fModel.getType() == ContentTypeId.INVALID) {
+ return;
+ }
+
if (input != null) {
if (Utils.isUIThread()) {
doSetViewerInput(viewer, input);
@@ -819,6 +908,31 @@ public void run() {
}
}
+ private void setEnablementOfUI(boolean enabled) {
+ Composite composite = fControl;
+ if (Utils.isUIThread()) {
+ setEnabledOfControls(enabled, composite);
+ } else {
+ Display.getDefault().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ setEnabledOfControls(enabled, composite);
+ }
+ });
+ }
+ }
+
+ private void setEnabledOfControls(boolean enabled, Composite composite) {
+ for (Control control : composite.getChildren()) {
+ if (control instanceof Composite childComposite) {
+ setEnabledOfControls(enabled, childComposite);
+ } else {
+ control.setEnabled(enabled);
+ }
+ }
+ }
+
private void doSetViewerInput(StructuredViewer viewer, Object input) {
viewer.setInput(input);
if (createColumns) {
@@ -961,6 +1075,9 @@ public void widgetSelected(SelectionEvent e) {
public void storeTableColumnPreferences() {
if (!(fZipViewer instanceof TableViewer))
return;
+ if (fModel.getType() == ContentTypeId.INVALID) {
+ return;
+ }
Table table = ((TableViewer) fZipViewer).getTable();
IPreferenceStore store = getPreferenceStore();
String suffix = PreferenceConstants.getPreferenceSuffix(fModel.getType());
@@ -1016,8 +1133,8 @@ private void createActions(int mode) {
fZipActionGroup = new ZipActionGroup(this);
fOpenActionGroup = new OpenActionGroup(getViewer());
setAction(ACTION_NEW_FOLDER, new NewFolderAction(getViewer()));
- ToggleViewModeAction toggleViewModeAction = new ToggleViewModeAction(this, ActionMessages.getString("ToggleViewModeAction.0"), PreferenceConstants.PREFIX_EDITOR, PreferenceConstants.VIEW_MODE_TREE); //$NON-NLS-1$
- toggleViewModeAction.setToolTipText(ActionMessages.getString("ToggleViewModeAction.1")); //$NON-NLS-1$
+ ToggleViewModeAction toggleViewModeAction = new ToggleViewModeAction(this, "", PreferenceConstants.PREFIX_EDITOR, PreferenceConstants.VIEW_MODE_TREE); //$NON-NLS-1$
+ toggleViewModeAction.setToolTipText(""); //$NON-NLS-1$
toggleViewModeAction.setImageDescriptor(ZipEditorPlugin.getImageDescriptor("icons/togglemode.gif")); //$NON-NLS-1$
setAction(ACTION_TOGGLE_MODE, toggleViewModeAction);
@@ -1118,7 +1235,9 @@ public void selectionChanged(SelectionChangedEvent event) {
}
getEditorSite().getShell().getDisplay().asyncExec(new Runnable() {
public void run() {
- fOutlinePage.setInput(fModel.getRoot());
+ if(fOutlinePage != null && fModel != null) {
+ fOutlinePage.setInput(fModel.getRoot());
+ }
}
});
return fOutlinePage;
@@ -1215,8 +1334,22 @@ public int getMode() {
}
public void propertyChange(PropertyChangeEvent event) {
- if ((PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.SORT_ENABLED + SortAction.SORTING_CHANGED).equals(event.getProperty()))
+ if ((PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.SORT_ENABLED + SortAction.SORTING_CHANGED).equals(event.getProperty())) {
+ updateView(getMode(), true);
+ } else if ((PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.ACTIVATE_ZSTD_LIB).equals(event.getProperty())) {
+ fModel = null;
+ setViewerInput(fZipViewer);
+ getAdapter(IContentOutlinePage.class);
+
updateView(getMode(), true);
+
+ } else if ((PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.SELECTED_ZSTD_LIB).equals(event.getProperty())) {
+ fModel = null;
+ setViewerInput(fZipViewer);
+ getAdapter(IContentOutlinePage.class);
+
+ updateView(getMode(), true);
+ }
}
public void saveState(IMemento memento) {
diff --git a/ZipEditor/src/zipeditor/ZipEditorDropAdapter.java b/ZipEditor/src/zipeditor/ZipEditorDropAdapter.java
index dfc4504..179d4e1 100644
--- a/ZipEditor/src/zipeditor/ZipEditorDropAdapter.java
+++ b/ZipEditor/src/zipeditor/ZipEditorDropAdapter.java
@@ -13,6 +13,7 @@
import org.eclipse.ui.part.PluginDropAdapter;
import zipeditor.model.Node;
+import zipeditor.model.zstd.ZstdUtilities;
import zipeditor.operations.AddOperation;
public class ZipEditorDropAdapter extends PluginDropAdapter {
@@ -49,8 +50,8 @@ public boolean performDrop(Object data) {
parentNode = parentNode.getParent();
String[] names = (String[]) data;
AddOperation operation = new AddOperation();
- operation.execute(names, parentNode, selectedNode, (StructuredViewer) getViewer());
+ boolean useZstdCompression = ZstdUtilities.useZstdCompression(parentNode);
+ operation.execute(names, parentNode, selectedNode, (StructuredViewer) getViewer(), useZstdCompression);
return true;
}
-
}
diff --git a/ZipEditor/src/zipeditor/ZipNodePropertyPage.java b/ZipEditor/src/zipeditor/ZipNodePropertyPage.java
index 08ee69f..b8744e6 100644
--- a/ZipEditor/src/zipeditor/ZipNodePropertyPage.java
+++ b/ZipEditor/src/zipeditor/ZipNodePropertyPage.java
@@ -2,6 +2,7 @@
import java.util.zip.ZipEntry;
+import org.apache.commons.compress.archivers.zip.ZipMethod;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
@@ -11,6 +12,7 @@
import zipeditor.model.Node;
import zipeditor.model.ZipNode;
import zipeditor.model.ZipNodeProperty;
+import zipeditor.preferences.PreferenceUtils;
public class ZipNodePropertyPage extends NodePropertyPage implements IWorkbenchPropertyPage {
private class MappingPropertyAccessor extends MultiplePropertyAccessor {
@@ -38,6 +40,9 @@ protected Control createContents(Composite parent) {
fMethod = createCombo(control, 30, 1);
fMethod.add(Messages.getString("MappingPropertyAccessor.8")); //$NON-NLS-1$
fMethod.add(Messages.getString("MappingPropertyAccessor.0")); //$NON-NLS-1$
+ if (PreferenceUtils.isZstdAvailableAndActive()) {
+ fMethod.add(Messages.getString("MappingPropertyAccessor.93")); //$NON-NLS-1$
+ }
select(fMethod, new MappingPropertyAccessor(ZipNode.class).getAccessor("method")); //$NON-NLS-1$
createLabel(control, ZipNodeProperty.PPACKED_SIZE.toString(), 1);
fPackedSize = createText(control, 30, 1, false);
@@ -90,6 +95,8 @@ public boolean performOk() {
zipNode.setMethod(ZipEntry.DEFLATED);
else if (method == 2)
zipNode.setMethod(ZipEntry.STORED);
+ else if (method == 3)
+ zipNode.setMethod(ZipMethod.ZSTD.getCode());
}
return true;
}
diff --git a/ZipEditor/src/zipeditor/actions/AddAction.java b/ZipEditor/src/zipeditor/actions/AddAction.java
index a7a71ed..064e741 100644
--- a/ZipEditor/src/zipeditor/actions/AddAction.java
+++ b/ZipEditor/src/zipeditor/actions/AddAction.java
@@ -10,7 +10,10 @@
import zipeditor.ZipEditorPlugin;
import zipeditor.model.Node;
+import zipeditor.model.ZipContentDescriber.ContentTypeId;
+import zipeditor.model.zstd.ZstdUtilities;
import zipeditor.operations.AddOperation;
+import zipeditor.preferences.PreferenceUtils;
public class AddAction extends DialogAction {
public AddAction(StructuredViewer viewer) {
@@ -20,13 +23,13 @@ public AddAction(StructuredViewer viewer) {
}
public void run() {
- File[] paths = openDialog(ActionMessages.getString("AddAction.2"), null, true, true); //$NON-NLS-1$);
- if (paths == null || paths.length == 0)
- return;
Node[] selectedNodes = getSelectedNodes();
Node targetNode = selectedNodes.length > 0 ? selectedNodes[0] : getViewerInputAsNode();
+ File[] paths = openDialog(ActionMessages.getString("AddAction.2"), null, true, true, PreferenceUtils.isZstdAvailableAndActive() && targetNode.getModel().getType() == ContentTypeId.ZIP_FILE); //$NON-NLS-1$);
+ if (paths == null || paths.length == 0)
+ return;
AddOperation operation = new AddOperation();
- operation.execute(paths, targetNode, null, getViewer());
+ operation.execute(paths, targetNode, null, getViewer(), ZstdUtilities.useZstdCompression(targetNode.getModel().getRoot()));
}
}
diff --git a/ZipEditor/src/zipeditor/actions/DialogAction.java b/ZipEditor/src/zipeditor/actions/DialogAction.java
index 9e2203f..7faa6ba 100644
--- a/ZipEditor/src/zipeditor/actions/DialogAction.java
+++ b/ZipEditor/src/zipeditor/actions/DialogAction.java
@@ -19,7 +19,10 @@
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
@@ -27,9 +30,12 @@
import org.eclipse.ui.PlatformUI;
import zipeditor.ZipEditorPlugin;
+import zipeditor.preferences.PreferenceUtils;
public abstract class DialogAction extends ViewerAction {
+ private boolean zstdCompression = false;
+
private class FileDialog extends Dialog implements ISelectionChangedListener {
private FileSystemChooseControl fWorkspaceViewer;
private FileSystemChooseControl fFileSystemViewer;
@@ -40,9 +46,11 @@ private class FileDialog extends Dialog implements ISelectionChangedListener {
private boolean fMultiSelection;
private boolean fShowFiles;
private File fInitialSelection;
+ private boolean fAllowZstd;
- private FileDialog(String text) {
+ private FileDialog(String text, boolean allowZstd) {
super(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
+ fAllowZstd = allowZstd;
setShellStyle(getShellStyle() | SWT.SHELL_TRIM);
fText = text;
}
@@ -68,6 +76,20 @@ protected Control createDialogArea(Composite parent) {
fStatusLabel = new Label(control, SWT.LEFT | SWT.WRAP);
fStatusLabel.setLayoutData(new GridData(GridData.FILL, SWT.END, true, false));
+ if (fAllowZstd) {
+ Button useZstdCheckbox = new Button(control, SWT.CHECK);
+ useZstdCheckbox.setText("Use Zstd Compression"); //$NON-NLS-1$
+ zstdCompression = PreferenceUtils.isZstdDefaultCompression();
+ useZstdCheckbox.setSelection(zstdCompression);
+ useZstdCheckbox.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ zstdCompression = useZstdCheckbox.getSelection();
+ }
+
+ });
+ }
applyDialogFont(control);
return control;
}
@@ -168,12 +190,16 @@ protected DialogAction(String text, StructuredViewer viewer, boolean useFilter)
super(text, viewer);
}
- protected File[] openDialog(String text, File path, boolean multiSelection, boolean showFiles) {
- FileDialog dialog = new FileDialog(text);
+ protected File[] openDialog(String text, File path, boolean multiSelection, boolean showFiles, boolean allowZstd) {
+ FileDialog dialog = new FileDialog(text, allowZstd);
dialog.setMultiSelection(multiSelection);
dialog.setShowFiles(showFiles);
dialog.setSelection(path);
int result = dialog.open();
return result == Window.OK ? dialog.getFiles() : null;
}
+
+ public boolean isZstdCompression() {
+ return zstdCompression;
+ }
}
diff --git a/ZipEditor/src/zipeditor/actions/ExtractAction.java b/ZipEditor/src/zipeditor/actions/ExtractAction.java
index f1c7e28..da5e4fd 100644
--- a/ZipEditor/src/zipeditor/actions/ExtractAction.java
+++ b/ZipEditor/src/zipeditor/actions/ExtractAction.java
@@ -45,7 +45,7 @@ public void run() {
Node[] nodes = getSelectedNodes();
if (nodes.length == 0)
nodes = new Node[] { getViewerInputAsNode() };
- File[] folder = openDialog(ActionMessages.getString("ExtractAction.2"), fSelectedFolder, false, false); //$NON-NLS-1$
+ File[] folder = openDialog(ActionMessages.getString("ExtractAction.2"), fSelectedFolder, false, false, false); //$NON-NLS-1$
if (folder != null && folder.length > 0) {
ExtractOperation operation = new ExtractOperation();
operation.setRefreshJob(new RefreshJob());
diff --git a/ZipEditor/src/zipeditor/messages.properties b/ZipEditor/src/zipeditor/messages.properties
index d403135..9e804b2 100644
--- a/ZipEditor/src/zipeditor/messages.properties
+++ b/ZipEditor/src/zipeditor/messages.properties
@@ -5,6 +5,8 @@ ZipEditor.11=Refreshing Zip editor
ZipEditor.12=An error has occurred while trying to save {0}
ZipEditor.13=Close
ZipEditor.14=Save
+ZipEditor.15=The content of this Zip file seems to be invalid.\n\nIt could be that Zstd support is disabled or the Zstd implementation libraries are not available.\nPlease check the Zip Editor preferences.
+ZipEditor.16=Open Preference Page
ZipEditor.2=Saving
ZipEditor.3=Computing number of archive entries
ZipEditor.4=File changed
@@ -67,3 +69,4 @@ TarNodePropertyPage.1=Invalid user id, must be an Integer
TarNodePropertyPage.2=Invalid mode
MappingPropertyAccessor.0=Stored
MappingPropertyAccessor.8=Deflated
+MappingPropertyAccessor.93=Zstd
diff --git a/ZipEditor/src/zipeditor/model/Node.java b/ZipEditor/src/zipeditor/model/Node.java
index 9b7df2e..2b294e4 100644
--- a/ZipEditor/src/zipeditor/model/Node.java
+++ b/ZipEditor/src/zipeditor/model/Node.java
@@ -14,6 +14,7 @@
import java.util.Iterator;
import java.util.List;
+import org.apache.commons.compress.archivers.zip.ZipMethod;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.NullOutputStream;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -283,8 +284,11 @@ public void add(Node node, Node beforeSibling) {
internalAdd(node, children != null && beforeSibling != null ? children.indexOf(beforeSibling) : -1);
}
- public void add(File file, Node beforeSibling, IProgressMonitor monitor) {
+ public void add(File file, Node beforeSibling, IProgressMonitor monitor, boolean useZstdCompression) {
Node node = create(model, file.getName(), file.isDirectory());
+ if (useZstdCompression && node instanceof ZipNode) {
+ ((ZipNode)node).setMethod(ZipMethod.ZSTD.getCode());
+ }
add(node, beforeSibling);
node.state |= ADDED;
if (node.isFolder()) {
@@ -295,7 +299,7 @@ public void add(File file, Node beforeSibling, IProgressMonitor monitor) {
if (monitor.isCanceled())
break;
monitor.subTask(files[i].getName());
- node.add(files[i], null, monitor);
+ node.add(files[i], null, monitor, useZstdCompression);
}
}
node.state |= MODIFIED;
diff --git a/ZipEditor/src/zipeditor/model/NodeProperty.java b/ZipEditor/src/zipeditor/model/NodeProperty.java
index 53b7041..36f7609 100644
--- a/ZipEditor/src/zipeditor/model/NodeProperty.java
+++ b/ZipEditor/src/zipeditor/model/NodeProperty.java
@@ -14,12 +14,14 @@ public class NodeProperty {
public static final int SIZE = 4;
public static final int PATH = 9;
public static final int PERSISTED = 12;
+ public static final int METHOD = 13;
public static final NodeProperty PNAME = new NodeProperty(NAME);
public static final NodeProperty PTYPE = new NodeProperty(TYPE);
public static final NodeProperty PDATE = new NodeProperty(DATE);
public static final NodeProperty PSIZE = new NodeProperty(SIZE);
public static final NodeProperty PPATH = new NodeProperty(PATH);
public static final NodeProperty PPERSISTED = new NodeProperty(PERSISTED);
+ public static final NodeProperty PMETHOD = new NodeProperty(METHOD);
protected int type;
protected NodeProperty(int type) {
diff --git a/ZipEditor/src/zipeditor/model/ZipContentDescriber.java b/ZipEditor/src/zipeditor/model/ZipContentDescriber.java
index 261284f..431018d 100644
--- a/ZipEditor/src/zipeditor/model/ZipContentDescriber.java
+++ b/ZipEditor/src/zipeditor/model/ZipContentDescriber.java
@@ -39,6 +39,8 @@ public static class ContentTypeId {
public final static ContentTypeId BZ2_FILE = add("bz2file", ContentTypeId.BZ2); //$NON-NLS-1$
public final static ContentTypeId TBZ_FILE = add("tarbz2file", ContentTypeId.TBZ); //$NON-NLS-1$
public final static ContentTypeId RPM_FILE = add("rpmfile", ContentTypeId.RPM); //$NON-NLS-1$
+ // Avoid handling as file, due this is a dummy for invalid file contents.
+ public final static ContentTypeId INVALID = new ContentTypeId("invalid", -1); // $NON-NLS-1$
private static void init() {}
diff --git a/ZipEditor/src/zipeditor/model/ZipEditorZstdException.java b/ZipEditor/src/zipeditor/model/ZipEditorZstdException.java
new file mode 100644
index 0000000..2fd0018
--- /dev/null
+++ b/ZipEditor/src/zipeditor/model/ZipEditorZstdException.java
@@ -0,0 +1,20 @@
+package zipeditor.model;
+
+import java.io.IOException;
+
+/**
+ * This is just a marker class to differ all other {@link IOException}s from the
+ * Zstd problems. If this exception is thrown, than either the zstd support is
+ * not activated or the selected zstd compression library is not available. If
+ * this exception is thrown the zip editor should warn, that this zip file
+ * contains zstd compression which can't be opened.
+ */
+public class ZipEditorZstdException extends IOException {
+
+ public ZipEditorZstdException(String message) {
+ super(message);
+ }
+
+ private static final long serialVersionUID = 8897411573370620194L;
+
+}
diff --git a/ZipEditor/src/zipeditor/model/ZipModel.java b/ZipEditor/src/zipeditor/model/ZipModel.java
index 51a5da4..4925edc 100644
--- a/ZipEditor/src/zipeditor/model/ZipModel.java
+++ b/ZipEditor/src/zipeditor/model/ZipModel.java
@@ -18,12 +18,12 @@
import java.util.zip.CRC32;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
-import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+import org.apache.commons.compress.archivers.zip.ZipMethod;
import org.apache.tools.bzip2.CBZip2InputStream;
import org.apache.tools.bzip2.CBZip2OutputStream;
import org.apache.tools.tar.TarConstants;
@@ -37,12 +37,14 @@
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.ui.statushandlers.StatusManager;
import zipeditor.Messages;
import zipeditor.Utils;
import zipeditor.ZipEditorPlugin;
import zipeditor.model.IModelListener.ModelChangeEvent;
import zipeditor.model.ZipContentDescriber.ContentTypeId;
+import zipeditor.model.zstd.ZstdUtilities;
import zipeditor.rpm.RpmEntry;
import zipeditor.rpm.RpmInputStream;
@@ -105,13 +107,18 @@ public static ContentTypeId detectType(InputStream contents) {
if (count == -1)
return null;
try {
- ZipArchiveInputStream zip = new ZipArchiveInputStream(contents);
+ ZipArchiveInputStream zip = new ZstdAwareZipArchiveInputStream(contents);
if (zip.getNextEntry() != null) {
contents.reset();
return ContentTypeId.ZIP_FILE;
}
} catch (IOException ioe) {
- // thrown in getNextEntry() method if, if file is not a zip file.
+ if (ioe instanceof ZipEditorZstdException) {
+ // thrown if zstd support is not active or library is missing
+ // we can close further actions with this zip file.
+ return ContentTypeId.INVALID;
+ }
+ // thrown in getNextEntry() method, if file is not a zip file.
}
contents.reset();
try {
@@ -257,9 +264,15 @@ private void initialize(InputStream inputStream, IModelInitParticipant participa
InputStream zipStream = inputStream;
try {
zipStream = detectStream(inputStream);
+ if (ContentTypeId.INVALID == type) {
+ return;
+ }
root = getRoot(zipStream);
readStream(zipStream, participant, stopNode);
} catch (IOException e) {
+ if (e instanceof ZipEditorZstdException) {
+ type = ContentTypeId.INVALID;
+ }
// ignore
} finally {
if (zipStream != null && participant == null) {
@@ -308,6 +321,11 @@ else if (zipStream instanceof TarInputStream)
else if (zipStream instanceof RpmInputStream)
rpmEntry = ((RpmInputStream) zipStream).getNextEntry();
} catch (Exception e) {
+ if (e instanceof ZipEditorZstdException) {
+ type = ContentTypeId.INVALID;
+ // No log no error dialog necessary.. Editor will deactivate itself with a hint.
+ return;
+ }
String message = "Error reading archive"; //$NON-NLS-1$
if (zipPath != null)
message += " " + zipPath.getAbsolutePath(); //$NON-NLS-1$
@@ -434,7 +452,7 @@ private InputStream detectStream(InputStream contents) throws IOException {
default:
return in;
case ContentTypeId.ZIP:
- return new ZipArchiveInputStream(in);
+ return new ZstdAwareZipArchiveInputStream(in);
case ContentTypeId.TAR:
return new TarInputStream(in);
case ContentTypeId.GZ:
@@ -512,7 +530,7 @@ private void saveNode(OutputStream out, Node node, ContentTypeId type, IProgress
monitor.subTask(entryName);
zipEntry.setComment(((ZipNode) node).getComment());
zipEntry.setMethod(((ZipNode) node).getMethod());
- if (zipEntry.getMethod() == ZipEntry.STORED) {
+ if (zipEntry.getMethod() == ZipMethod.STORED.getCode() || zipEntry.getMethod() == ZipMethod.ZSTD.getCode() || zipEntry.getMethod() == ZipMethod.ZSTD_DEPRECATED.getCode()) {
handleCrc(node, entryName, zipEntry);
}
}
@@ -535,10 +553,17 @@ private void saveNode(OutputStream out, Node node, ContentTypeId type, IProgress
((ZipArchiveOutputStream) out).putArchiveEntry(zipEntry);
else if (out instanceof TarOutputStream)
((TarOutputStream) out).putNextEntry(tarEntry);
- Utils.readAndWrite(node.getContent(), out, false);
+ if (node instanceof ZipNode && ((ZipNode)node).getMethod() == ZipMethod.ZSTD.getCode()) {
+ try (OutputStream zstdOutput = ZstdUtilities.getOutputStream(out)) {
+ Utils.readAndWrite(node.getContent(), zstdOutput, false);
+ zstdOutput.flush();
+ }
+ } else {
+ Utils.readAndWrite(node.getContent(), out, false);
+ }
if (zipEntry != null) {
((ZipArchiveOutputStream)out).closeArchiveEntry();
- }
+ }
if (tarEntry != null)
((TarOutputStream) out).closeEntry();
monitor.worked(1);
diff --git a/ZipEditor/src/zipeditor/model/ZipNode.java b/ZipEditor/src/zipeditor/model/ZipNode.java
index 1b263ed..bec1b0b 100644
--- a/ZipEditor/src/zipeditor/model/ZipNode.java
+++ b/ZipEditor/src/zipeditor/model/ZipNode.java
@@ -5,6 +5,8 @@
package zipeditor.model;
import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.commons.compress.archivers.zip.ZipMethod;
+import zipeditor.model.zstd.ZstdUtilities;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import java.io.IOException;
import java.io.InputStream;
@@ -82,14 +84,25 @@ public void setMethod(int method) {
protected InputStream doGetContent() throws IOException {
InputStream in = super.doGetContent();
- if (in != null)
+ if (in != null) {
return in;
- if (zipEntry != null) {
- return model.getZipPath() != null ? new EntryStream(zipEntry, ZipFile.builder().setFile(model.getZipPath()).get()) : null;
+ }
+ if (zipEntry != null && model.getZipPath() != null) {
+ ZipFile zipFile;
+ if (isZstdEncoded(zipEntry)) {
+ zipFile = ZstdUtilities.getZipFileBuilder().setFile(model.getZipPath()).get();
+ } else {
+ zipFile = ZipFile.builder().setFile(model.getZipPath()).get();
+ }
+ return new EntryStream(zipEntry, zipFile);
}
return null;
}
+ private static boolean isZstdEncoded(ZipArchiveEntry zipEntry) {
+ return zipEntry.getMethod() == ZipMethod.ZSTD.getCode() || zipEntry.getMethod() == ZipMethod.ZSTD_DEPRECATED.getCode();
+ }
+
public void reset() {
super.reset();
if (zipEntry != null) {
diff --git a/ZipEditor/src/zipeditor/model/ZipRootNode.java b/ZipEditor/src/zipeditor/model/ZipRootNode.java
index a4d25ab..85cec50 100644
--- a/ZipEditor/src/zipeditor/model/ZipRootNode.java
+++ b/ZipEditor/src/zipeditor/model/ZipRootNode.java
@@ -13,4 +13,29 @@ public ZipRootNode(ZipModel model) {
public Node create(ZipModel model, String name, boolean isFolder) {
return new ZipNode(model, name, isFolder);
}
+
+ /**
+ * This method can be used to check if new compression methods can be used without doubts.
+ *
+ * @param zipMethod the compression method to check
+ * @return true if the given zipMethod was already used in this node model, else false.
+ */
+ public boolean hasContentWithCompression(int zipMethod) {
+ return hasContentWithCompression(this, zipMethod);
+ }
+
+ private boolean hasContentWithCompression(Node parentNode, int zipMethod) {
+ for (Node node : parentNode.getChildren()) {
+ if (!(node instanceof ZipNode zipNode)) {
+ continue;
+ }
+ if (zipNode.getMethod() == zipMethod) {
+ return true;
+ }
+ if (hasContentWithCompression(zipNode, zipMethod)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/ZipEditor/src/zipeditor/model/ZstdAwareZipArchiveInputStream.java b/ZipEditor/src/zipeditor/model/ZstdAwareZipArchiveInputStream.java
new file mode 100644
index 0000000..13a223d
--- /dev/null
+++ b/ZipEditor/src/zipeditor/model/ZstdAwareZipArchiveInputStream.java
@@ -0,0 +1,20 @@
+package zipeditor.model;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
+
+import zipeditor.model.zstd.ZstdUtilities;
+
+public final class ZstdAwareZipArchiveInputStream extends ZipArchiveInputStream {
+ public ZstdAwareZipArchiveInputStream(InputStream inputStream) {
+ super(inputStream, StandardCharsets.UTF_8.name(), true, true);
+ }
+
+ @Override
+ protected InputStream createZstdInputStream(InputStream in) throws IOException {
+ return ZstdUtilities.getInputStream(in);
+ }
+}
\ No newline at end of file
diff --git a/ZipEditor/src/zipeditor/model/zstd/AircompressorHandler.java b/ZipEditor/src/zipeditor/model/zstd/AircompressorHandler.java
new file mode 100644
index 0000000..e740cc8
--- /dev/null
+++ b/ZipEditor/src/zipeditor/model/zstd/AircompressorHandler.java
@@ -0,0 +1,28 @@
+package zipeditor.model.zstd;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.io.function.IOFunction;
+
+import io.airlift.compress.zstd.ZstdInputStream;
+import io.airlift.compress.zstd.ZstdOutputStream;
+
+public class AircompressorHandler implements ZstdImplementationHandler {
+
+ @Override
+ public InputStream createInputStream(InputStream input) {
+ return new ZstdInputStream(input);
+ }
+
+ @Override
+ public OutputStream createOutputStream(OutputStream output) throws IOException {
+ return new ZstdOutputStream(noClose(output));
+ }
+
+ @Override
+ public IOFunction getIOFunction() {
+ return ZstdInputStream::new;
+ }
+}
diff --git a/ZipEditor/src/zipeditor/model/zstd/JniZstdLibCompressorHandler.java b/ZipEditor/src/zipeditor/model/zstd/JniZstdLibCompressorHandler.java
new file mode 100644
index 0000000..879c617
--- /dev/null
+++ b/ZipEditor/src/zipeditor/model/zstd/JniZstdLibCompressorHandler.java
@@ -0,0 +1,29 @@
+package zipeditor.model.zstd;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.compress.compressors.zstandard.ZstdCompressorInputStream;
+import org.apache.commons.compress.compressors.zstandard.ZstdCompressorOutputStream;
+import org.apache.commons.io.function.IOFunction;
+
+import zipeditor.preferences.PreferenceUtils;
+
+public class JniZstdLibCompressorHandler implements ZstdImplementationHandler {
+
+ @Override
+ public InputStream createInputStream(InputStream input) throws IOException {
+ return new ZstdCompressorInputStream(input);
+ }
+
+ @Override
+ public OutputStream createOutputStream(OutputStream output) throws IOException {
+ return new ZstdCompressorOutputStream(noClose(output), PreferenceUtils.getCompressionLevel());
+ }
+
+ @Override
+ public IOFunction getIOFunction() {
+ return ZstdCompressorInputStream::new;
+ }
+}
diff --git a/ZipEditor/src/zipeditor/model/zstd/Messages.java b/ZipEditor/src/zipeditor/model/zstd/Messages.java
new file mode 100644
index 0000000..dd309e0
--- /dev/null
+++ b/ZipEditor/src/zipeditor/model/zstd/Messages.java
@@ -0,0 +1,18 @@
+package zipeditor.model.zstd;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = Messages.class.getPackageName() + ".messages"; //$NON-NLS-1$
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+
+ public static String ZstdHandler_aircompLibNotAvailable;
+ public static String ZstdHandler_jniLibNotAvailable;
+ public static String ZstdHandler_notActive;
+}
diff --git a/ZipEditor/src/zipeditor/model/zstd/ZstdImplementationHandler.java b/ZipEditor/src/zipeditor/model/zstd/ZstdImplementationHandler.java
new file mode 100644
index 0000000..2f27bd3
--- /dev/null
+++ b/ZipEditor/src/zipeditor/model/zstd/ZstdImplementationHandler.java
@@ -0,0 +1,36 @@
+package zipeditor.model.zstd;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.io.function.IOFunction;
+
+public interface ZstdImplementationHandler {
+
+ default OutputStream noClose(OutputStream out) {
+ return new OutputStream() {
+ @Override
+ public void write(byte[] b) throws IOException {
+ out.write(b);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ out.write(b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ out.write(b, off, len);
+ }
+ };
+ }
+
+ InputStream createInputStream(InputStream input) throws IOException;
+
+ OutputStream createOutputStream(OutputStream output) throws IOException;
+
+ IOFunction getIOFunction();
+
+}
diff --git a/ZipEditor/src/zipeditor/model/zstd/ZstdUtilities.java b/ZipEditor/src/zipeditor/model/zstd/ZstdUtilities.java
new file mode 100644
index 0000000..18719aa
--- /dev/null
+++ b/ZipEditor/src/zipeditor/model/zstd/ZstdUtilities.java
@@ -0,0 +1,83 @@
+package zipeditor.model.zstd;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.commons.compress.archivers.zip.ZipMethod;
+import org.apache.commons.compress.archivers.zip.ZipFile.Builder;
+import org.apache.commons.compress.compressors.zstandard.ZstdUtils;
+
+import zipeditor.model.Node;
+import zipeditor.model.RootNode;
+import zipeditor.model.ZipEditorZstdException;
+import zipeditor.model.ZipRootNode;
+import zipeditor.preferences.PreferenceUtils;
+
+public class ZstdUtilities {
+
+ public static InputStream getInputStream(InputStream in) throws IOException {
+ if (!PreferenceUtils.isZstdAvailableAndActive()) {
+ throw new ZipEditorZstdException(Messages.ZstdHandler_notActive);
+ }
+ String library = PreferenceUtils.getSelectedOrAvailableLibrary();
+ if (PreferenceUtils.JNI_LIBRARY.equals(library)) {
+ return new JniZstdLibCompressorHandler().createInputStream(in);
+ } else {
+ return new AircompressorHandler().createInputStream(in);
+ }
+ }
+
+ public static OutputStream getOutputStream(OutputStream out) throws IOException {
+ if (!PreferenceUtils.isZstdAvailableAndActive()) {
+ throw new ZipEditorZstdException(Messages.ZstdHandler_notActive);
+ }
+ String library = PreferenceUtils.getSelectedOrAvailableLibrary();
+ if (PreferenceUtils.JNI_LIBRARY.equals(library)) {
+ return new JniZstdLibCompressorHandler().createOutputStream(out);
+ } else {
+ return new AircompressorHandler().createOutputStream(out);
+ }
+ }
+
+ private static boolean hasAircompressor;
+ private static boolean checked;
+ public static boolean isAircompressorAvailable() {
+ if (checked)
+ return hasAircompressor;
+
+ checked = true;
+ try {
+ Class.forName("io.airlift.compress.zstd.ZstdInputStream"); //$NON-NLS-1$
+ hasAircompressor = true;
+ } catch (ClassNotFoundException e) {
+ hasAircompressor = false;
+ }
+ return hasAircompressor;
+ }
+
+ public static Builder getZipFileBuilder() throws ZipEditorZstdException {
+ if (!PreferenceUtils.isZstdAvailableAndActive()) {
+ throw new ZipEditorZstdException(Messages.ZstdHandler_notActive);
+ }
+ String library = PreferenceUtils.getSelectedOrAvailableLibrary();
+ if (PreferenceUtils.JNI_LIBRARY.equals(library)) {
+ return ZipFile.builder();
+ } else {
+ return ZipFile.builder().setZstdInputStreamFactory(new AircompressorHandler().getIOFunction());
+ }
+ }
+
+ public static boolean isZstdJniCompressionAvailable() {
+ return ZstdUtils.isZstdCompressionAvailable();
+ }
+
+ public static boolean useZstdCompression(Node parentNode) {
+ boolean useZstdCompression = PreferenceUtils.isZstdAvailableAndActive() && PreferenceUtils.isZstdDefaultCompression();
+ RootNode root = parentNode.getModel().getRoot();
+ if (useZstdCompression && root instanceof ZipRootNode zipRootNode) {
+ useZstdCompression = zipRootNode.getChildren().length == 0 || zipRootNode.hasContentWithCompression(ZipMethod.ZSTD.getCode());
+ }
+ return useZstdCompression;
+ }
+}
diff --git a/ZipEditor/src/zipeditor/model/zstd/messages.properties b/ZipEditor/src/zipeditor/model/zstd/messages.properties
new file mode 100644
index 0000000..8206a1d
--- /dev/null
+++ b/ZipEditor/src/zipeditor/model/zstd/messages.properties
@@ -0,0 +1,3 @@
+ZstdHandler_aircompLibNotAvailable=Aircompressor is selected but not available
+ZstdHandler_jniLibNotAvailable=zstd-jni library is not available
+ZstdHandler_notActive=Support for zstd is deactivated or there is no available zstd library. Please check the zip editor settings.
diff --git a/ZipEditor/src/zipeditor/operations/AddOperation.java b/ZipEditor/src/zipeditor/operations/AddOperation.java
index c197114..59fb918 100644
--- a/ZipEditor/src/zipeditor/operations/AddOperation.java
+++ b/ZipEditor/src/zipeditor/operations/AddOperation.java
@@ -25,13 +25,15 @@ private class AddFilesJob extends Job {
private Node fParentNode;
private Node fBeforeSibling;
private UIJob fRefreshJob;
+ private boolean fUseZstdCompression;
- public AddFilesJob(File[] filesNames, Node parentNode, Node beforeSibling, UIJob refreshJob) {
+ public AddFilesJob(File[] filesNames, Node parentNode, Node beforeSibling, UIJob refreshJob, boolean useZstdCompression) {
super(Messages.getString("AddOperation.1")); //$NON-NLS-1$
fFilesNames = filesNames;
fParentNode = parentNode;
fBeforeSibling = beforeSibling;
fRefreshJob = refreshJob;
+ fUseZstdCompression = useZstdCompression;
}
public IStatus run(IProgressMonitor monitor) {
@@ -47,7 +49,7 @@ public IStatus run(IProgressMonitor monitor) {
if (subMonitor.isCanceled())
break;
try {
- fParentNode.add(fFilesNames[i], fBeforeSibling, subMonitor);
+ fParentNode.add(fFilesNames[i], fBeforeSibling, subMonitor, fUseZstdCompression);
oneAdded = true;
} catch (Exception e) {
return ZipEditorPlugin.createErrorStatus(Messages.getString("AddOperation.0"), e); //$NON-NLS-1$
@@ -82,18 +84,22 @@ public IStatus runInUIThread(IProgressMonitor monitor) {
};
public void execute(String[] fileNames, Node parentNode, Node beforeSibling, StructuredViewer viewer) {
- execute(getFilesFromNames(fileNames), parentNode, beforeSibling, viewer);
+ // The default case is disabled zstd compressoin. This is done to not disturb all other cases.
+ execute(fileNames, parentNode, beforeSibling, viewer, false);
}
- public void execute(File[] fileNames, Node parentNode, Node beforeSibling, StructuredViewer viewer) {
-
+ public void execute(String[] fileNames, Node parentNode, Node beforeSibling, StructuredViewer viewer, boolean useZstdCompression) {
+ execute(getFilesFromNames(fileNames), parentNode, beforeSibling, viewer, useZstdCompression);
+ }
+
+ public void execute(File[] fileNames, Node parentNode, Node beforeSibling, StructuredViewer viewer, boolean useZstdCompression) {
while (parentNode != null && !parentNode.isFolder())
parentNode = parentNode.getParent();
- AddFilesJob addFilesJob = new AddFilesJob(fileNames, parentNode, beforeSibling, new RefreshJob(viewer));
+ AddFilesJob addFilesJob = new AddFilesJob(fileNames, parentNode, beforeSibling, new RefreshJob(viewer), useZstdCompression);
addFilesJob.schedule();
}
- private File[] getFilesFromNames(String[] filesNames) {
+ public File[] getFilesFromNames(String[] filesNames) {
File[] files = new File[filesNames.length];
for (int i = 0; i < files.length; i++) {
files[i] = new File(filesNames[i]);
diff --git a/ZipEditor/src/zipeditor/operations/ExtractOperation.java b/ZipEditor/src/zipeditor/operations/ExtractOperation.java
index c2a4e82..9c15fc1 100644
--- a/ZipEditor/src/zipeditor/operations/ExtractOperation.java
+++ b/ZipEditor/src/zipeditor/operations/ExtractOperation.java
@@ -9,6 +9,7 @@
import java.util.HashSet;
import java.util.Set;
+import org.apache.commons.io.IOUtils;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
@@ -172,7 +173,9 @@ private File internalExtract(Node node, File toDir, boolean overwrite, boolean f
try {
extracting.add(file);
long time = System.currentTimeMillis();
- Utils.readAndWrite(node.getContent(), new FileOutputStream(file), true);
+ try (FileOutputStream out = new FileOutputStream(file)) {
+ IOUtils.copyLarge(node.getContent(), out);
+ }
if (ZipEditorPlugin.DEBUG)
System.out.println("Extracted " + node + " in " + (System.currentTimeMillis() - time) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} catch (Exception e) {
diff --git a/ZipEditor/src/zipeditor/preferences/Messages.java b/ZipEditor/src/zipeditor/preferences/Messages.java
new file mode 100644
index 0000000..5f68f08
--- /dev/null
+++ b/ZipEditor/src/zipeditor/preferences/Messages.java
@@ -0,0 +1,26 @@
+package zipeditor.preferences;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = Messages.class.getPackageName() + ".messages"; //$NON-NLS-1$
+ public static String PreferenceUtils_AircompressorLabel;
+ public static String PreferenceUtils_ZSTDJniLibraryLabel;
+ public static String ZipEditorPreferencePage_LibAvailable;
+ public static String ZipEditorPreferencePage_LibNotAvailable;
+ public static String ZipEditorPreferencePage_ZstdAsDefaultCompression;
+ public static String ZipEditorPreferencePage_ZstdCompressionLevel;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+
+ public static String ZipEditorPreferencePage_ActivateZstdSupport;
+ public static String ZipEditorPreferencePage_HintNoLibraries;
+ public static String ZipEditorPreferencePage_ScaleValueCompressionLevel;
+ public static String ZipEditorPreferencePage_ZstdLibrary;
+ public static String ZipEditorPreferencePage_ZstdSettingsGroupTitle;
+}
diff --git a/ZipEditor/src/zipeditor/preferences/PreferenceUtils.java b/ZipEditor/src/zipeditor/preferences/PreferenceUtils.java
new file mode 100644
index 0000000..3a59c29
--- /dev/null
+++ b/ZipEditor/src/zipeditor/preferences/PreferenceUtils.java
@@ -0,0 +1,150 @@
+package zipeditor.preferences;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+
+import zipeditor.PreferenceConstants;
+import zipeditor.ZipEditorPlugin;
+import zipeditor.model.zstd.ZstdUtilities;
+
+public class PreferenceUtils {
+
+ public record ZstdLibrary(String label, String identifier) {
+ public ZstdLibrary(String label, String identifier) {
+ this.label = label;
+ this.identifier = identifier;
+ }
+ }
+ /**
+ * Preference value for the aircompressor library.
+ */
+ public static final String AIRCOMPRESSOR = "aircompressor"; //$NON-NLS-1$
+
+ /**
+ * Preference value for the zstd-jni library.
+ */
+ public static final String JNI_LIBRARY = "jniLibrary"; //$NON-NLS-1$
+
+ public static final List libraries = new ArrayList();
+ static {
+ libraries.add(new ZstdLibrary(Messages.PreferenceUtils_ZSTDJniLibraryLabel, JNI_LIBRARY));
+ libraries.add(new ZstdLibrary(Messages.PreferenceUtils_AircompressorLabel, AIRCOMPRESSOR));
+ }
+
+ private static String getSelectedZstdLib() {
+ IPreferenceStore preferenceStore = ZipEditorPlugin.getDefault().getPreferenceStore();
+ String selectedLib = preferenceStore
+ .getString(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.SELECTED_ZSTD_LIB);
+ return selectedLib;
+ }
+
+ /**
+ * Returns the available libraries.
+ * @return a {@link List} of available {@link ZstdLibrary} objects.
+ */
+ public static List getAvailableLibraries() {
+ List availableLibs = new ArrayList();
+ for (ZstdLibrary libData : libraries) {
+ if (libData.identifier.equals(JNI_LIBRARY) && ZstdUtilities.isZstdJniCompressionAvailable()) {
+ availableLibs.add(libData);
+ } else if (libData.identifier.equals(AIRCOMPRESSOR) && ZstdUtilities.isAircompressorAvailable()) {
+ availableLibs.add(libData);
+ }
+ }
+ return availableLibs;
+ }
+
+ /**
+ * Returns the available libraries.
+ * @return a {@link List} of available {@link ZstdLibrary} objects.
+ */
+ public static String[][] getAvailableLibrariesForPreferenceUI() {
+ List availableLibraries = getAvailableLibraries();
+ String[][] libs = new String[availableLibraries.size()][2];
+ for (int i = 0; i < availableLibraries.size(); i++) {
+ ZstdLibrary zstdLibrary = availableLibraries.get(i);
+ libs[i] = new String[] { zstdLibrary.label, zstdLibrary.identifier };
+ }
+ return libs;
+ }
+
+ /**
+ * @return true, if the zstd handling is active.
+ */
+ static boolean isZstdActive() {
+ IPreferenceStore preferenceStore = ZipEditorPlugin.getDefault().getPreferenceStore();
+ return preferenceStore.getBoolean(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.ACTIVATE_ZSTD_LIB);
+ }
+
+ /**
+ * @return true, if the zstd-jni library is selected for zstd handling.
+ */
+ public static boolean isJNIZstdSelected() {
+ String selectedLib = getSelectedZstdLib();
+
+ return JNI_LIBRARY.equals(selectedLib);
+ }
+
+ /**
+ * @return true, if the aircompressor library is selected for zstd handling.
+ */
+ public static boolean isAircompressorSelected() {
+ String selectedLib = getSelectedZstdLib();
+
+ return AIRCOMPRESSOR.equals(selectedLib);
+ }
+
+ /**
+ * Checks if any zstd library is available and the zstd active pref is true.
+ *
+ * @return
+ */
+ public static boolean isZstdAvailableAndActive() {
+ return isZstdActive() && getAvailableLibraries().size() > 0;
+ }
+
+ /**
+ * Returns the preference value for default zstd compression
+ *
+ * @return true if zstd can be used as default or it returns false.
+ */
+ public static boolean isZstdDefaultCompression() {
+ IPreferenceStore preferenceStore = ZipEditorPlugin.getDefault().getPreferenceStore();
+ return preferenceStore.getBoolean(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.USE_ZSTD_AS_DEFAULT);
+ }
+
+ /**
+ * Returns the preference value for the zstd compression level.
+ *
+ * @return the value of the compression level preference.
+ */
+ public static int getCompressionLevel() {
+ IPreferenceStore preferenceStore = ZipEditorPlugin.getDefault().getPreferenceStore();
+ return preferenceStore.getInt(PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.COMPRESSION_LEVEL);
+ }
+
+ /**
+ * Checks if the selected library is available and returns it.
+ * If the selected library is not available it returns the available one.
+ *
+ * @return the selected or available library.
+ * identifier of the library which is written in the constants JNI_LIBRARY or AIRCOMPRESSOR
+ * or null if there is no library available.
+ */
+ public static String getSelectedOrAvailableLibrary() {
+ List availableLibraries = getAvailableLibraries();
+ if (availableLibraries.size() == 0) {
+ return null;
+ }
+ String selectedZstdLibIdentifier = getSelectedZstdLib();
+ for (ZstdLibrary library : availableLibraries) {
+ if (selectedZstdLibIdentifier.equals(library.identifier)) {
+ return selectedZstdLibIdentifier;
+ }
+ }
+
+ return availableLibraries.get(0).identifier;
+ }
+}
diff --git a/ZipEditor/src/zipeditor/preferences/ZipEditorPreferencePage.java b/ZipEditor/src/zipeditor/preferences/ZipEditorPreferencePage.java
new file mode 100644
index 0000000..cc9ddeb
--- /dev/null
+++ b/ZipEditor/src/zipeditor/preferences/ZipEditorPreferencePage.java
@@ -0,0 +1,161 @@
+package zipeditor.preferences;
+
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.preference.*;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.IWorkbench;
+import zipeditor.PreferenceConstants;
+import zipeditor.ZipEditorPlugin;
+
+/**
+ * This is the Preference Page for changing the zstd library for reading / writing a zstd compressed stream.
+ * The zstd libraries are optional so the zstd handling can also be disabled, which will lead to loose of the zstd compressed data, after saving.
+ */
+public class ZipEditorPreferencePage
+ extends FieldEditorPreferencePage
+ implements IWorkbenchPreferencePage, IPropertyChangeListener {
+
+ private ComboFieldEditor zstdLibComboFieldEditor;
+ private BooleanFieldEditor zstdStateFieldEditor;
+ private BooleanFieldEditor fBooleanFieldEditor;
+ private ScaleFieldEditor zstdCompressionLevelFieldEditor;
+ private Label fLScaleValue;
+
+ public ZipEditorPreferencePage() {
+ super(GRID);
+ setPreferenceStore(ZipEditorPlugin.getDefault().getPreferenceStore());
+ }
+
+ public void createFieldEditors() {
+ String[][] availableLibraries = PreferenceUtils.getAvailableLibrariesForPreferenceUI();
+ if (availableLibraries.length >= 1) {
+ zstdStateFieldEditor = new BooleanFieldEditor(
+ PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.ACTIVATE_ZSTD_LIB,
+ Messages.ZipEditorPreferencePage_ActivateZstdSupport,
+ getFieldEditorParent());
+ addField(zstdStateFieldEditor);
+
+ if (availableLibraries.length == 1) {
+ Label lLibraryName = new Label(getFieldEditorParent(), SWT.NONE);
+ GridDataFactory.fillDefaults().span(2, 1).applyTo(lLibraryName);
+ lLibraryName.setText(Messages.ZipEditorPreferencePage_ZstdLibrary + ' ' + availableLibraries[0][0]);
+
+
+ if (PreferenceUtils.JNI_LIBRARY.equals(availableLibraries[0][1])) {
+ addZstdCompressionLevelField();
+ }
+ } else {
+ String selectedZstdLibPrefName = PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.SELECTED_ZSTD_LIB;
+ zstdLibComboFieldEditor = new ComboFieldEditor(selectedZstdLibPrefName, Messages.ZipEditorPreferencePage_ZstdLibrary, availableLibraries, getFieldEditorParent()) {
+ @Override
+ protected void valueChanged(String oldValue, String newValue) {
+ super.valueChanged(oldValue, newValue);
+
+ boolean isVisible = PreferenceUtils.JNI_LIBRARY.equals(newValue);
+ zstdCompressionLevelFieldEditor.getScaleControl().setVisible(isVisible);
+ zstdCompressionLevelFieldEditor.getLabelControl(getFieldEditorParent()).setVisible(isVisible);
+ fLScaleValue.setVisible(isVisible);
+
+ zstdCompressionLevelFieldEditor.getScaleControl().setEnabled(isVisible);
+ zstdCompressionLevelFieldEditor.getLabelControl(getFieldEditorParent()).setEnabled(isVisible);
+ fLScaleValue.setEnabled(isVisible);
+ }
+ };
+ addField(zstdLibComboFieldEditor);
+ zstdLibComboFieldEditor.setEnabled(PreferenceUtils.isZstdActive(), getFieldEditorParent());
+ getPreferenceStore().addPropertyChangeListener(this);
+
+ addZstdCompressionLevelField();
+ }
+
+ String zstdDefaultPrefName = PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.USE_ZSTD_AS_DEFAULT;
+ fBooleanFieldEditor = new BooleanFieldEditor(zstdDefaultPrefName, Messages.ZipEditorPreferencePage_ZstdAsDefaultCompression, getFieldEditorParent());
+ addField(fBooleanFieldEditor);
+ fBooleanFieldEditor.setEnabled(PreferenceUtils.isZstdActive(), getFieldEditorParent());
+
+ } else {
+ Label lHint = new Label(getFieldEditorParent(), SWT.WRAP);
+ lHint.setText(Messages.ZipEditorPreferencePage_HintNoLibraries);
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(false, false).applyTo(lHint);
+ lHint.pack(true);
+ }
+ }
+
+ private void addZstdCompressionLevelField() {
+ String zstdCompressionLevelPrefName = PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.COMPRESSION_LEVEL;
+ zstdCompressionLevelFieldEditor = new ScaleFieldEditor(zstdCompressionLevelPrefName, Messages.ZipEditorPreferencePage_ZstdCompressionLevel, getFieldEditorParent());
+ addField(zstdCompressionLevelFieldEditor);
+ zstdCompressionLevelFieldEditor.setMaximum(0);
+ zstdCompressionLevelFieldEditor.setMaximum(22);
+ zstdCompressionLevelFieldEditor.setIncrement(1);
+ fLScaleValue = new Label(getFieldEditorParent(), SWT.WRAP);
+ GridDataFactory.fillDefaults().span(2, 1).align(SWT.FILL, SWT.FILL).grab(true, false).applyTo(fLScaleValue);
+ zstdCompressionLevelFieldEditor.getScaleControl().addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ int selection = zstdCompressionLevelFieldEditor.getScaleControl().getSelection();
+ fLScaleValue.setText(Messages.ZipEditorPreferencePage_ScaleValueCompressionLevel + selection);
+ }
+ });
+
+ zstdCompressionLevelFieldEditor.load();
+ fLScaleValue.setText(Messages.ZipEditorPreferencePage_ScaleValueCompressionLevel + PreferenceUtils.getCompressionLevel());
+
+ boolean aircompNotSelected = !PreferenceUtils.isAircompressorSelected();
+
+ zstdCompressionLevelFieldEditor.getScaleControl().setVisible(aircompNotSelected);
+ zstdCompressionLevelFieldEditor.getLabelControl(getFieldEditorParent()).setVisible(aircompNotSelected);
+ fLScaleValue.setVisible(aircompNotSelected);
+
+ if (aircompNotSelected) {
+ boolean isEnabled = PreferenceUtils.isZstdAvailableAndActive();
+
+ zstdCompressionLevelFieldEditor.getScaleControl().setEnabled(isEnabled);
+ zstdCompressionLevelFieldEditor.getLabelControl(getFieldEditorParent()).setEnabled(isEnabled);
+ fLScaleValue.setEnabled(isEnabled);
+ }
+ }
+
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ super.propertyChange(event);
+
+ if (event.getSource() instanceof BooleanFieldEditor booleanFieldEditor) {
+ if ((PreferenceConstants.PREFIX_EDITOR + PreferenceConstants.ACTIVATE_ZSTD_LIB).equals(booleanFieldEditor.getPreferenceName())) {
+ boolean isEnabled = (boolean) event.getNewValue();
+ if (zstdLibComboFieldEditor != null) {
+ zstdLibComboFieldEditor.setEnabled(isEnabled, getFieldEditorParent());
+ }
+ if (zstdCompressionLevelFieldEditor != null) {
+ zstdCompressionLevelFieldEditor.setEnabled(isEnabled, getFieldEditorParent());
+ }
+ if (fLScaleValue != null) {
+ fLScaleValue.setEnabled(isEnabled);
+ }
+ if (fBooleanFieldEditor != null) {
+ fBooleanFieldEditor.setEnabled(isEnabled, getFieldEditorParent());
+ }
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+ getPreferenceStore().removePropertyChangeListener(this);
+
+ super.dispose();
+ }
+
+ @Override
+ public void init(IWorkbench workbench) {
+ // nothing to do..
+ }
+
+}
\ No newline at end of file
diff --git a/ZipEditor/src/zipeditor/preferences/messages.properties b/ZipEditor/src/zipeditor/preferences/messages.properties
new file mode 100644
index 0000000..b64d644
--- /dev/null
+++ b/ZipEditor/src/zipeditor/preferences/messages.properties
@@ -0,0 +1,11 @@
+PreferenceUtils_AircompressorLabel=Aircompressor
+PreferenceUtils_ZSTDJniLibraryLabel=JNI Library
+ZipEditorPreferencePage_ActivateZstdSupport=Activate Zstd Support
+ZipEditorPreferencePage_HintNoLibraries=Zstd zip compression support is not available.\nIf you want to use zstd compression, you have to install a library that provides zstd compression, like zstd-jni or aircompressor.
+ZipEditorPreferencePage_LibAvailable=Library is available
+ZipEditorPreferencePage_LibNotAvailable=Library is not available
+ZipEditorPreferencePage_ScaleValueCompressionLevel=Selected Compression level:
+ZipEditorPreferencePage_ZstdAsDefaultCompression=Use Zstd compression by default for new zip files
+ZipEditorPreferencePage_ZstdCompressionLevel=Compression Level:
+ZipEditorPreferencePage_ZstdLibrary=Zstd Library:
+ZipEditorPreferencePage_ZstdSettingsGroupTitle=Zstd Settings:
diff --git a/maven-bnd/README.md b/maven-bnd/README.md
new file mode 100644
index 0000000..6660cfa
--- /dev/null
+++ b/maven-bnd/README.md
@@ -0,0 +1,15 @@
+# Maven BND
+
+## Content
+
+A [content report](../report/maven-bnd/merged-target/REPORT.md) is generated for the contents of [MavenBND.target](tp/MavenBND.target) with links to the artifacts in Maven Central.
+
+
+## Updates
+
+Updates are provided by [https://download.eclipse.org/tools/orbit/simrel/maven-bnd](https://download.eclipse.org/tools/orbit/simrel/maven-bnd).
+
+
+## Builds
+
+Builds are driven by [https://ci.eclipse.org/orbit/job/orbit-simrel-maven-bnd](https://ci.eclipse.org/orbit/job/orbit-simrel-maven-bnd).
diff --git a/maven-bnd/pom.xml b/maven-bnd/pom.xml
new file mode 100644
index 0000000..b37c6f0
--- /dev/null
+++ b/maven-bnd/pom.xml
@@ -0,0 +1,147 @@
+
+
+ 4.0.0
+
+ org.eclipse.orbit.maven-bnd
+ org.eclipse.orbit.maven-bnd.parent
+ pom
+
+
+ com.github
+ ../
+ 1.0.0-SNAPSHOT
+ ZipEditor.parent
+
+
+
+ UTF-8
+ 1.5.2
+ yyyyMMddHHmm
+ 1.1.1-SNAPSHOT
+
+
+
+
+ tycho-snapshots
+ https://repo.eclipse.org/content/repositories/tycho-snapshots
+
+
+
+ eclipse-maven-releases
+ https://repo.eclipse.org/content/repositories/releases
+
+
+
+ eclipse-cbi-releases
+ https://repo.eclipse.org/content/repositories/cbi-releases
+
+
+ maven-repository
+ https://repo1.maven.org/maven2
+
+
+ apache-repository
+ https://repository.apache.org/content/repositories/snapshots
+
+ true
+
+
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-maven-plugin
+ true
+
+
+ org.eclipse.tycho
+ tycho-p2-publisher-plugin
+ ${tycho-version}
+
+ true
+
+
+
+ org.eclipse.tycho
+ target-platform-configuration
+ ${tycho-version}
+
+
+
+ org.eclipse.orbit.maven-bnd
+ org.eclipse.orbit.maven-bnd.tp
+ 1.0.0-SNAPSHOT
+ MavenBND
+
+
+ JavaSE-21
+
+
+ win32
+ win32
+ x86_64
+
+
+ macosx
+ cocoa
+ x86_64
+
+
+ macosx
+ cocoa
+ aarch64
+
+
+ linux
+ gtk
+ x86_64
+
+
+ linux
+ gtk
+ aarch64
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-maven-plugin
+ ${tycho-version}
+ true
+
+
+ org.eclipse.cbi.maven.plugins
+ eclipse-jarsigner-plugin
+ ${jarsigner-version}
+
+
+ org.apache.maven.shared
+ maven-shared-utils
+ 3.4.2
+
+
+
+
+
+
+
+
+ tp
+ site
+
+
+
\ No newline at end of file
diff --git a/maven-bnd/site/.gitignore b/maven-bnd/site/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/maven-bnd/site/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/maven-bnd/site/.project b/maven-bnd/site/.project
new file mode 100644
index 0000000..3a020d4
--- /dev/null
+++ b/maven-bnd/site/.project
@@ -0,0 +1,17 @@
+
+
+ site
+
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/maven-bnd/site/category.xml b/maven-bnd/site/category.xml
new file mode 100644
index 0000000..afde35c
--- /dev/null
+++ b/maven-bnd/site/category.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/maven-bnd/site/pom.xml b/maven-bnd/site/pom.xml
new file mode 100644
index 0000000..f553cfd
--- /dev/null
+++ b/maven-bnd/site/pom.xml
@@ -0,0 +1,34 @@
+
+
+ 4.0.0
+
+ org.eclipse.orbit.maven-bnd
+ org.eclipse.orbit.maven-bnd.parent
+ 1.0.0-SNAPSHOT
+ ..
+
+
+ org.eclipse.orbit.maven-bnd.site
+ eclipse-repository
+
+
+
+
+ org.eclipse.tycho
+ tycho-p2-repository-plugin
+ ${tycho-version}
+
+ Orbit Maven BND
+ true
+ true
+ false
+ false
+
+
+
+
+
+
diff --git a/maven-bnd/tp/MavenBND.target b/maven-bnd/tp/MavenBND.target
new file mode 100644
index 0000000..da61190
--- /dev/null
+++ b/maven-bnd/tp/MavenBND.target
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+ io.airlift
+ aircompressor
+ 2.0.2
+ jar
+
+
+
+
+ Id1
+ https://repo1.maven.org/maven2/
+
+
+
+
+
+
+
+ org.apache.commons
+ commons-compress
+ 1.28.0-SNAPSHOT
+ jar
+
+
+ org.apache.commons
+ commons-lang3
+ 3.18.0-SNAPSHOT
+ jar
+
+
+
+
+ apache snapshot
+ https://repository.apache.org/content/repositories/snapshots/
+
+
+
+
+
+
+
+ com.github.luben
+ zstd-jni
+ 1.5.7-2
+ jar
+
+
+
+
+
+
\ No newline at end of file
diff --git a/maven-bnd/tp/pom.xml b/maven-bnd/tp/pom.xml
new file mode 100644
index 0000000..e75e699
--- /dev/null
+++ b/maven-bnd/tp/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ 4.0.0
+
+ org.eclipse.orbit.maven-bnd
+ org.eclipse.orbit.maven-bnd.parent
+ 1.0.0-SNAPSHOT
+ ..
+
+ org.eclipse.orbit.maven-bnd.tp
+ eclipse-target-definition
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..e55bcd4
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,48 @@
+
+ 4.0.0
+
+ com.github
+ ZipEditor.parent
+ 1.0.0-SNAPSHOT
+ pom
+
+
+ 4.0.13
+
+
+
+ maven-bnd
+ ZipEditor
+ zipeditor.feature
+ ZipEditor.targetPlatform
+ ZipEditor.UpdateSite
+
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-maven-plugin
+ ${tycho-version}
+ true
+
+
+ org.eclipse.cbi.maven.plugins
+ eclipse-jarsigner-plugin
+ ${jarsigner-version}
+
+
+ org.apache.maven.shared
+ maven-shared-utils
+ 3.4.2
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zipeditor.feature/.gitignore b/zipeditor.feature/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/zipeditor.feature/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/ZipEditor Feature/.project b/zipeditor.feature/.project
similarity index 91%
rename from ZipEditor Feature/.project
rename to zipeditor.feature/.project
index 057f33a..5bbd900 100644
--- a/ZipEditor Feature/.project
+++ b/zipeditor.feature/.project
@@ -1,6 +1,6 @@
- ZipEditor Feature
+ zipeditor.feature
diff --git a/ZipEditor Feature/.settings/org.eclipse.core.resources.prefs b/zipeditor.feature/.settings/org.eclipse.core.resources.prefs
similarity index 50%
rename from ZipEditor Feature/.settings/org.eclipse.core.resources.prefs
rename to zipeditor.feature/.settings/org.eclipse.core.resources.prefs
index 370ae2c..99f26c0 100644
--- a/ZipEditor Feature/.settings/org.eclipse.core.resources.prefs
+++ b/zipeditor.feature/.settings/org.eclipse.core.resources.prefs
@@ -1,2 +1,2 @@
eclipse.preferences.version=1
-encoding/=ISO-8859-1
+encoding/=UTF-8
diff --git a/ZipEditor Feature/cpl10.txt b/zipeditor.feature/cpl10.txt
similarity index 100%
rename from ZipEditor Feature/cpl10.txt
rename to zipeditor.feature/cpl10.txt
diff --git a/zipeditor.feature/feature.xml b/zipeditor.feature/feature.xml
new file mode 100644
index 0000000..695f73c
--- /dev/null
+++ b/zipeditor.feature/feature.xml
@@ -0,0 +1,266 @@
+
+
+
+
+ An Eclipse editor to manipulate archives.
+1.2.0
+---------------------
+- zstd zip encoding support
+1.1.9
+---------------------
+- Support search within non-archive files as well
+1.1.8
+---------------------
+- Replaced some references to deprecated types/methods
+1.1.7
+---------------------
+- https://sourceforge.net/p/zipeditor/bugs/14/ remove references to org.eclipse.jface.util.Assert
+1.1.6
+---------------------
+- https://sourceforge.net/p/zipeditor/bugs/11/ disable debug by default
+- https://sourceforge.net/p/zipeditor/bugs/12/ don't log too much
+- https://sourceforge.net/p/zipeditor/bugs/13/ late opening of files
+1.1.5
+---------------------
+- added RPM read functionality
+- added method (compressed/stored) to zip entries
+- save archive type specific editor settings
+- general performance improvements
+New in release 1.1.4
+---------------------
+- Ctrl+O in the editor opens a quick outline
+- "Open in Zip Editor" can be used on build path entries
+- Editors opened on search results show marker annotations for occurrences now.\
+
+New in release 1.1.3
+---------------------
+- Use the Eclipse search to recursively search in archives.
+
+
+
+ © Uwe Voigt, 2006, 2007. All Rights Reserved.
+
+
+
+ THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS
+COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR
+DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
+OF THIS AGREEMENT.
+1. DEFINITIONS
+"Contribution" means:
+a) in the case of the initial Contributor, the initial code and
+documentation distributed under this Agreement, and
+b) in the case of each subsequent Contributor:
+i) changes to the Program, and
+ii) additions to the Program;
+where such changes and/or additions to the Program originate
+from and are distributed by that particular Contributor. A Contribution
+'originates' from a Contributor if it was added to the Program
+by such Contributor itself or anyone acting on such Contributor's
+behalf. Contributions do not include additions to the Program
+which:(i) are separate modules of software distributed in conjunction
+with the Program under their own license agreement, and (ii)
+are not derivative works of the Program.
+"Contributor" means any person or entity that distributes the
+Program.
+"Licensed Patents " mean patent claims licensable by a Contributor
+which are necessarily infringed by the use or sale of its Contribution
+alone or when combined with the Program.
+"Program" means the Contributions distributed in accordance with
+this Agreement.
+"Recipient" means anyone who receives the Program under this
+Agreement, including all Contributors.
+2. GRANT OF RIGHTS
+a) Subject to the terms of this Agreement, each Contributor hereby
+grants Recipient a non-exclusive, worldwide, royalty-free copyright
+license to reproduce, prepare derivative works of, publicly display,
+publicly perform, distribute and sublicense the Contribution
+of such Contributor, if any, and such derivative works, in source
+code and object code form.
+b) Subject to the terms of this Agreement, each Contributor hereby
+grants Recipient a non-exclusive, worldwide, royalty-free patent
+license under Licensed Patents to make, use, sell, offer to sell,
+import and otherwise transfer the Contribution of such Contributor,
+if any, in source code and object code form. This patent license
+shall apply to the combination of the Contribution and the Program
+if, at the time the Contribution is added by the Contributor,
+such addition of the Contribution causes such combination to
+be covered by the Licensed Patents. The patent license shall
+not apply to any other combinations which include the Contribution.
+No hardware per se is licensed hereunder.
+c) Recipient understands that although each Contributor grants
+the licenses to its Contributions set forth herein, no assurances
+are provided by any Contributor that the Program does not infringe
+the patent or other intellectual property rights of any other
+entity. Each Contributor disclaims any liability to Recipient
+for claims brought by any other entity based on infringement
+of intellectual property rights or otherwise. As a condition
+to exercising the rights and licenses granted hereunder, each
+Recipient hereby assumes sole responsibility to secure any other
+intellectual property rights needed, if any. For example, if
+a third party patent license is required to allow Recipient to
+distribute the Program, it is Recipient's responsibility to acquire
+that license before distributing the Program.
+d) Each Contributor represents that to its knowledge it has sufficient
+copyright rights in its Contribution, if any, to grant the copyright
+license set forth in this Agreement.
+3. REQUIREMENTS
+A Contributor may choose to distribute the Program in object
+code form under its own license agreement, provided that:
+a) it complies with the terms and conditions of this Agreement;
+and
+b) its license agreement:
+i) effectively disclaims on behalf of all Contributors all warranties
+and conditions, express and implied, including warranties or
+conditions of title and non-infringement, and implied warranties
+or conditions of merchantability and fitness for a particular
+purpose;
+ii) effectively excludes on behalf of all Contributors all liability
+for damages, including direct, indirect, special, incidental
+and consequential damages, such as lost profits;
+iii) states that any provisions which differ from this Agreement
+are offered by that Contributor alone and not by any other party;
+and
+iv) states that source code for the Program is available from
+such Contributor, and informs licensees how to obtain it in a
+reasonable manner on or through a medium customarily used for
+software exchange.
+When the Program is made available in source code form:
+a) it must be made available under this Agreement; and
+b) a copy of this Agreement must be included with each copy of
+the Program.
+Contributors may not remove or alter any copyright notices contained
+within the Program.
+Each Contributor must identify itself as the originator of its
+Contribution, if any, in a manner that reasonably allows subsequent
+Recipients to identify the originator of the Contribution.
+4. COMMERCIAL DISTRIBUTION
+Commercial distributors of software may accept certain responsibilities
+with respect to end users, business partners and the like. While
+this license is intended to facilitate the commercial use of
+the Program, the Contributor who includes the Program in a commercial
+product offering should do so in a manner which does not create
+potential liability for other Contributors. Therefore, if a Contributor
+includes the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify
+every other Contributor ("Indemnified Contributor") against any
+losses, damages and costs (collectively "Losses") arising from
+claims, lawsuits and other legal actions brought by a third party
+against the Indemnified Contributor to the extent caused by the
+acts or omissions of such Commercial Contributor in connection
+with its distribution of the Program in a commercial product
+offering. The obligations in this section do not apply to any
+claims or Losses relating to any actual or alleged intellectual
+property infringement. In order to qualify, an Indemnified Contributor
+must: a) promptly notify the Commercial Contributor in writing
+of such claim, and b) allow the Commercial Contributor to control,
+and cooperate with the Commercial Contributor in, the defense
+and any related settlement negotiations. The Indemnified Contributor
+may participate in any such claim at its own expense.
+For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have
+to defend claims against the other Contributors related to those
+performance claims and warranties, and if a court requires any
+other Contributor to pay any damages as a result, the Commercial
+Contributor must pay those damages.
+5. NO WARRANTY
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM
+IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,
+ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with
+its exercise of rights under this Agreement, including but not
+limited to the risks and costs of program errors, compliance
+with applicable laws, damage to or loss of data, programs or
+equipment, and unavailability or interruption of operations.
+6. DISCLAIMER OF LIABILITY
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
+NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE
+OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGES.
+7. GENERAL
+If any provision of this Agreement is invalid or unenforceable
+under applicable law, it shall not affect the validity or enforceability
+of the remainder of the terms of this Agreement, and without
+further action by the parties hereto, such provision shall be
+reformed to the minimum extent necessary to make such provision
+valid and enforceable.
+If Recipient institutes patent litigation against a Contributor
+with respect to a patent applicable to software (including a
+cross-claim or counterclaim in a lawsuit), then any patent licenses
+granted by that Contributor to such Recipient under this Agreement
+shall terminate as of the date such litigation is filed. In addition,
+if Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging
+that the Program itself (excluding combinations of the Program
+with other software or hardware) infringes such Recipient's patent(s),
+then such Recipient's rights granted under Section 2(b) shall
+terminate as of the date such litigation is filed.
+All Recipient's rights under this Agreement shall terminate if
+it fails to comply with any of the material terms or conditions
+of this Agreement and does not cure such failure in a reasonable
+period of time after becoming aware of such noncompliance. If
+all Recipient's rights under this Agreement terminate, Recipient
+agrees to cease use and distribution of the Program as soon as
+reasonably practicable. However, Recipient's obligations under
+this Agreement and any licenses granted by Recipient relating
+to the Program shall continue and survive.
+Everyone is permitted to copy and distribute copies of this Agreement,
+but in order to avoid inconsistency the Agreement is copyrighted
+and may only be modified in the following manner. The Agreement
+Steward reserves the right to publish new versions (including
+revisions) of this Agreement from time to time. No one other
+than the Agreement Steward has the right to modify this Agreement.
+IBM is the initial Agreement Steward. IBM may assign the responsibility
+to serve as the Agreement Steward to a suitable separate entity.
+Each new version of the Agreement will be given a distinguishing
+version number. The Program (including Contributions) may always
+be distributed subject to the version of the Agreement under
+which it was received. In addition, after a new version of the
+Agreement is published, Contributor may elect to distribute the
+Program (including its Contributions) under the new version.
+Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
+receives no rights or licenses to the intellectual property of
+any Contributor under this Agreement, whether expressly, by implication,
+estoppel or otherwise. All rights in the Program not expressly
+granted under this Agreement are reserved.
+This Agreement is governed by the laws of the State of New York
+and the intellectual property laws of the United States of America.
+No party to this Agreement will bring a legal action under this
+Agreement more than one year after the cause of action arose.
+Each party waives its rights to a jury trial in any resulting
+litigation.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/zipeditor.feature/pom.xml b/zipeditor.feature/pom.xml
new file mode 100644
index 0000000..8370dfa
--- /dev/null
+++ b/zipeditor.feature/pom.xml
@@ -0,0 +1,72 @@
+
+ 4.0.0
+
+ zipeditor.feature
+ eclipse-feature
+ 1.2.1-SNAPSHOT
+
+ ..
+ ZipEditor.parent
+ com.github
+ 1.0.0-SNAPSHOT
+
+ Zip Editor Feature
+ This is the feature of the Zip editor
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-packaging-plugin
+ ${tycho.version}
+
+
+ default-validate-id
+ none
+
+
+
+
+ org.eclipse.tycho
+ tycho-maven-plugin
+ true
+
+
+ org.eclipse.tycho
+ tycho-packaging-plugin
+ ${tycho-version}
+
+
+ attach-sources
+
+ package-feature
+
+
+
+
+
+
+
+
+
+ localtarget
+ file:/${project.basedir}/../maven-bnd/site/target/repository/
+ p2
+
+
+ eclipse 2025-06
+ http://download.eclipse.org/releases/2025-06
+ p2
+
+
+ apache-repository
+ https://repository.apache.org/content/repositories/snapshots
+
+ true
+
+
+
+