BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/src/LICENSES/license.txt b/src/LICENSES/license.txt
new file mode 100644
index 00000000..8c94be34
--- /dev/null
+++ b/src/LICENSES/license.txt
@@ -0,0 +1,12 @@
+imgscalr -> Apache License 2.0
+commons-cli -> Apache License 2.0
+commons-codec -> Apache License 2.0
+commons-lang3 -> Apache License 2.0
+commons-io -> Apache License 2.0
+isoparser -> Apache License 2.0
+zt-zip -> Apache License 2.0
+Procyon -> Apache License 2.0
+JD-GUI -> GPLv3
+apktool -> Apache License 2.0
+fernflower -> Apache License 2.0
+dex2jar -> Apache License 2.0
\ No newline at end of file
diff --git a/src/LICENSES/smali.txt b/src/LICENSES/smali.txt
new file mode 100644
index 00000000..4ce4514b
--- /dev/null
+++ b/src/LICENSES/smali.txt
@@ -0,0 +1,85 @@
+The majority of smali/baksmali is written and copyrighted by me (Ben Gruver)
+and released under the following license:
+
+*******************************************************************************
+Copyright (c) 2010 Ben Gruver (JesusFreke)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************
+
+
+Unless otherwise stated in the code/commit message, any changes with the
+committer of bgruv@google.com is copyrighted by Google Inc. and released
+under the following license:
+
+*******************************************************************************
+Copyright 2011, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************
+
+
+Various portions of the code are taken from the Android Open Source Project,
+and are used in accordance with the following license:
+
+*******************************************************************************
+Copyright (C) 2007 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*******************************************************************************
\ No newline at end of file
diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF
index 4a83d752..53f4396f 100644
--- a/src/META-INF/MANIFEST.MF
+++ b/src/META-INF/MANIFEST.MF
@@ -1,19 +1,3 @@
-Manifest-Version: 1.0
-Class-Path: . BytecodeViewer 2.9.9-preview2_lib/byteanalysis-1.0.jar B
- ytecodeViewer 2.9.9-preview2_lib/commons-codec-1.9.jar BytecodeViewer
- 2.9.9-preview2_lib/commons-io-2.4.jar BytecodeViewer 2.9.9-preview2_
- lib/commons-lang3-3.3.2.jar BytecodeViewer 2.9.9-preview2_lib/imgscal
- r-lib-4.2.jar BytecodeViewer 2.9.9-preview2_lib/jar-rename-1.6.jar By
- tecodeViewer 2.9.9-preview2_lib/jasmin-p2.5.jar BytecodeViewer 2.9.9-
- preview2_lib/jgraphx.jar BytecodeViewer 2.9.9-preview2_lib/rsyntaxtex
- tarea.jar BytecodeViewer 2.9.9-preview2_lib/smali-2.0.3-obf-patched.j
- ar BytecodeViewer 2.9.9-preview2_lib/baksmali-2.0.3.jar BytecodeViewe
- r 2.9.9-preview2_lib/fernflower-2017.jar BytecodeViewer 2.9.9-preview2
- _lib/commons-compiler.jar BytecodeViewer 2.9.9-preview2_lib/apktool_2
- .0.0rc4_obf.jar BytecodeViewer 2.9.9-preview2_lib/dex2jar_2.0_obf.jar
- BytecodeViewer 2.9.9-preview2_lib/jd-gui-1.0.0-RC4.jar BytecodeViewe
- r 2.9.9-preview2_lib/procyon-decompiler-0.5.30.jar BytecodeViewer 2.9
- .9-preview2_lib/cfr_0_125.jar BytecodeViewer 2.9.9-preview2_lib/commo
- ns-net-3.1.jar BytecodeViewer 2.9.9-preview2_lib/janino.jar
-Main-Class: the.bytecode.club.bytecodeviewer.BytecodeViewer
-
+Manifest-Version: 1.0
+Main-Class: the.bytecode.club.bytecodeviewer.BytecodeViewer
+
diff --git a/src/enjarify-4.zip b/src/enjarify-4.zip
new file mode 100644
index 00000000..a0bb48b6
Binary files /dev/null and b/src/enjarify-4.zip differ
diff --git a/src/org/apache/commons/cli/AlreadySelectedException.java b/src/org/apache/commons/cli/AlreadySelectedException.java
deleted file mode 100644
index 81ffc991..00000000
--- a/src/org/apache/commons/cli/AlreadySelectedException.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-/**
- * Thrown when more than one option in an option group
- * has been provided.
- *
- * @version $Id: AlreadySelectedException.java 1443102 2013-02-06 18:12:16Z tn $
- */
-public class AlreadySelectedException extends ParseException {
- /**
- * This exception {@code serialVersionUID}.
- */
- private static final long serialVersionUID = 3674381532418544760L;
-
- /** The option group selected. */
- private OptionGroup group;
-
- /** The option that triggered the exception. */
- private Option option;
-
- /**
- * Construct a new AlreadySelectedException
- * with the specified detail message.
- *
- * @param message the detail message
- */
- public AlreadySelectedException(String message) {
- super(message);
- }
-
- /**
- * Construct a new AlreadySelectedException
- * for the specified option group.
- *
- * @param group the option group already selected
- * @param option the option that triggered the exception
- * @since 1.2
- */
- public AlreadySelectedException(OptionGroup group, Option option) {
- this("The option '" + option.getKey() + "' was specified but an option from this group "
- + "has already been selected: '" + group.getSelected() + "'");
- this.group = group;
- this.option = option;
- }
-
- /**
- * Returns the option group where another option has been selected.
- *
- * @return the related option group
- * @since 1.2
- */
- public OptionGroup getOptionGroup() {
- return group;
- }
-
- /**
- * Returns the option that was added to the group and triggered the exception.
- *
- * @return the related option
- * @since 1.2
- */
- public Option getOption() {
- return option;
- }
-}
diff --git a/src/org/apache/commons/cli/AmbiguousOptionException.java b/src/org/apache/commons/cli/AmbiguousOptionException.java
deleted file mode 100644
index cc5089e3..00000000
--- a/src/org/apache/commons/cli/AmbiguousOptionException.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.util.Collection;
-import java.util.Iterator;
-
-/**
- * Exception thrown when an option can't be identified from a partial name.
- *
- * @version $Id: AmbiguousOptionException.java 1669814 2015-03-28 18:09:26Z britter $
- * @since 1.3
- */
-public class AmbiguousOptionException extends UnrecognizedOptionException {
- /**
- * This exception {@code serialVersionUID}.
- */
- private static final long serialVersionUID = 5829816121277947229L;
-
- /** The list of options matching the partial name specified */
- private final Collection matchingOptions;
-
- /**
- * Constructs a new AmbiguousOptionException.
- *
- * @param option the partial option name
- * @param matchingOptions the options matching the name
- */
- public AmbiguousOptionException(String option, Collection matchingOptions) {
- super(createMessage(option, matchingOptions), option);
- this.matchingOptions = matchingOptions;
- }
-
- /**
- * Returns the options matching the partial name.
- * @return a collection of options matching the name
- */
- public Collection getMatchingOptions() {
- return matchingOptions;
- }
-
- /**
- * Build the exception message from the specified list of options.
- *
- * @param option
- * @param matchingOptions
- * @return
- */
- private static String createMessage(String option, Collection matchingOptions) {
- StringBuilder buf = new StringBuilder("Ambiguous option: '");
- buf.append(option);
- buf.append("' (could be: ");
-
- Iterator it = matchingOptions.iterator();
- while (it.hasNext()) {
- buf.append("'");
- buf.append(it.next());
- buf.append("'");
- if (it.hasNext()) {
- buf.append(", ");
- }
- }
- buf.append(")");
-
- return buf.toString();
- }
-}
diff --git a/src/org/apache/commons/cli/BasicParser.java b/src/org/apache/commons/cli/BasicParser.java
deleted file mode 100644
index a4e42eec..00000000
--- a/src/org/apache/commons/cli/BasicParser.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-/**
- * The class BasicParser provides a very simple implementation of
- * the {@link Parser#flatten(Options, String[], boolean) flatten} method.
- *
- * @version $Id: BasicParser.java 1443102 2013-02-06 18:12:16Z tn $
- * @deprecated since 1.3, use the {@link DefaultParser} instead
- */
-@Deprecated
-public class BasicParser extends Parser {
- /**
- *
A simple implementation of {@link Parser}'s abstract
- * {@link Parser#flatten(Options, String[], boolean) flatten} method.
- *
- * Note: options
and stopAtNonOption
- * are not used in this flatten
method.
- *
- * @param options The command line {@link Options}
- * @param arguments The command line arguments to be parsed
- * @param stopAtNonOption Specifies whether to stop flattening
- * when an non option is found.
- * @return The arguments
String array.
- */
- @Override
- protected String[] flatten(@SuppressWarnings("unused") Options options,
- String[] arguments,
- @SuppressWarnings("unused") boolean stopAtNonOption) {
- // just echo the arguments
- return arguments;
- }
-}
diff --git a/src/org/apache/commons/cli/CommandLine.java b/src/org/apache/commons/cli/CommandLine.java
deleted file mode 100644
index ec46cda4..00000000
--- a/src/org/apache/commons/cli/CommandLine.java
+++ /dev/null
@@ -1,345 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Properties;
-
-/**
- * Represents list of arguments parsed against a {@link Options} descriptor.
- *
- * It allows querying of a boolean {@link #hasOption(String opt)},
- * in addition to retrieving the {@link #getOptionValue(String opt)}
- * for options requiring arguments.
- *
- * Additionally, any left-over or unrecognized arguments,
- * are available for further processing.
- *
- * @version $Id: CommandLine.java 1444365 2013-02-09 14:21:27Z tn $
- */
-public class CommandLine implements Serializable {
- /** The serial version UID. */
- private static final long serialVersionUID = 1L;
-
- /** the unrecognised options/arguments */
- private final List args = new LinkedList();
-
- /** the processed options */
- private final List options = new ArrayList ();
-
- /**
- * Creates a command line.
- */
- protected CommandLine() {
- // nothing to do
- }
-
- /**
- * Query to see if an option has been set.
- *
- * @param opt Short name of the option
- * @return true if set, false if not
- */
- public boolean hasOption(String opt) {
- return options.contains(resolveOption(opt));
- }
-
- /**
- * Query to see if an option has been set.
- *
- * @param opt character name of the option
- * @return true if set, false if not
- */
- public boolean hasOption(char opt) {
- return hasOption(String.valueOf(opt));
- }
-
- /**
- * Return the Object
type of this Option
.
- *
- * @param opt the name of the option
- * @return the type of this Option
- * @deprecated due to System.err message. Instead use getParsedOptionValue(String)
- */
- @Deprecated
- public Object getOptionObject(String opt) {
- try {
- return getParsedOptionValue(opt);
- } catch (ParseException pe) {
- System.err.println("Exception found converting " + opt + " to desired type: " + pe.getMessage());
- return null;
- }
- }
-
- /**
- * Return a version of this Option
converted to a particular type.
- *
- * @param opt the name of the option
- * @return the value parsed into a particular object
- * @throws ParseException if there are problems turning the option value into the desired type
- * @see PatternOptionBuilder
- * @since 1.2
- */
- public Object getParsedOptionValue(String opt) throws ParseException {
- String res = getOptionValue(opt);
- Option option = resolveOption(opt);
-
- if (option == null || res == null) {
- return null;
- }
-
- return TypeHandler.createValue(res, option.getType());
- }
-
- /**
- * Return the Object
type of this Option
.
- *
- * @param opt the name of the option
- * @return the type of opt
- */
- public Object getOptionObject(char opt) {
- return getOptionObject(String.valueOf(opt));
- }
-
- /**
- * Retrieve the first argument, if any, of this option.
- *
- * @param opt the name of the option
- * @return Value of the argument if option is set, and has an argument,
- * otherwise null.
- */
- public String getOptionValue(String opt) {
- String[] values = getOptionValues(opt);
-
- return (values == null) ? null : values[0];
- }
-
- /**
- * Retrieve the first argument, if any, of this option.
- *
- * @param opt the character name of the option
- * @return Value of the argument if option is set, and has an argument,
- * otherwise null.
- */
- public String getOptionValue(char opt) {
- return getOptionValue(String.valueOf(opt));
- }
-
- /**
- * Retrieves the array of values, if any, of an option.
- *
- * @param opt string name of the option
- * @return Values of the argument if option is set, and has an argument,
- * otherwise null.
- */
- public String[] getOptionValues(String opt) {
- List values = new ArrayList();
-
- for (Option option : options) {
- if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt())) {
- values.addAll(option.getValuesList());
- }
- }
-
- return values.isEmpty() ? null : values.toArray(new String[values.size()]);
- }
-
- /**
- * Retrieves the option object given the long or short option as a String
- *
- * @param opt short or long name of the option
- * @return Canonicalized option
- */
- private Option resolveOption(String opt) {
- opt = Util.stripLeadingHyphens(opt);
- for (Option option : options) {
- if (opt.equals(option.getOpt())) {
- return option;
- }
-
- if (opt.equals(option.getLongOpt())) {
- return option;
- }
-
- }
- return null;
- }
-
- /**
- * Retrieves the array of values, if any, of an option.
- *
- * @param opt character name of the option
- * @return Values of the argument if option is set, and has an argument,
- * otherwise null.
- */
- public String[] getOptionValues(char opt) {
- return getOptionValues(String.valueOf(opt));
- }
-
- /**
- * Retrieve the first argument, if any, of an option.
- *
- * @param opt name of the option
- * @param defaultValue is the default value to be returned if the option
- * is not specified
- * @return Value of the argument if option is set, and has an argument,
- * otherwise defaultValue
.
- */
- public String getOptionValue(String opt, String defaultValue) {
- String answer = getOptionValue(opt);
-
- return (answer != null) ? answer : defaultValue;
- }
-
- /**
- * Retrieve the argument, if any, of an option.
- *
- * @param opt character name of the option
- * @param defaultValue is the default value to be returned if the option
- * is not specified
- * @return Value of the argument if option is set, and has an argument,
- * otherwise defaultValue
.
- */
- public String getOptionValue(char opt, String defaultValue) {
- return getOptionValue(String.valueOf(opt), defaultValue);
- }
-
- /**
- * Retrieve the map of values associated to the option. This is convenient
- * for options specifying Java properties like -Dparam1=value1
- * -Dparam2=value2 . The first argument of the option is the key, and
- * the 2nd argument is the value. If the option has only one argument
- * (-Dfoo ) it is considered as a boolean flag and the value is
- * "true" .
- *
- * @param opt name of the option
- * @return The Properties mapped by the option, never null
- * even if the option doesn't exists
- * @since 1.2
- */
- public Properties getOptionProperties(String opt) {
- Properties props = new Properties();
-
- for (Option option : options) {
- if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt())) {
- List values = option.getValuesList();
- if (values.size() >= 2) {
- // use the first 2 arguments as the key/value pair
- props.put(values.get(0), values.get(1));
- } else if (values.size() == 1) {
- // no explicit value, handle it as a boolean
- props.put(values.get(0), "true");
- }
- }
- }
-
- return props;
- }
-
- /**
- * Retrieve any left-over non-recognized options and arguments
- *
- * @return remaining items passed in but not parsed as an array
- */
- public String[] getArgs() {
- String[] answer = new String[args.size()];
-
- args.toArray(answer);
-
- return answer;
- }
-
- /**
- * Retrieve any left-over non-recognized options and arguments
- *
- * @return remaining items passed in but not parsed as a List
.
- */
- public List getArgList() {
- return args;
- }
-
- /**
- * jkeyes
- * - commented out until it is implemented properly
- * Dump state, suitable for debugging.
- *
- * @return Stringified form of this object
- */
-
- /*
- public String toString() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("[ CommandLine: [ options: ");
- buf.append(options.toString());
- buf.append(" ] [ args: ");
- buf.append(args.toString());
- buf.append(" ] ]");
-
- return buf.toString();
- }
- */
-
- /**
- * Add left-over unrecognized option/argument.
- *
- * @param arg the unrecognised option/argument.
- */
- protected void addArg(String arg) {
- args.add(arg);
- }
-
- /**
- * Add an option to the command line. The values of the option are stored.
- *
- * @param opt the processed option
- */
- protected void addOption(Option opt) {
- options.add(opt);
- }
-
- /**
- * Returns an iterator over the Option members of CommandLine.
- *
- * @return an Iterator
over the processed {@link Option}
- * members of this {@link CommandLine}
- */
- public Iterator iterator() {
- return options.iterator();
- }
-
- /**
- * Returns an array of the processed {@link Option}s.
- *
- * @return an array of the processed {@link Option}s.
- */
- public Option[] getOptions() {
- Collection processed = options;
-
- // reinitialise array
- Option[] optionsArray = new Option[processed.size()];
-
- // return the array
- return processed.toArray(optionsArray);
- }
-}
diff --git a/src/org/apache/commons/cli/CommandLineParser.java b/src/org/apache/commons/cli/CommandLineParser.java
deleted file mode 100644
index 96ecb201..00000000
--- a/src/org/apache/commons/cli/CommandLineParser.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-/**
- * A class that implements the CommandLineParser
interface
- * can parse a String array according to the {@link Options} specified
- * and return a {@link CommandLine}.
- *
- * @version $Id: CommandLineParser.java 1443102 2013-02-06 18:12:16Z tn $
- */
-public interface CommandLineParser {
- /**
- * Parse the arguments according to the specified options.
- *
- * @param options the specified Options
- * @param arguments the command line arguments
- * @return the list of atomic option and value tokens
- *
- * @throws ParseException if there are any problems encountered
- * while parsing the command line tokens.
- */
- CommandLine parse(Options options, String[] arguments) throws ParseException;
-
- /**
- * Parse the arguments according to the specified options and
- * properties.
- *
- * @param options the specified Options
- * @param arguments the command line arguments
- * @param properties command line option name-value pairs
- * @return the list of atomic option and value tokens
- *
- * @throws ParseException if there are any problems encountered
- * while parsing the command line tokens.
- */
- /* To maintain binary compatibility, this is commented out.
- It is still in the abstract Parser class, so most users will
- still reap the benefit.
- CommandLine parse(Options options, String[] arguments, Properties properties)
- throws ParseException;
- */
-
- /**
- * Parse the arguments according to the specified options.
- *
- * @param options the specified Options
- * @param arguments the command line arguments
- * @param stopAtNonOption if true an unrecognized argument stops
- * the parsing and the remaining arguments are added to the
- * {@link CommandLine}s args list. If false an unrecognized
- * argument triggers a ParseException.
- *
- * @return the list of atomic option and value tokens
- * @throws ParseException if there are any problems encountered
- * while parsing the command line tokens.
- */
- CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException;
-
- /**
- * Parse the arguments according to the specified options and
- * properties.
- *
- * @param options the specified Options
- * @param arguments the command line arguments
- * @param properties command line option name-value pairs
- * @param stopAtNonOption if true an unrecognized argument stops
- * the parsing and the remaining arguments are added to the
- * {@link CommandLine}s args list. If false an unrecognized
- * argument triggers a ParseException.
- *
- * @return the list of atomic option and value tokens
- * @throws ParseException if there are any problems encountered
- * while parsing the command line tokens.
- */
- /* To maintain binary compatibility, this is commented out.
- It is still in the abstract Parser class, so most users will
- still reap the benefit.
- CommandLine parse(Options options, String[] arguments, Properties properties, boolean stopAtNonOption)
- throws ParseException;
- */
-}
diff --git a/src/org/apache/commons/cli/DefaultParser.java b/src/org/apache/commons/cli/DefaultParser.java
deleted file mode 100644
index 415323d6..00000000
--- a/src/org/apache/commons/cli/DefaultParser.java
+++ /dev/null
@@ -1,581 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Properties;
-
-/**
- * Default parser.
- *
- * @version $Id: DefaultParser.java 1677454 2015-05-03 17:13:54Z ggregory $
- * @since 1.3
- */
-public class DefaultParser implements CommandLineParser {
- /** The command-line instance. */
- protected CommandLine cmd;
-
- /** The current options. */
- protected Options options;
-
- /**
- * Flag indicating how unrecognized tokens are handled. true to stop
- * the parsing and add the remaining tokens to the args list.
- * false to throw an exception.
- */
- protected boolean stopAtNonOption;
-
- /** The token currently processed. */
- protected String currentToken;
-
- /** The last option parsed. */
- protected Option currentOption;
-
- /** Flag indicating if tokens should no longer be analyzed and simply added as arguments of the command line. */
- protected boolean skipParsing;
-
- /** The required options and groups expected to be found when parsing the command line. */
- protected List expectedOpts;
-
- public CommandLine parse(Options options, String[] arguments) throws ParseException {
- return parse(options, arguments, null);
- }
-
- /**
- * Parse the arguments according to the specified options and properties.
- *
- * @param options the specified Options
- * @param arguments the command line arguments
- * @param properties command line option name-value pairs
- * @return the list of atomic option and value tokens
- *
- * @throws ParseException if there are any problems encountered
- * while parsing the command line tokens.
- */
- public CommandLine parse(Options options, String[] arguments, Properties properties) throws ParseException {
- return parse(options, arguments, properties, false);
- }
-
- public CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException {
- return parse(options, arguments, null, stopAtNonOption);
- }
-
- /**
- * Parse the arguments according to the specified options and properties.
- *
- * @param options the specified Options
- * @param arguments the command line arguments
- * @param properties command line option name-value pairs
- * @param stopAtNonOption if true an unrecognized argument stops
- * the parsing and the remaining arguments are added to the
- * {@link CommandLine}s args list. If false an unrecognized
- * argument triggers a ParseException.
- *
- * @return the list of atomic option and value tokens
- * @throws ParseException if there are any problems encountered
- * while parsing the command line tokens.
- */
- public CommandLine parse(Options options, String[] arguments, Properties properties, boolean stopAtNonOption)
- throws ParseException {
- this.options = options;
- this.stopAtNonOption = stopAtNonOption;
- skipParsing = false;
- currentOption = null;
- expectedOpts = new ArrayList(options.getRequiredOptions());
-
- // clear the data from the groups
- for (OptionGroup group : options.getOptionGroups()) {
- group.setSelected(null);
- }
-
- cmd = new CommandLine();
-
- if (arguments != null) {
- for (String argument : arguments) {
- handleToken(argument);
- }
- }
-
- // check the arguments of the last option
- checkRequiredArgs();
-
- // add the default options
- handleProperties(properties);
-
- checkRequiredOptions();
-
- return cmd;
- }
-
- /**
- * Sets the values of Options using the values in properties
.
- *
- * @param properties The value properties to be processed.
- */
- private void handleProperties(Properties properties) throws ParseException {
- if (properties == null) {
- return;
- }
-
- for (Enumeration> e = properties.propertyNames(); e.hasMoreElements(); ) {
- String option = e.nextElement().toString();
-
- Option opt = options.getOption(option);
- if (opt == null) {
- throw new UnrecognizedOptionException("Default option wasn't defined", option);
- }
-
- // if the option is part of a group, check if another option of the group has been selected
- OptionGroup group = options.getOptionGroup(opt);
- boolean selected = group != null && group.getSelected() != null;
-
- if (!cmd.hasOption(option) && !selected) {
- // get the value from the properties
- String value = properties.getProperty(option);
-
- if (opt.hasArg()) {
- if (opt.getValues() == null || opt.getValues().length == 0) {
- opt.addValueForProcessing(value);
- }
- } else if (!("yes".equalsIgnoreCase(value)
- || "true".equalsIgnoreCase(value)
- || "1".equalsIgnoreCase(value))) {
- // if the value is not yes, true or 1 then don't add the option to the CommandLine
- continue;
- }
-
- handleOption(opt);
- currentOption = null;
- }
- }
- }
-
- /**
- * Throws a {@link MissingOptionException} if all of the required options
- * are not present.
- *
- * @throws MissingOptionException if any of the required Options
- * are not present.
- */
- private void checkRequiredOptions() throws MissingOptionException {
- // if there are required options that have not been processed
- if (!expectedOpts.isEmpty()) {
- throw new MissingOptionException(expectedOpts);
- }
- }
-
- /**
- * Throw a {@link MissingArgumentException} if the current option
- * didn't receive the number of arguments expected.
- */
- private void checkRequiredArgs() throws ParseException {
- if (currentOption != null && currentOption.requiresArg()) {
- throw new MissingArgumentException(currentOption);
- }
- }
-
- /**
- * Handle any command line token.
- *
- * @param token the command line token to handle
- * @throws ParseException
- */
- private void handleToken(String token) throws ParseException {
- currentToken = token;
-
- if (skipParsing) {
- cmd.addArg(token);
- } else if ("--".equals(token)) {
- skipParsing = true;
- } else if (currentOption != null && currentOption.acceptsArg() && isArgument(token)) {
- currentOption.addValueForProcessing(Util.stripLeadingAndTrailingQuotes(token));
- } else if (token.startsWith("--")) {
- handleLongOption(token);
- } else if (token.startsWith("-") && !"-".equals(token)) {
- handleShortAndLongOption(token);
- } else {
- handleUnknownToken(token);
- }
-
- if (currentOption != null && !currentOption.acceptsArg()) {
- currentOption = null;
- }
- }
-
- /**
- * Returns true is the token is a valid argument.
- *
- * @param token
- */
- private boolean isArgument(String token) {
- return !isOption(token) || isNegativeNumber(token);
- }
-
- /**
- * Check if the token is a negative number.
- *
- * @param token
- */
- private boolean isNegativeNumber(String token) {
- try {
- Double.parseDouble(token);
- return true;
- } catch (NumberFormatException e) {
- return false;
- }
- }
-
- /**
- * Tells if the token looks like an option.
- *
- * @param token
- */
- private boolean isOption(String token) {
- return isLongOption(token) || isShortOption(token);
- }
-
- /**
- * Tells if the token looks like a short option.
- *
- * @param token
- */
- private boolean isShortOption(String token) {
- // short options (-S, -SV, -S=V, -SV1=V2, -S1S2)
- return token.startsWith("-") && token.length() >= 2 && options.hasShortOption(token.substring(1, 2));
- }
-
- /**
- * Tells if the token looks like a long option.
- *
- * @param token
- */
- private boolean isLongOption(String token) {
- if (!token.startsWith("-") || token.length() == 1) {
- return false;
- }
-
- int pos = token.indexOf("=");
- String t = pos == -1 ? token : token.substring(0, pos);
-
- if (!options.getMatchingOptions(t).isEmpty()) {
- // long or partial long options (--L, -L, --L=V, -L=V, --l, --l=V)
- return true;
- } else if (getLongPrefix(token) != null && !token.startsWith("--")) {
- // -LV
- return true;
- }
-
- return false;
- }
-
- /**
- * Handles an unknown token. If the token starts with a dash an
- * UnrecognizedOptionException is thrown. Otherwise the token is added
- * to the arguments of the command line. If the stopAtNonOption flag
- * is set, this stops the parsing and the remaining tokens are added
- * as-is in the arguments of the command line.
- *
- * @param token the command line token to handle
- */
- private void handleUnknownToken(String token) throws ParseException {
- if (token.startsWith("-") && token.length() > 1 && !stopAtNonOption) {
- throw new UnrecognizedOptionException("Unrecognized option: " + token, token);
- }
-
- cmd.addArg(token);
- if (stopAtNonOption) {
- skipParsing = true;
- }
- }
-
- /**
- * Handles the following tokens:
- *
- * --L
- * --L=V
- * --L V
- * --l
- *
- * @param token the command line token to handle
- */
- private void handleLongOption(String token) throws ParseException {
- if (token.indexOf('=') == -1) {
- handleLongOptionWithoutEqual(token);
- } else {
- handleLongOptionWithEqual(token);
- }
- }
-
- /**
- * Handles the following tokens:
- *
- * --L
- * -L
- * --l
- * -l
- *
- * @param token the command line token to handle
- */
- private void handleLongOptionWithoutEqual(String token) throws ParseException {
- List matchingOpts = options.getMatchingOptions(token);
- if (matchingOpts.isEmpty()) {
- handleUnknownToken(currentToken);
- } else if (matchingOpts.size() > 1) {
- throw new AmbiguousOptionException(token, matchingOpts);
- } else {
- handleOption(options.getOption(matchingOpts.get(0)));
- }
- }
-
- /**
- * Handles the following tokens:
- *
- * --L=V
- * -L=V
- * --l=V
- * -l=V
- *
- * @param token the command line token to handle
- */
- private void handleLongOptionWithEqual(String token) throws ParseException {
- int pos = token.indexOf('=');
-
- String value = token.substring(pos + 1);
-
- String opt = token.substring(0, pos);
-
- List matchingOpts = options.getMatchingOptions(opt);
- if (matchingOpts.isEmpty()) {
- handleUnknownToken(currentToken);
- } else if (matchingOpts.size() > 1) {
- throw new AmbiguousOptionException(opt, matchingOpts);
- } else {
- Option option = options.getOption(matchingOpts.get(0));
-
- if (option.acceptsArg()) {
- handleOption(option);
- currentOption.addValueForProcessing(value);
- currentOption = null;
- } else {
- handleUnknownToken(currentToken);
- }
- }
- }
-
- /**
- * Handles the following tokens:
- *
- * -S
- * -SV
- * -S V
- * -S=V
- * -S1S2
- * -S1S2 V
- * -SV1=V2
- *
- * -L
- * -LV
- * -L V
- * -L=V
- * -l
- *
- * @param token the command line token to handle
- */
- private void handleShortAndLongOption(String token) throws ParseException {
- String t = Util.stripLeadingHyphens(token);
-
- int pos = t.indexOf('=');
-
- if (t.length() == 1) {
- // -S
- if (options.hasShortOption(t)) {
- handleOption(options.getOption(t));
- } else {
- handleUnknownToken(token);
- }
- } else if (pos == -1) {
- // no equal sign found (-xxx)
- if (options.hasShortOption(t)) {
- handleOption(options.getOption(t));
- } else if (!options.getMatchingOptions(t).isEmpty()) {
- // -L or -l
- handleLongOptionWithoutEqual(token);
- } else {
- // look for a long prefix (-Xmx512m)
- String opt = getLongPrefix(t);
-
- if (opt != null && options.getOption(opt).acceptsArg()) {
- handleOption(options.getOption(opt));
- currentOption.addValueForProcessing(t.substring(opt.length()));
- currentOption = null;
- } else if (isJavaProperty(t)) {
- // -SV1 (-Dflag)
- handleOption(options.getOption(t.substring(0, 1)));
- currentOption.addValueForProcessing(t.substring(1));
- currentOption = null;
- } else {
- // -S1S2S3 or -S1S2V
- handleConcatenatedOptions(token);
- }
- }
- } else {
- // equal sign found (-xxx=yyy)
- String opt = t.substring(0, pos);
- String value = t.substring(pos + 1);
-
- if (opt.length() == 1) {
- // -S=V
- Option option = options.getOption(opt);
- if (option != null && option.acceptsArg()) {
- handleOption(option);
- currentOption.addValueForProcessing(value);
- currentOption = null;
- } else {
- handleUnknownToken(token);
- }
- } else if (isJavaProperty(opt)) {
- // -SV1=V2 (-Dkey=value)
- handleOption(options.getOption(opt.substring(0, 1)));
- currentOption.addValueForProcessing(opt.substring(1));
- currentOption.addValueForProcessing(value);
- currentOption = null;
- } else {
- // -L=V or -l=V
- handleLongOptionWithEqual(token);
- }
- }
- }
-
- /**
- * Search for a prefix that is the long name of an option (-Xmx512m)
- *
- * @param token
- */
- private String getLongPrefix(String token) {
- String t = Util.stripLeadingHyphens(token);
-
- int i;
- String opt = null;
- for (i = t.length() - 2; i > 1; i--) {
- String prefix = t.substring(0, i);
- if (options.hasLongOption(prefix)) {
- opt = prefix;
- break;
- }
- }
-
- return opt;
- }
-
- /**
- * Check if the specified token is a Java-like property (-Dkey=value).
- */
- private boolean isJavaProperty(String token) {
- String opt = token.substring(0, 1);
- Option option = options.getOption(opt);
-
- return option != null && (option.getArgs() >= 2 || option.getArgs() == Option.UNLIMITED_VALUES);
- }
-
- private void handleOption(Option option) throws ParseException {
- // check the previous option before handling the next one
- checkRequiredArgs();
-
- option = (Option) option.clone();
-
- updateRequiredOptions(option);
-
- cmd.addOption(option);
-
- if (option.hasArg()) {
- currentOption = option;
- } else {
- currentOption = null;
- }
- }
-
- /**
- * Removes the option or its group from the list of expected elements.
- *
- * @param option
- */
- private void updateRequiredOptions(Option option) throws AlreadySelectedException {
- if (option.isRequired()) {
- expectedOpts.remove(option.getKey());
- }
-
- // if the option is in an OptionGroup make that option the selected option of the group
- if (options.getOptionGroup(option) != null) {
- OptionGroup group = options.getOptionGroup(option);
-
- if (group.isRequired()) {
- expectedOpts.remove(group);
- }
-
- group.setSelected(option);
- }
- }
-
- /**
- * Breaks token
into its constituent parts
- * using the following algorithm.
- *
- *
- * ignore the first character ("- ")
- * foreach remaining character check if an {@link Option}
- * exists with that id.
- * if an {@link Option} does exist then add that character
- * prepended with "- " to the list of processed tokens.
- * if the {@link Option} can have an argument value and there
- * are remaining characters in the token then add the remaining
- * characters as a token to the list of processed tokens.
- * if an {@link Option} does NOT exist AND
- * stopAtNonOption
IS set then add the special token
- * "-- " followed by the remaining characters and also
- * the remaining tokens directly to the processed tokens list.
- * if an {@link Option} does NOT exist AND
- * stopAtNonOption
IS NOT set then add that
- * character prepended with "- ".
- *
- *
- * @param token The current token to be burst
- * at the first non-Option encountered.
- * @throws ParseException if there are any problems encountered
- * while parsing the command line token.
- */
- protected void handleConcatenatedOptions(String token) throws ParseException {
- for (int i = 1; i < token.length(); i++) {
- String ch = String.valueOf(token.charAt(i));
-
- if (options.hasOption(ch)) {
- handleOption(options.getOption(ch));
-
- if (currentOption != null && token.length() != i + 1) {
- // add the trail as an argument of the option
- currentOption.addValueForProcessing(token.substring(i + 1));
- break;
- }
- } else {
- handleUnknownToken(stopAtNonOption && i > 1 ? token.substring(i) : token);
- break;
- }
- }
- }
-}
diff --git a/src/org/apache/commons/cli/GnuParser.java b/src/org/apache/commons/cli/GnuParser.java
deleted file mode 100644
index 29a2ee81..00000000
--- a/src/org/apache/commons/cli/GnuParser.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * The class GnuParser provides an implementation of the
- * {@link Parser#flatten(Options, String[], boolean) flatten} method.
- *
- * @version $Id: GnuParser.java 1445352 2013-02-12 20:48:19Z tn $
- * @deprecated since 1.3, use the {@link DefaultParser} instead
- */
-@Deprecated
-public class GnuParser extends Parser {
- /**
- * This flatten method does so using the following rules:
- *
- * If an {@link Option} exists for the first character of
- * the arguments
entry AND an {@link Option}
- * does not exist for the whole argument
then
- * add the first character as an option to the processed tokens
- * list e.g. "-D" and add the rest of the entry to the also.
- * Otherwise just add the token to the processed tokens list.
- *
- *
- * @param options The Options to parse the arguments by.
- * @param arguments The arguments that have to be flattened.
- * @param stopAtNonOption specifies whether to stop flattening when
- * a non option has been encountered
- * @return a String array of the flattened arguments
- */
- @Override
- protected String[] flatten(Options options, String[] arguments, boolean stopAtNonOption) {
- List tokens = new ArrayList();
-
- boolean eatTheRest = false;
-
- for (int i = 0; i < arguments.length; i++) {
- String arg = arguments[i];
-
- if ("--".equals(arg)) {
- eatTheRest = true;
- tokens.add("--");
- } else if ("-".equals(arg)) {
- tokens.add("-");
- } else if (arg.startsWith("-")) {
- String opt = Util.stripLeadingHyphens(arg);
-
- if (options.hasOption(opt)) {
- tokens.add(arg);
- } else {
- if (opt.indexOf('=') != -1 && options.hasOption(opt.substring(0, opt.indexOf('=')))) {
- // the format is --foo=value or -foo=value
- tokens.add(arg.substring(0, arg.indexOf('='))); // --foo
- tokens.add(arg.substring(arg.indexOf('=') + 1)); // value
- } else if (options.hasOption(arg.substring(0, 2))) {
- // the format is a special properties option (-Dproperty=value)
- tokens.add(arg.substring(0, 2)); // -D
- tokens.add(arg.substring(2)); // property=value
- } else {
- eatTheRest = stopAtNonOption;
- tokens.add(arg);
- }
- }
- } else {
- tokens.add(arg);
- }
-
- if (eatTheRest) {
- for (i++; i < arguments.length; i++) //NOPMD
- {
- tokens.add(arguments[i]);
- }
- }
- }
-
- return tokens.toArray(new String[tokens.size()]);
- }
-}
diff --git a/src/org/apache/commons/cli/HelpFormatter.java b/src/org/apache/commons/cli/HelpFormatter.java
deleted file mode 100644
index 88b0c8f6..00000000
--- a/src/org/apache/commons/cli/HelpFormatter.java
+++ /dev/null
@@ -1,994 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.Serializable;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * A formatter of help messages for command line options.
- *
- *
Example:
- *
- *
- * Options options = new Options();
- * options.addOption(OptionBuilder.withLongOpt("file")
- * .withDescription("The file to be processed")
- * .hasArg()
- * .withArgName("FILE")
- * .isRequired()
- * .create('f'));
- * options.addOption(OptionBuilder.withLongOpt("version")
- * .withDescription("Print the version of the application")
- * .create('v'));
- * options.addOption(OptionBuilder.withLongOpt("help").create('h'));
- *
- * String header = "Do something useful with an input file\n\n";
- * String footer = "\nPlease report issues at http://example.com/issues";
- *
- * HelpFormatter formatter = new HelpFormatter();
- * formatter.printHelp("myapp", header, options, footer, true);
- *
- *
- * This produces the following output:
- *
- *
- * usage: myapp -f <FILE> [-h] [-v]
- * Do something useful with an input file
- *
- * -f,--file <FILE> The file to be processed
- * -h,--help
- * -v,--version Print the version of the application
- *
- * Please report issues at http://example.com/issues
- *
- *
- * @version $Id: HelpFormatter.java 1677407 2015-05-03 14:31:12Z britter $
- */
-public class HelpFormatter {
- // --------------------------------------------------------------- Constants
-
- /** default number of characters per line */
- public static final int DEFAULT_WIDTH = 74;
-
- /** default padding to the left of each line */
- public static final int DEFAULT_LEFT_PAD = 1;
-
- /** number of space characters to be prefixed to each description line */
- public static final int DEFAULT_DESC_PAD = 3;
-
- /** the string to display at the beginning of the usage statement */
- public static final String DEFAULT_SYNTAX_PREFIX = "usage: ";
-
- /** default prefix for shortOpts */
- public static final String DEFAULT_OPT_PREFIX = "-";
-
- /** default prefix for long Option */
- public static final String DEFAULT_LONG_OPT_PREFIX = "--";
-
- /**
- * default separator displayed between a long Option and its value
- *
- * @since 1.3
- **/
- public static final String DEFAULT_LONG_OPT_SEPARATOR = " ";
-
- /** default name for an argument */
- public static final String DEFAULT_ARG_NAME = "arg";
-
- // -------------------------------------------------------------- Attributes
-
- /**
- * number of characters per line
- *
- * @deprecated Scope will be made private for next major version
- * - use get/setWidth methods instead.
- */
- @Deprecated
- public int defaultWidth = DEFAULT_WIDTH;
-
- /**
- * amount of padding to the left of each line
- *
- * @deprecated Scope will be made private for next major version
- * - use get/setLeftPadding methods instead.
- */
- @Deprecated
- public int defaultLeftPad = DEFAULT_LEFT_PAD;
-
- /**
- * the number of characters of padding to be prefixed
- * to each description line
- *
- * @deprecated Scope will be made private for next major version
- * - use get/setDescPadding methods instead.
- */
- @Deprecated
- public int defaultDescPad = DEFAULT_DESC_PAD;
-
- /**
- * the string to display at the beginning of the usage statement
- *
- * @deprecated Scope will be made private for next major version
- * - use get/setSyntaxPrefix methods instead.
- */
- @Deprecated
- public String defaultSyntaxPrefix = DEFAULT_SYNTAX_PREFIX;
-
- /**
- * the new line string
- *
- * @deprecated Scope will be made private for next major version
- * - use get/setNewLine methods instead.
- */
- @Deprecated
- public String defaultNewLine = System.getProperty("line.separator");
-
- /**
- * the shortOpt prefix
- *
- * @deprecated Scope will be made private for next major version
- * - use get/setOptPrefix methods instead.
- */
- @Deprecated
- public String defaultOptPrefix = DEFAULT_OPT_PREFIX;
-
- /**
- * the long Opt prefix
- *
- * @deprecated Scope will be made private for next major version
- * - use get/setLongOptPrefix methods instead.
- */
- @Deprecated
- public String defaultLongOptPrefix = DEFAULT_LONG_OPT_PREFIX;
-
- /**
- * the name of the argument
- *
- * @deprecated Scope will be made private for next major version
- * - use get/setArgName methods instead.
- */
- @Deprecated
- public String defaultArgName = DEFAULT_ARG_NAME;
-
- /**
- * Comparator used to sort the options when they output in help text
- *
- * Defaults to case-insensitive alphabetical sorting by option key
- */
- protected Comparator optionComparator = new OptionComparator();
-
- /** The separator displayed between the long option and its value. */
- private String longOptSeparator = DEFAULT_LONG_OPT_SEPARATOR;
-
- /**
- * Sets the 'width'.
- *
- * @param width the new value of 'width'
- */
- public void setWidth(int width) {
- this.defaultWidth = width;
- }
-
- /**
- * Returns the 'width'.
- *
- * @return the 'width'
- */
- public int getWidth() {
- return defaultWidth;
- }
-
- /**
- * Sets the 'leftPadding'.
- *
- * @param padding the new value of 'leftPadding'
- */
- public void setLeftPadding(int padding) {
- this.defaultLeftPad = padding;
- }
-
- /**
- * Returns the 'leftPadding'.
- *
- * @return the 'leftPadding'
- */
- public int getLeftPadding() {
- return defaultLeftPad;
- }
-
- /**
- * Sets the 'descPadding'.
- *
- * @param padding the new value of 'descPadding'
- */
- public void setDescPadding(int padding) {
- this.defaultDescPad = padding;
- }
-
- /**
- * Returns the 'descPadding'.
- *
- * @return the 'descPadding'
- */
- public int getDescPadding() {
- return defaultDescPad;
- }
-
- /**
- * Sets the 'syntaxPrefix'.
- *
- * @param prefix the new value of 'syntaxPrefix'
- */
- public void setSyntaxPrefix(String prefix) {
- this.defaultSyntaxPrefix = prefix;
- }
-
- /**
- * Returns the 'syntaxPrefix'.
- *
- * @return the 'syntaxPrefix'
- */
- public String getSyntaxPrefix() {
- return defaultSyntaxPrefix;
- }
-
- /**
- * Sets the 'newLine'.
- *
- * @param newline the new value of 'newLine'
- */
- public void setNewLine(String newline) {
- this.defaultNewLine = newline;
- }
-
- /**
- * Returns the 'newLine'.
- *
- * @return the 'newLine'
- */
- public String getNewLine() {
- return defaultNewLine;
- }
-
- /**
- * Sets the 'optPrefix'.
- *
- * @param prefix the new value of 'optPrefix'
- */
- public void setOptPrefix(String prefix) {
- this.defaultOptPrefix = prefix;
- }
-
- /**
- * Returns the 'optPrefix'.
- *
- * @return the 'optPrefix'
- */
- public String getOptPrefix() {
- return defaultOptPrefix;
- }
-
- /**
- * Sets the 'longOptPrefix'.
- *
- * @param prefix the new value of 'longOptPrefix'
- */
- public void setLongOptPrefix(String prefix) {
- this.defaultLongOptPrefix = prefix;
- }
-
- /**
- * Returns the 'longOptPrefix'.
- *
- * @return the 'longOptPrefix'
- */
- public String getLongOptPrefix() {
- return defaultLongOptPrefix;
- }
-
- /**
- * Set the separator displayed between a long option and its value.
- * Ensure that the separator specified is supported by the parser used,
- * typically ' ' or '='.
- *
- * @param longOptSeparator the separator, typically ' ' or '='.
- * @since 1.3
- */
- public void setLongOptSeparator(String longOptSeparator) {
- this.longOptSeparator = longOptSeparator;
- }
-
- /**
- * Returns the separator displayed between a long option and its value.
- *
- * @return the separator
- * @since 1.3
- */
- public String getLongOptSeparator() {
- return longOptSeparator;
- }
-
- /**
- * Sets the 'argName'.
- *
- * @param name the new value of 'argName'
- */
- public void setArgName(String name) {
- this.defaultArgName = name;
- }
-
- /**
- * Returns the 'argName'.
- *
- * @return the 'argName'
- */
- public String getArgName() {
- return defaultArgName;
- }
-
- /**
- * Comparator used to sort the options when they output in help text.
- * Defaults to case-insensitive alphabetical sorting by option key.
- *
- * @return the {@link Comparator} currently in use to sort the options
- * @since 1.2
- */
- public Comparator getOptionComparator() {
- return optionComparator;
- }
-
- /**
- * Set the comparator used to sort the options when they output in help text.
- * Passing in a null comparator will keep the options in the order they were declared.
- *
- * @param comparator the {@link Comparator} to use for sorting the options
- * @since 1.2
- */
- public void setOptionComparator(Comparator comparator) {
- this.optionComparator = comparator;
- }
-
- /**
- * Print the help for options
with the specified
- * command line syntax. This method prints help information to
- * System.out.
- *
- * @param cmdLineSyntax the syntax for this application
- * @param options the Options instance
- */
- public void printHelp(String cmdLineSyntax, Options options) {
- printHelp(getWidth(), cmdLineSyntax, null, options, null, false);
- }
-
- /**
- * Print the help for options
with the specified
- * command line syntax. This method prints help information to
- * System.out.
- *
- * @param cmdLineSyntax the syntax for this application
- * @param options the Options instance
- * @param autoUsage whether to print an automatically generated
- * usage statement
- */
- public void printHelp(String cmdLineSyntax, Options options, boolean autoUsage) {
- printHelp(getWidth(), cmdLineSyntax, null, options, null, autoUsage);
- }
-
- /**
- * Print the help for options
with the specified
- * command line syntax. This method prints help information to
- * System.out.
- *
- * @param cmdLineSyntax the syntax for this application
- * @param header the banner to display at the beginning of the help
- * @param options the Options instance
- * @param footer the banner to display at the end of the help
- */
- public void printHelp(String cmdLineSyntax, String header, Options options, String footer) {
- printHelp(cmdLineSyntax, header, options, footer, false);
- }
-
- /**
- * Print the help for options
with the specified
- * command line syntax. This method prints help information to
- * System.out.
- *
- * @param cmdLineSyntax the syntax for this application
- * @param header the banner to display at the beginning of the help
- * @param options the Options instance
- * @param footer the banner to display at the end of the help
- * @param autoUsage whether to print an automatically generated
- * usage statement
- */
- public void printHelp(String cmdLineSyntax, String header, Options options, String footer, boolean autoUsage) {
- printHelp(getWidth(), cmdLineSyntax, header, options, footer, autoUsage);
- }
-
- /**
- * Print the help for options
with the specified
- * command line syntax. This method prints help information to
- * System.out.
- *
- * @param width the number of characters to be displayed on each line
- * @param cmdLineSyntax the syntax for this application
- * @param header the banner to display at the beginning of the help
- * @param options the Options instance
- * @param footer the banner to display at the end of the help
- */
- public void printHelp(int width, String cmdLineSyntax, String header, Options options, String footer) {
- printHelp(width, cmdLineSyntax, header, options, footer, false);
- }
-
- /**
- * Print the help for options
with the specified
- * command line syntax. This method prints help information to
- * System.out.
- *
- * @param width the number of characters to be displayed on each line
- * @param cmdLineSyntax the syntax for this application
- * @param header the banner to display at the beginning of the help
- * @param options the Options instance
- * @param footer the banner to display at the end of the help
- * @param autoUsage whether to print an automatically generated
- * usage statement
- */
- public void printHelp(int width, String cmdLineSyntax, String header,
- Options options, String footer, boolean autoUsage) {
- PrintWriter pw = new PrintWriter(System.out);
-
- printHelp(pw, width, cmdLineSyntax, header, options, getLeftPadding(), getDescPadding(), footer, autoUsage);
- pw.flush();
- }
-
- /**
- * Print the help for options
with the specified
- * command line syntax.
- *
- * @param pw the writer to which the help will be written
- * @param width the number of characters to be displayed on each line
- * @param cmdLineSyntax the syntax for this application
- * @param header the banner to display at the beginning of the help
- * @param options the Options instance
- * @param leftPad the number of characters of padding to be prefixed
- * to each line
- * @param descPad the number of characters of padding to be prefixed
- * to each description line
- * @param footer the banner to display at the end of the help
- *
- * @throws IllegalStateException if there is no room to print a line
- */
- public void printHelp(PrintWriter pw, int width, String cmdLineSyntax,
- String header, Options options, int leftPad,
- int descPad, String footer) {
- printHelp(pw, width, cmdLineSyntax, header, options, leftPad, descPad, footer, false);
- }
-
-
- /**
- * Print the help for options
with the specified
- * command line syntax.
- *
- * @param pw the writer to which the help will be written
- * @param width the number of characters to be displayed on each line
- * @param cmdLineSyntax the syntax for this application
- * @param header the banner to display at the beginning of the help
- * @param options the Options instance
- * @param leftPad the number of characters of padding to be prefixed
- * to each line
- * @param descPad the number of characters of padding to be prefixed
- * to each description line
- * @param footer the banner to display at the end of the help
- * @param autoUsage whether to print an automatically generated
- * usage statement
- *
- * @throws IllegalStateException if there is no room to print a line
- */
- public void printHelp(PrintWriter pw, int width, String cmdLineSyntax,
- String header, Options options, int leftPad,
- int descPad, String footer, boolean autoUsage) {
- if (cmdLineSyntax == null || cmdLineSyntax.length() == 0) {
- throw new IllegalArgumentException("cmdLineSyntax not provided");
- }
-
- if (autoUsage) {
- printUsage(pw, width, cmdLineSyntax, options);
- } else {
- printUsage(pw, width, cmdLineSyntax);
- }
-
- if (header != null && header.trim().length() > 0) {
- printWrapped(pw, width, header);
- }
-
- printOptions(pw, width, options, leftPad, descPad);
-
- if (footer != null && footer.trim().length() > 0) {
- printWrapped(pw, width, footer);
- }
- }
-
- /**
- * Prints the usage statement for the specified application.
- *
- * @param pw The PrintWriter to print the usage statement
- * @param width The number of characters to display per line
- * @param app The application name
- * @param options The command line Options
- */
- public void printUsage(PrintWriter pw, int width, String app, Options options) {
- // initialise the string buffer
- StringBuffer buff = new StringBuffer(getSyntaxPrefix()).append(app).append(" ");
-
- // create a list for processed option groups
- Collection processedGroups = new ArrayList();
-
- List optList = new ArrayList (options.getOptions());
- if (getOptionComparator() != null) {
- Collections.sort(optList, getOptionComparator());
- }
- // iterate over the options
- for (Iterator it = optList.iterator(); it.hasNext(); ) {
- // get the next Option
- Option option = it.next();
-
- // check if the option is part of an OptionGroup
- OptionGroup group = options.getOptionGroup(option);
-
- // if the option is part of a group
- if (group != null) {
- // and if the group has not already been processed
- if (!processedGroups.contains(group)) {
- // add the group to the processed list
- processedGroups.add(group);
-
-
- // add the usage clause
- appendOptionGroup(buff, group);
- }
-
- // otherwise the option was displayed in the group
- // previously so ignore it.
- }
-
- // if the Option is not part of an OptionGroup
- else {
- appendOption(buff, option, option.isRequired());
- }
-
- if (it.hasNext()) {
- buff.append(" ");
- }
- }
-
-
- // call printWrapped
- printWrapped(pw, width, buff.toString().indexOf(' ') + 1, buff.toString());
- }
-
- /**
- * Appends the usage clause for an OptionGroup to a StringBuffer.
- * The clause is wrapped in square brackets if the group is required.
- * The display of the options is handled by appendOption
- * @param buff the StringBuffer to append to
- * @param group the group to append
- * @see #appendOption(StringBuffer, Option, boolean)
- */
- private void appendOptionGroup(StringBuffer buff, OptionGroup group) {
- if (!group.isRequired()) {
- buff.append("[");
- }
-
- List optList = new ArrayList (group.getOptions());
- if (getOptionComparator() != null) {
- Collections.sort(optList, getOptionComparator());
- }
- // for each option in the OptionGroup
- for (Iterator it = optList.iterator(); it.hasNext(); ) {
- // whether the option is required or not is handled at group level
- appendOption(buff, it.next(), true);
-
- if (it.hasNext()) {
- buff.append(" | ");
- }
- }
-
- if (!group.isRequired()) {
- buff.append("]");
- }
- }
-
- /**
- * Appends the usage clause for an Option to a StringBuffer.
- *
- * @param buff the StringBuffer to append to
- * @param option the Option to append
- * @param required whether the Option is required or not
- */
- private void appendOption(StringBuffer buff, Option option, boolean required) {
- if (!required) {
- buff.append("[");
- }
-
- if (option.getOpt() != null) {
- buff.append("-").append(option.getOpt());
- } else {
- buff.append("--").append(option.getLongOpt());
- }
-
- // if the Option has a value and a non blank argname
- if (option.hasArg() && (option.getArgName() == null || option.getArgName().length() != 0)) {
- buff.append(option.getOpt() == null ? longOptSeparator : " ");
- buff.append("<").append(option.getArgName() != null ? option.getArgName() : getArgName()).append(">");
- }
-
- // if the Option is not a required option
- if (!required) {
- buff.append("]");
- }
- }
-
- /**
- * Print the cmdLineSyntax to the specified writer, using the
- * specified width.
- *
- * @param pw The printWriter to write the help to
- * @param width The number of characters per line for the usage statement.
- * @param cmdLineSyntax The usage statement.
- */
- public void printUsage(PrintWriter pw, int width, String cmdLineSyntax) {
- int argPos = cmdLineSyntax.indexOf(' ') + 1;
-
- printWrapped(pw, width, getSyntaxPrefix().length() + argPos, getSyntaxPrefix() + cmdLineSyntax);
- }
-
- /**
- * Print the help for the specified Options to the specified writer,
- * using the specified width, left padding and description padding.
- *
- * @param pw The printWriter to write the help to
- * @param width The number of characters to display per line
- * @param options The command line Options
- * @param leftPad the number of characters of padding to be prefixed
- * to each line
- * @param descPad the number of characters of padding to be prefixed
- * to each description line
- */
- public void printOptions(PrintWriter pw, int width, Options options,
- int leftPad, int descPad) {
- StringBuffer sb = new StringBuffer();
-
- renderOptions(sb, width, options, leftPad, descPad);
- pw.println(sb.toString());
- }
-
- /**
- * Print the specified text to the specified PrintWriter.
- *
- * @param pw The printWriter to write the help to
- * @param width The number of characters to display per line
- * @param text The text to be written to the PrintWriter
- */
- public void printWrapped(PrintWriter pw, int width, String text) {
- printWrapped(pw, width, 0, text);
- }
-
- /**
- * Print the specified text to the specified PrintWriter.
- *
- * @param pw The printWriter to write the help to
- * @param width The number of characters to display per line
- * @param nextLineTabStop The position on the next line for the first tab.
- * @param text The text to be written to the PrintWriter
- */
- public void printWrapped(PrintWriter pw, int width, int nextLineTabStop, String text) {
- StringBuffer sb = new StringBuffer(text.length());
-
- renderWrappedTextBlock(sb, width, nextLineTabStop, text);
- pw.println(sb.toString());
- }
-
- // --------------------------------------------------------------- Protected
-
- /**
- * Render the specified Options and return the rendered Options
- * in a StringBuffer.
- *
- * @param sb The StringBuffer to place the rendered Options into.
- * @param width The number of characters to display per line
- * @param options The command line Options
- * @param leftPad the number of characters of padding to be prefixed
- * to each line
- * @param descPad the number of characters of padding to be prefixed
- * to each description line
- *
- * @return the StringBuffer with the rendered Options contents.
- */
- protected StringBuffer renderOptions(StringBuffer sb, int width, Options options, int leftPad, int descPad) {
- final String lpad = createPadding(leftPad);
- final String dpad = createPadding(descPad);
-
- // first create list containing only -a,--aaa where
- // -a is opt and --aaa is long opt; in parallel look for
- // the longest opt string this list will be then used to
- // sort options ascending
- int max = 0;
- List prefixList = new ArrayList();
-
- List optList = options.helpOptions();
-
- if (getOptionComparator() != null) {
- Collections.sort(optList, getOptionComparator());
- }
-
- for (Option option : optList) {
- StringBuffer optBuf = new StringBuffer();
-
- if (option.getOpt() == null) {
- optBuf.append(lpad).append(" ").append(getLongOptPrefix()).append(option.getLongOpt());
- } else {
- optBuf.append(lpad).append(getOptPrefix()).append(option.getOpt());
-
- if (option.hasLongOpt()) {
- optBuf.append(',').append(getLongOptPrefix()).append(option.getLongOpt());
- }
- }
-
- if (option.hasArg()) {
- String argName = option.getArgName();
- if (argName != null && argName.length() == 0) {
- // if the option has a blank argname
- optBuf.append(' ');
- } else {
- optBuf.append(option.hasLongOpt() ? longOptSeparator : " ");
- optBuf.append("<").append(argName != null ? option.getArgName() : getArgName()).append(">");
- }
- }
-
- prefixList.add(optBuf);
- max = optBuf.length() > max ? optBuf.length() : max;
- }
-
- int x = 0;
-
- for (Iterator it = optList.iterator(); it.hasNext(); ) {
- Option option = it.next();
- StringBuilder optBuf = new StringBuilder(prefixList.get(x++).toString());
-
- if (optBuf.length() < max) {
- optBuf.append(createPadding(max - optBuf.length()));
- }
-
- optBuf.append(dpad);
-
- int nextLineTabStop = max + descPad;
-
- if (option.getDescription() != null) {
- optBuf.append(option.getDescription());
- }
-
- renderWrappedText(sb, width, nextLineTabStop, optBuf.toString());
-
- if (it.hasNext()) {
- sb.append(getNewLine());
- }
- }
-
- return sb;
- }
-
- /**
- * Render the specified text and return the rendered Options
- * in a StringBuffer.
- *
- * @param sb The StringBuffer to place the rendered text into.
- * @param width The number of characters to display per line
- * @param nextLineTabStop The position on the next line for the first tab.
- * @param text The text to be rendered.
- *
- * @return the StringBuffer with the rendered Options contents.
- */
- protected StringBuffer renderWrappedText(StringBuffer sb, int width,
- int nextLineTabStop, String text) {
- int pos = findWrapPos(text, width, 0);
-
- if (pos == -1) {
- sb.append(rtrim(text));
-
- return sb;
- }
- sb.append(rtrim(text.substring(0, pos))).append(getNewLine());
-
- if (nextLineTabStop >= width) {
- // stops infinite loop happening
- nextLineTabStop = 1;
- }
-
- // all following lines must be padded with nextLineTabStop space characters
- final String padding = createPadding(nextLineTabStop);
-
- while (true) {
- text = padding + text.substring(pos).trim();
- pos = findWrapPos(text, width, 0);
-
- if (pos == -1) {
- sb.append(text);
-
- return sb;
- }
-
- if (text.length() > width && pos == nextLineTabStop - 1) {
- pos = width;
- }
-
- sb.append(rtrim(text.substring(0, pos))).append(getNewLine());
- }
- }
-
- /**
- * Render the specified text width a maximum width. This method differs
- * from renderWrappedText by not removing leading spaces after a new line.
- *
- * @param sb The StringBuffer to place the rendered text into.
- * @param width The number of characters to display per line
- * @param nextLineTabStop The position on the next line for the first tab.
- * @param text The text to be rendered.
- */
- private Appendable renderWrappedTextBlock(StringBuffer sb, int width, int nextLineTabStop, String text) {
- try {
- BufferedReader in = new BufferedReader(new StringReader(text));
- String line;
- boolean firstLine = true;
- while ((line = in.readLine()) != null) {
- if (!firstLine) {
- sb.append(getNewLine());
- } else {
- firstLine = false;
- }
- renderWrappedText(sb, width, nextLineTabStop, line);
- }
- } catch (IOException e) //NOPMD
- {
- // cannot happen
- }
-
- return sb;
- }
-
- /**
- * Finds the next text wrap position after startPos
for the
- * text in text
with the column width width
.
- * The wrap point is the last position before startPos+width having a
- * whitespace character (space, \n, \r). If there is no whitespace character
- * before startPos+width, it will return startPos+width.
- *
- * @param text The text being searched for the wrap position
- * @param width width of the wrapped text
- * @param startPos position from which to start the lookup whitespace
- * character
- * @return position on which the text must be wrapped or -1 if the wrap
- * position is at the end of the text
- */
- protected int findWrapPos(String text, int width, int startPos) {
- // the line ends before the max wrap pos or a new line char found
- int pos = text.indexOf('\n', startPos);
- if (pos != -1 && pos <= width) {
- return pos + 1;
- }
-
- pos = text.indexOf('\t', startPos);
- if (pos != -1 && pos <= width) {
- return pos + 1;
- }
-
- if (startPos + width >= text.length()) {
- return -1;
- }
-
- // look for the last whitespace character before startPos+width
- for (pos = startPos + width; pos >= startPos; --pos) {
- final char c = text.charAt(pos);
- if (c == ' ' || c == '\n' || c == '\r') {
- break;
- }
- }
-
- // if we found it - just return
- if (pos > startPos) {
- return pos;
- }
-
- // if we didn't find one, simply chop at startPos+width
- pos = startPos + width;
-
- return pos == text.length() ? -1 : pos;
- }
-
- /**
- * Return a String of padding of length len
.
- *
- * @param len The length of the String of padding to create.
- *
- * @return The String of padding
- */
- protected String createPadding(int len) {
- char[] padding = new char[len];
- Arrays.fill(padding, ' ');
-
- return new String(padding);
- }
-
- /**
- * Remove the trailing whitespace from the specified String.
- *
- * @param s The String to remove the trailing padding from.
- *
- * @return The String of without the trailing padding
- */
- protected String rtrim(String s) {
- if (s == null || s.length() == 0) {
- return s;
- }
-
- int pos = s.length();
-
- while (pos > 0 && Character.isWhitespace(s.charAt(pos - 1))) {
- --pos;
- }
-
- return s.substring(0, pos);
- }
-
- // ------------------------------------------------------ Package protected
- // ---------------------------------------------------------------- Private
- // ---------------------------------------------------------- Inner classes
-
- /**
- * This class implements the Comparator
interface
- * for comparing Options.
- */
- private static class OptionComparator implements Comparator , Serializable {
- /** The serial version UID. */
- private static final long serialVersionUID = 5305467873966684014L;
-
- /**
- * Compares its two arguments for order. Returns a negative
- * integer, zero, or a positive integer as the first argument
- * is less than, equal to, or greater than the second.
- *
- * @param opt1 The first Option to be compared.
- * @param opt2 The second Option to be compared.
- * @return a negative integer, zero, or a positive integer as
- * the first argument is less than, equal to, or greater than the
- * second.
- */
- public int compare(Option opt1, Option opt2) {
- return opt1.getKey().compareToIgnoreCase(opt2.getKey());
- }
- }
-}
diff --git a/src/org/apache/commons/cli/MissingArgumentException.java b/src/org/apache/commons/cli/MissingArgumentException.java
deleted file mode 100644
index 2d7d72f2..00000000
--- a/src/org/apache/commons/cli/MissingArgumentException.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-/**
- * Thrown when an option requiring an argument
- * is not provided with an argument.
- *
- * @version $Id: MissingArgumentException.java 1443102 2013-02-06 18:12:16Z tn $
- */
-public class MissingArgumentException extends ParseException {
- /**
- * This exception {@code serialVersionUID}.
- */
- private static final long serialVersionUID = -7098538588704965017L;
-
- /** The option requiring additional arguments */
- private Option option;
-
- /**
- * Construct a new MissingArgumentException
- * with the specified detail message.
- *
- * @param message the detail message
- */
- public MissingArgumentException(String message) {
- super(message);
- }
-
- /**
- * Construct a new MissingArgumentException
- * with the specified detail message.
- *
- * @param option the option requiring an argument
- * @since 1.2
- */
- public MissingArgumentException(Option option) {
- this("Missing argument for option: " + option.getKey());
- this.option = option;
- }
-
- /**
- * Return the option requiring an argument that wasn't provided
- * on the command line.
- *
- * @return the related option
- * @since 1.2
- */
- public Option getOption() {
- return option;
- }
-}
diff --git a/src/org/apache/commons/cli/MissingOptionException.java b/src/org/apache/commons/cli/MissingOptionException.java
deleted file mode 100644
index 1fad95cd..00000000
--- a/src/org/apache/commons/cli/MissingOptionException.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.util.List;
-import java.util.Iterator;
-
-/**
- * Thrown when a required option has not been provided.
- *
- * @version $Id: MissingOptionException.java 1443102 2013-02-06 18:12:16Z tn $
- */
-public class MissingOptionException extends ParseException {
- /** This exception {@code serialVersionUID}. */
- private static final long serialVersionUID = 8161889051578563249L;
-
- /** The list of missing options and groups */
- private List missingOptions;
-
- /**
- * Construct a new MissingSelectedException
- * with the specified detail message.
- *
- * @param message the detail message
- */
- public MissingOptionException(String message) {
- super(message);
- }
-
- /**
- * Constructs a new MissingSelectedException
with the
- * specified list of missing options.
- *
- * @param missingOptions the list of missing options and groups
- * @since 1.2
- */
- public MissingOptionException(List missingOptions) {
- this(createMessage(missingOptions));
- this.missingOptions = missingOptions;
- }
-
- /**
- * Returns the list of options or option groups missing in the command line parsed.
- *
- * @return the missing options, consisting of String instances for simple
- * options, and OptionGroup instances for required option groups.
- * @since 1.2
- */
- public List getMissingOptions() {
- return missingOptions;
- }
-
- /**
- * Build the exception message from the specified list of options.
- *
- * @param missingOptions the list of missing options and groups
- * @since 1.2
- */
- private static String createMessage(List> missingOptions) {
- StringBuilder buf = new StringBuilder("Missing required option");
- buf.append(missingOptions.size() == 1 ? "" : "s");
- buf.append(": ");
-
- Iterator> it = missingOptions.iterator();
- while (it.hasNext()) {
- buf.append(it.next());
- if (it.hasNext()) {
- buf.append(", ");
- }
- }
-
- return buf.toString();
- }
-}
diff --git a/src/org/apache/commons/cli/Option.java b/src/org/apache/commons/cli/Option.java
deleted file mode 100644
index 2a34d88b..00000000
--- a/src/org/apache/commons/cli/Option.java
+++ /dev/null
@@ -1,920 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Describes a single command-line option. It maintains
- * information regarding the short-name of the option, the long-name,
- * if any exists, a flag indicating if an argument is required for
- * this option, and a self-documenting description of the option.
- *
- * An Option is not created independently, but is created through
- * an instance of {@link Options}. An Option is required to have
- * at least a short or a long-name.
- *
- * Note: once an {@link Option} has been added to an instance
- * of {@link Options}, it's required flag may not be changed anymore.
- *
- * @see org.apache.commons.cli.Options
- * @see org.apache.commons.cli.CommandLine
- *
- * @version $Id: Option.java 1677406 2015-05-03 14:27:31Z britter $
- */
-public class Option implements Cloneable, Serializable {
- /** constant that specifies the number of argument values has not been specified */
- public static final int UNINITIALIZED = -1;
-
- /** constant that specifies the number of argument values is infinite */
- public static final int UNLIMITED_VALUES = -2;
-
- /** The serial version UID. */
- private static final long serialVersionUID = 1L;
-
- /** the name of the option */
- private final String opt;
-
- /** the long representation of the option */
- private String longOpt;
-
- /** the name of the argument for this option */
- private String argName;
-
- /** description of the option */
- private String description;
-
- /** specifies whether this option is required to be present */
- private boolean required;
-
- /** specifies whether the argument value of this Option is optional */
- private boolean optionalArg;
-
- /** the number of argument values this option can have */
- private int numberOfArgs = UNINITIALIZED;
-
- /** the type of this Option */
- private Class> type = String.class;
-
- /** the list of argument values **/
- private List values = new ArrayList();
-
- /** the character that is the value separator */
- private char valuesep;
-
- /**
- * Private constructor used by the nested Builder class.
- *
- * @param builder builder used to create this option
- */
- private Option(final Builder builder) {
- this.argName = builder.argName;
- this.description = builder.description;
- this.longOpt = builder.longOpt;
- this.numberOfArgs = builder.numberOfArgs;
- this.opt = builder.opt;
- this.optionalArg = builder.optionalArg;
- this.required = builder.required;
- this.type = builder.type;
- this.valuesep = builder.valuesep;
- }
-
- /**
- * Creates an Option using the specified parameters.
- * The option does not take an argument.
- *
- * @param opt short representation of the option
- * @param description describes the function of the option
- *
- * @throws IllegalArgumentException if there are any non valid
- * Option characters in opt
.
- */
- public Option(String opt, String description) throws IllegalArgumentException {
- this(opt, null, false, description);
- }
-
- /**
- * Creates an Option using the specified parameters.
- *
- * @param opt short representation of the option
- * @param hasArg specifies whether the Option takes an argument or not
- * @param description describes the function of the option
- *
- * @throws IllegalArgumentException if there are any non valid
- * Option characters in opt
.
- */
- public Option(String opt, boolean hasArg, String description) throws IllegalArgumentException {
- this(opt, null, hasArg, description);
- }
-
- /**
- * Creates an Option using the specified parameters.
- *
- * @param opt short representation of the option
- * @param longOpt the long representation of the option
- * @param hasArg specifies whether the Option takes an argument or not
- * @param description describes the function of the option
- *
- * @throws IllegalArgumentException if there are any non valid
- * Option characters in opt
.
- */
- public Option(String opt, String longOpt, boolean hasArg, String description)
- throws IllegalArgumentException {
- // ensure that the option is valid
- OptionValidator.validateOption(opt);
-
- this.opt = opt;
- this.longOpt = longOpt;
-
- // if hasArg is set then the number of arguments is 1
- if (hasArg) {
- this.numberOfArgs = 1;
- }
-
- this.description = description;
- }
-
- /**
- * Returns the id of this Option. This is only set when the
- * Option shortOpt is a single character. This is used for switch
- * statements.
- *
- * @return the id of this Option
- */
- public int getId() {
- return getKey().charAt(0);
- }
-
- /**
- * Returns the 'unique' Option identifier.
- *
- * @return the 'unique' Option identifier
- */
- String getKey() {
- // if 'opt' is null, then it is a 'long' option
- return (opt == null) ? longOpt : opt;
- }
-
- /**
- * Retrieve the name of this Option.
- *
- * It is this String which can be used with
- * {@link CommandLine#hasOption(String opt)} and
- * {@link CommandLine#getOptionValue(String opt)} to check
- * for existence and argument.
- *
- * @return The name of this option
- */
- public String getOpt() {
- return opt;
- }
-
- /**
- * Retrieve the type of this Option.
- *
- * @return The type of this option
- */
- public Object getType() {
- return type;
- }
-
- /**
- * Sets the type of this Option.
- *
- * Note: this method is kept for binary compatibility and the
- * input type is supposed to be a {@link Class} object.
- *
- * @param type the type of this Option
- * @deprecated since 1.3, use {@link #setType(Class)} instead
- */
- @Deprecated
- public void setType(Object type) {
- setType((Class>) type);
- }
-
- /**
- * Sets the type of this Option.
- *
- * @param type the type of this Option
- * @since 1.3
- */
- public void setType(Class> type) {
- this.type = type;
- }
-
- /**
- * Retrieve the long name of this Option.
- *
- * @return Long name of this option, or null, if there is no long name
- */
- public String getLongOpt() {
- return longOpt;
- }
-
- /**
- * Sets the long name of this Option.
- *
- * @param longOpt the long name of this Option
- */
- public void setLongOpt(String longOpt) {
- this.longOpt = longOpt;
- }
-
- /**
- * Sets whether this Option can have an optional argument.
- *
- * @param optionalArg specifies whether the Option can have
- * an optional argument.
- */
- public void setOptionalArg(boolean optionalArg) {
- this.optionalArg = optionalArg;
- }
-
- /**
- * @return whether this Option can have an optional argument
- */
- public boolean hasOptionalArg() {
- return optionalArg;
- }
-
- /**
- * Query to see if this Option has a long name
- *
- * @return boolean flag indicating existence of a long name
- */
- public boolean hasLongOpt() {
- return longOpt != null;
- }
-
- /**
- * Query to see if this Option requires an argument
- *
- * @return boolean flag indicating if an argument is required
- */
- public boolean hasArg() {
- return numberOfArgs > 0 || numberOfArgs == UNLIMITED_VALUES;
- }
-
- /**
- * Retrieve the self-documenting description of this Option
- *
- * @return The string description of this option
- */
- public String getDescription() {
- return description;
- }
-
- /**
- * Sets the self-documenting description of this Option
- *
- * @param description The description of this option
- * @since 1.1
- */
- public void setDescription(String description) {
- this.description = description;
- }
-
- /**
- * Query to see if this Option is mandatory
- *
- * @return boolean flag indicating whether this Option is mandatory
- */
- public boolean isRequired() {
- return required;
- }
-
- /**
- * Sets whether this Option is mandatory.
- *
- * @param required specifies whether this Option is mandatory
- */
- public void setRequired(boolean required) {
- this.required = required;
- }
-
- /**
- * Sets the display name for the argument value.
- *
- * @param argName the display name for the argument value.
- */
- public void setArgName(String argName) {
- this.argName = argName;
- }
-
- /**
- * Gets the display name for the argument value.
- *
- * @return the display name for the argument value.
- */
- public String getArgName() {
- return argName;
- }
-
- /**
- * Returns whether the display name for the argument value has been set.
- *
- * @return if the display name for the argument value has been set.
- */
- public boolean hasArgName() {
- return argName != null && argName.length() > 0;
- }
-
- /**
- * Query to see if this Option can take many values.
- *
- * @return boolean flag indicating if multiple values are allowed
- */
- public boolean hasArgs() {
- return numberOfArgs > 1 || numberOfArgs == UNLIMITED_VALUES;
- }
-
- /**
- * Sets the number of argument values this Option can take.
- *
- * @param num the number of argument values
- */
- public void setArgs(int num) {
- this.numberOfArgs = num;
- }
-
- /**
- * Sets the value separator. For example if the argument value
- * was a Java property, the value separator would be '='.
- *
- * @param sep The value separator.
- */
- public void setValueSeparator(char sep) {
- this.valuesep = sep;
- }
-
- /**
- * Returns the value separator character.
- *
- * @return the value separator character.
- */
- public char getValueSeparator() {
- return valuesep;
- }
-
- /**
- * Return whether this Option has specified a value separator.
- *
- * @return whether this Option has specified a value separator.
- * @since 1.1
- */
- public boolean hasValueSeparator() {
- return valuesep > 0;
- }
-
- /**
- * Returns the number of argument values this Option can take.
- *
- * @return num the number of argument values
- */
- public int getArgs() {
- return numberOfArgs;
- }
-
- /**
- * Adds the specified value to this Option.
- *
- * @param value is a/the value of this Option
- */
- void addValueForProcessing(String value) {
- if (numberOfArgs == UNINITIALIZED) {
- throw new RuntimeException("NO_ARGS_ALLOWED");
- }
- processValue(value);
- }
-
- /**
- * Processes the value. If this Option has a value separator
- * the value will have to be parsed into individual tokens. When
- * n-1 tokens have been processed and there are more value separators
- * in the value, parsing is ceased and the remaining characters are
- * added as a single token.
- *
- * @param value The String to be processed.
- *
- * @since 1.0.1
- */
- private void processValue(String value) {
- // this Option has a separator character
- if (hasValueSeparator()) {
- // get the separator character
- char sep = getValueSeparator();
-
- // store the index for the value separator
- int index = value.indexOf(sep);
-
- // while there are more value separators
- while (index != -1) {
- // next value to be added
- if (values.size() == numberOfArgs - 1) {
- break;
- }
-
- // store
- add(value.substring(0, index));
-
- // parse
- value = value.substring(index + 1);
-
- // get new index
- index = value.indexOf(sep);
- }
- }
-
- // store the actual value or the last value that has been parsed
- add(value);
- }
-
- /**
- * Add the value to this Option. If the number of arguments
- * is greater than zero and there is enough space in the list then
- * add the value. Otherwise, throw a runtime exception.
- *
- * @param value The value to be added to this Option
- *
- * @since 1.0.1
- */
- private void add(String value) {
- if (!acceptsArg()) {
- throw new RuntimeException("Cannot add value, list full.");
- }
-
- // store value
- values.add(value);
- }
-
- /**
- * Returns the specified value of this Option or
- * null
if there is no value.
- *
- * @return the value/first value of this Option or
- * null
if there is no value.
- */
- public String getValue() {
- return hasNoValues() ? null : values.get(0);
- }
-
- /**
- * Returns the specified value of this Option or
- * null
if there is no value.
- *
- * @param index The index of the value to be returned.
- *
- * @return the specified value of this Option or
- * null
if there is no value.
- *
- * @throws IndexOutOfBoundsException if index is less than 1
- * or greater than the number of the values for this Option.
- */
- public String getValue(int index) throws IndexOutOfBoundsException {
- return hasNoValues() ? null : values.get(index);
- }
-
- /**
- * Returns the value/first value of this Option or the
- * defaultValue
if there is no value.
- *
- * @param defaultValue The value to be returned if there
- * is no value.
- *
- * @return the value/first value of this Option or the
- * defaultValue
if there are no values.
- */
- public String getValue(String defaultValue) {
- String value = getValue();
-
- return (value != null) ? value : defaultValue;
- }
-
- /**
- * Return the values of this Option as a String array
- * or null if there are no values
- *
- * @return the values of this Option as a String array
- * or null if there are no values
- */
- public String[] getValues() {
- return hasNoValues() ? null : values.toArray(new String[values.size()]);
- }
-
- /**
- * @return the values of this Option as a List
- * or null if there are no values
- */
- public List getValuesList() {
- return values;
- }
-
- /**
- * Dump state, suitable for debugging.
- *
- * @return Stringified form of this object
- */
- @Override
- public String toString() {
- StringBuilder buf = new StringBuilder().append("[ option: ");
-
- buf.append(opt);
-
- if (longOpt != null) {
- buf.append(" ").append(longOpt);
- }
-
- buf.append(" ");
-
- if (hasArgs()) {
- buf.append("[ARG...]");
- } else if (hasArg()) {
- buf.append(" [ARG]");
- }
-
- buf.append(" :: ").append(description);
-
- if (type != null) {
- buf.append(" :: ").append(type);
- }
-
- buf.append(" ]");
-
- return buf.toString();
- }
-
- /**
- * Returns whether this Option has any values.
- *
- * @return whether this Option has any values.
- */
- private boolean hasNoValues() {
- return values.isEmpty();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- Option option = (Option) o;
-
-
- if (opt != null ? !opt.equals(option.opt) : option.opt != null) {
- return false;
- }
- if (longOpt != null ? !longOpt.equals(option.longOpt) : option.longOpt != null) {
- return false;
- }
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result;
- result = opt != null ? opt.hashCode() : 0;
- result = 31 * result + (longOpt != null ? longOpt.hashCode() : 0);
- return result;
- }
-
- /**
- * A rather odd clone method - due to incorrect code in 1.0 it is public
- * and in 1.1 rather than throwing a CloneNotSupportedException it throws
- * a RuntimeException so as to maintain backwards compat at the API level.
- *
- * After calling this method, it is very likely you will want to call
- * clearValues().
- *
- * @return a clone of this Option instance
- * @throws RuntimeException if a {@link CloneNotSupportedException} has been thrown
- * by {@code super.clone()}
- */
- @Override
- public Object clone() {
- try {
- Option option = (Option) super.clone();
- option.values = new ArrayList(values);
- return option;
- } catch (CloneNotSupportedException cnse) {
- throw new RuntimeException("A CloneNotSupportedException was thrown: " + cnse.getMessage());
- }
- }
-
- /**
- * Clear the Option values. After a parse is complete, these are left with
- * data in them and they need clearing if another parse is done.
- *
- * See: CLI-71
- */
- void clearValues() {
- values.clear();
- }
-
- /**
- * This method is not intended to be used. It was a piece of internal
- * API that was made public in 1.0. It currently throws an UnsupportedOperationException.
- *
- * @param value the value to add
- * @return always throws an {@link UnsupportedOperationException}
- * @throws UnsupportedOperationException always
- * @deprecated
- */
- @Deprecated
- public boolean addValue(String value) {
- throw new UnsupportedOperationException("The addValue method is not intended for client use. "
- + "Subclasses should use the addValueForProcessing method instead. ");
- }
-
- /**
- * Tells if the option can accept more arguments.
- *
- * @return false if the maximum number of arguments is reached
- * @since 1.3
- */
- boolean acceptsArg() {
- return (hasArg() || hasArgs() || hasOptionalArg()) && (numberOfArgs <= 0 || values.size() < numberOfArgs);
- }
-
- /**
- * Tells if the option requires more arguments to be valid.
- *
- * @return false if the option doesn't require more arguments
- * @since 1.3
- */
- boolean requiresArg() {
- if (optionalArg) {
- return false;
- }
- if (numberOfArgs == UNLIMITED_VALUES) {
- return values.isEmpty();
- }
- return acceptsArg();
- }
-
- /**
- * Returns a {@link Builder} to create an {@link Option} using descriptive
- * methods.
- *
- * @return a new {@link Builder} instance
- * @since 1.3
- */
- public static Builder builder() {
- return builder(null);
- }
-
- /**
- * Returns a {@link Builder} to create an {@link Option} using descriptive
- * methods.
- *
- * @param opt short representation of the option
- * @return a new {@link Builder} instance
- * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}
- * @since 1.3
- */
- public static Builder builder(final String opt) {
- return new Builder(opt);
- }
-
- /**
- * A nested builder class to create Option
instances
- * using descriptive methods.
- *
- * Example usage:
- *
- * Option option = Option.builder("a")
- * .required(true)
- * .longOpt("arg-name")
- * .build();
- *
- *
- * @since 1.3
- */
- public static final class Builder {
- /** the name of the option */
- private final String opt;
-
- /** description of the option */
- private String description;
-
- /** the long representation of the option */
- private String longOpt;
-
- /** the name of the argument for this option */
- private String argName;
-
- /** specifies whether this option is required to be present */
- private boolean required;
-
- /** specifies whether the argument value of this Option is optional */
- private boolean optionalArg;
-
- /** the number of argument values this option can have */
- private int numberOfArgs = UNINITIALIZED;
-
- /** the type of this Option */
- private Class> type = String.class;
-
- /** the character that is the value separator */
- private char valuesep;
-
- /**
- * Constructs a new Builder
with the minimum
- * required parameters for an Option
instance.
- *
- * @param opt short representation of the option
- * @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}
- */
- private Builder(final String opt) throws IllegalArgumentException {
- OptionValidator.validateOption(opt);
- this.opt = opt;
- }
-
- /**
- * Sets the display name for the argument value.
- *
- * @param argName the display name for the argument value.
- * @return this builder, to allow method chaining
- */
- public Builder argName(final String argName) {
- this.argName = argName;
- return this;
- }
-
- /**
- * Sets the description for this option.
- *
- * @param description the description of the option.
- * @return this builder, to allow method chaining
- */
- public Builder desc(final String description) {
- this.description = description;
- return this;
- }
-
- /**
- * Sets the long name of the Option.
- *
- * @param longOpt the long name of the Option
- * @return this builder, to allow method chaining
- */
- public Builder longOpt(final String longOpt) {
- this.longOpt = longOpt;
- return this;
- }
-
- /**
- * Sets the number of argument values the Option can take.
- *
- * @param numberOfArgs the number of argument values
- * @return this builder, to allow method chaining
- */
- public Builder numberOfArgs(final int numberOfArgs) {
- this.numberOfArgs = numberOfArgs;
- return this;
- }
-
- /**
- * Sets whether the Option can have an optional argument.
- *
- * @param isOptional specifies whether the Option can have
- * an optional argument.
- * @return this builder, to allow method chaining
- */
- public Builder optionalArg(final boolean isOptional) {
- this.optionalArg = isOptional;
- return this;
- }
-
- /**
- * Marks this Option as required.
- *
- * @return this builder, to allow method chaining
- */
- public Builder required() {
- return required(true);
- }
-
- /**
- * Sets whether the Option is mandatory.
- *
- * @param required specifies whether the Option is mandatory
- * @return this builder, to allow method chaining
- */
- public Builder required(final boolean required) {
- this.required = required;
- return this;
- }
-
- /**
- * Sets the type of the Option.
- *
- * @param type the type of the Option
- * @return this builder, to allow method chaining
- */
- public Builder type(final Class> type) {
- this.type = type;
- return this;
- }
-
- /**
- * The Option will use '=' as a means to separate argument value.
- *
- * @return this builder, to allow method chaining
- */
- public Builder valueSeparator() {
- return valueSeparator('=');
- }
-
- /**
- * The Option will use sep
as a means to
- * separate argument values.
- *
- * Example:
- *
- * Option opt = Option.builder("D").hasArgs()
- * .valueSeparator('=')
- * .build();
- * Options options = new Options();
- * options.addOption(opt);
- * String[] args = {"-Dkey=value"};
- * CommandLineParser parser = new DefaultParser();
- * CommandLine line = parser.parse(options, args);
- * String propertyName = line.getOptionValues("D")[0]; // will be "key"
- * String propertyValue = line.getOptionValues("D")[1]; // will be "value"
- *
- *
- * @param sep The value separator.
- * @return this builder, to allow method chaining
- */
- public Builder valueSeparator(final char sep) {
- valuesep = sep;
- return this;
- }
-
- /**
- * Indicates that the Option will require an argument.
- *
- * @return this builder, to allow method chaining
- */
- public Builder hasArg() {
- return hasArg(true);
- }
-
- /**
- * Indicates if the Option has an argument or not.
- *
- * @param hasArg specifies whether the Option takes an argument or not
- * @return this builder, to allow method chaining
- */
- public Builder hasArg(final boolean hasArg) {
- // set to UNINITIALIZED when no arg is specified to be compatible with OptionBuilder
- numberOfArgs = hasArg ? 1 : Option.UNINITIALIZED;
- return this;
- }
-
- /**
- * Indicates that the Option can have unlimited argument values.
- *
- * @return this builder, to allow method chaining
- */
- public Builder hasArgs() {
- numberOfArgs = Option.UNLIMITED_VALUES;
- return this;
- }
-
- /**
- * Constructs an Option with the values declared by this {@link Builder}.
- *
- * @return the new {@link Option}
- * @throws IllegalArgumentException if neither {@code opt} or {@code longOpt} has been set
- */
- public Option build() {
- if (opt == null && longOpt == null) {
- throw new IllegalArgumentException("Either opt or longOpt must be specified");
- }
- return new Option(this);
- }
- }
-}
diff --git a/src/org/apache/commons/cli/OptionBuilder.java b/src/org/apache/commons/cli/OptionBuilder.java
deleted file mode 100644
index d19b3ced..00000000
--- a/src/org/apache/commons/cli/OptionBuilder.java
+++ /dev/null
@@ -1,369 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-/**
- * OptionBuilder allows the user to create Options using descriptive methods.
- *
- * Details on the Builder pattern can be found at
- * http://c2.com/cgi-bin/wiki?BuilderPattern .
- *
- * This class is NOT thread safe. See CLI-209
- *
- * @version $Id: OptionBuilder.java 1677400 2015-05-03 13:46:08Z britter $
- * @since 1.0
- * @deprecated since 1.3, use {@link Option#builder(String)} instead
- */
-@Deprecated
-public final class OptionBuilder {
- /** long option */
- private static String longopt;
-
- /** option description */
- private static String description;
-
- /** argument name */
- private static String argName;
-
- /** is required? */
- private static boolean required;
-
- /** the number of arguments */
- private static int numberOfArgs = Option.UNINITIALIZED;
-
- /** option type */
- private static Class> type;
-
- /** option can have an optional argument value */
- private static boolean optionalArg;
-
- /** value separator for argument value */
- private static char valuesep;
-
- /** option builder instance */
- private static final OptionBuilder INSTANCE = new OptionBuilder();
-
- static {
- // ensure the consistency of the initial values
- reset();
- }
-
- /**
- * private constructor to prevent instances being created
- */
- private OptionBuilder() {
- // hide the constructor
- }
-
- /**
- * Resets the member variables to their default values.
- */
- private static void reset() {
- description = null;
- argName = null;
- longopt = null;
- type = String.class;
- required = false;
- numberOfArgs = Option.UNINITIALIZED;
- optionalArg = false;
- valuesep = (char) 0;
- }
-
- /**
- * The next Option created will have the following long option value.
- *
- * @param newLongopt the long option value
- * @return the OptionBuilder instance
- */
- public static OptionBuilder withLongOpt(String newLongopt) {
- OptionBuilder.longopt = newLongopt;
-
- return INSTANCE;
- }
-
- /**
- * The next Option created will require an argument value.
- *
- * @return the OptionBuilder instance
- */
- public static OptionBuilder hasArg() {
- OptionBuilder.numberOfArgs = 1;
-
- return INSTANCE;
- }
-
- /**
- * The next Option created will require an argument value if
- * hasArg
is true.
- *
- * @param hasArg if true then the Option has an argument value
- * @return the OptionBuilder instance
- */
- public static OptionBuilder hasArg(boolean hasArg) {
- OptionBuilder.numberOfArgs = hasArg ? 1 : Option.UNINITIALIZED;
-
- return INSTANCE;
- }
-
- /**
- * The next Option created will have the specified argument value name.
- *
- * @param name the name for the argument value
- * @return the OptionBuilder instance
- */
- public static OptionBuilder withArgName(String name) {
- OptionBuilder.argName = name;
-
- return INSTANCE;
- }
-
- /**
- * The next Option created will be required.
- *
- * @return the OptionBuilder instance
- */
- public static OptionBuilder isRequired() {
- OptionBuilder.required = true;
-
- return INSTANCE;
- }
-
- /**
- * The next Option created uses sep
as a means to
- * separate argument values.
- *
- * Example:
- *
- * Option opt = OptionBuilder.withValueSeparator('=')
- * .create('D');
- *
- * String args = "-Dkey=value";
- * CommandLine line = parser.parse(args);
- * String propertyName = opt.getValue(0); // will be "key"
- * String propertyValue = opt.getValue(1); // will be "value"
- *
- *
- * @param sep The value separator to be used for the argument values.
- *
- * @return the OptionBuilder instance
- */
- public static OptionBuilder withValueSeparator(char sep) {
- OptionBuilder.valuesep = sep;
-
- return INSTANCE;
- }
-
- /**
- * The next Option created uses '=
' as a means to
- * separate argument values.
- *
- * Example:
- *
- * Option opt = OptionBuilder.withValueSeparator()
- * .create('D');
- *
- * CommandLine line = parser.parse(args);
- * String propertyName = opt.getValue(0);
- * String propertyValue = opt.getValue(1);
- *
- *
- * @return the OptionBuilder instance
- */
- public static OptionBuilder withValueSeparator() {
- OptionBuilder.valuesep = '=';
-
- return INSTANCE;
- }
-
- /**
- * The next Option created will be required if required
- * is true.
- *
- * @param newRequired if true then the Option is required
- * @return the OptionBuilder instance
- */
- public static OptionBuilder isRequired(boolean newRequired) {
- OptionBuilder.required = newRequired;
-
- return INSTANCE;
- }
-
- /**
- * The next Option created can have unlimited argument values.
- *
- * @return the OptionBuilder instance
- */
- public static OptionBuilder hasArgs() {
- OptionBuilder.numberOfArgs = Option.UNLIMITED_VALUES;
-
- return INSTANCE;
- }
-
- /**
- * The next Option created can have num
argument values.
- *
- * @param num the number of args that the option can have
- * @return the OptionBuilder instance
- */
- public static OptionBuilder hasArgs(int num) {
- OptionBuilder.numberOfArgs = num;
-
- return INSTANCE;
- }
-
- /**
- * The next Option can have an optional argument.
- *
- * @return the OptionBuilder instance
- */
- public static OptionBuilder hasOptionalArg() {
- OptionBuilder.numberOfArgs = 1;
- OptionBuilder.optionalArg = true;
-
- return INSTANCE;
- }
-
- /**
- * The next Option can have an unlimited number of optional arguments.
- *
- * @return the OptionBuilder instance
- */
- public static OptionBuilder hasOptionalArgs() {
- OptionBuilder.numberOfArgs = Option.UNLIMITED_VALUES;
- OptionBuilder.optionalArg = true;
-
- return INSTANCE;
- }
-
- /**
- * The next Option can have the specified number of optional arguments.
- *
- * @param numArgs - the maximum number of optional arguments
- * the next Option created can have.
- * @return the OptionBuilder instance
- */
- public static OptionBuilder hasOptionalArgs(int numArgs) {
- OptionBuilder.numberOfArgs = numArgs;
- OptionBuilder.optionalArg = true;
-
- return INSTANCE;
- }
-
- /**
- * The next Option created will have a value that will be an instance
- * of type
.
- *
- * Note: this method is kept for binary compatibility and the
- * input type is supposed to be a {@link Class} object.
- *
- * @param newType the type of the Options argument value
- * @return the OptionBuilder instance
- * @deprecated since 1.3, use {@link #withType(Class)} instead
- */
- @Deprecated
- public static OptionBuilder withType(Object newType) {
- return withType((Class>) newType);
- }
-
- /**
- * The next Option created will have a value that will be an instance
- * of type
.
- *
- * @param newType the type of the Options argument value
- * @return the OptionBuilder instance
- * @since 1.3
- */
- public static OptionBuilder withType(Class> newType) {
- OptionBuilder.type = newType;
-
- return INSTANCE;
- }
-
- /**
- * The next Option created will have the specified description
- *
- * @param newDescription a description of the Option's purpose
- * @return the OptionBuilder instance
- */
- public static OptionBuilder withDescription(String newDescription) {
- OptionBuilder.description = newDescription;
-
- return INSTANCE;
- }
-
- /**
- * Create an Option using the current settings and with
- * the specified Option char
.
- *
- * @param opt the character representation of the Option
- * @return the Option instance
- * @throws IllegalArgumentException if opt
is not
- * a valid character. See Option.
- */
- public static Option create(char opt) throws IllegalArgumentException {
- return create(String.valueOf(opt));
- }
-
- /**
- * Create an Option using the current settings
- *
- * @return the Option instance
- * @throws IllegalArgumentException if longOpt
has not been set.
- */
- public static Option create() throws IllegalArgumentException {
- if (longopt == null) {
- OptionBuilder.reset();
- throw new IllegalArgumentException("must specify longopt");
- }
-
- return create(null);
- }
-
- /**
- * Create an Option using the current settings and with
- * the specified Option char
.
- *
- * @param opt the java.lang.String
representation
- * of the Option
- * @return the Option instance
- * @throws IllegalArgumentException if opt
is not
- * a valid character. See Option.
- */
- public static Option create(String opt) throws IllegalArgumentException {
- Option option = null;
- try {
- // create the option
- option = new Option(opt, description);
-
- // set the option properties
- option.setLongOpt(longopt);
- option.setRequired(required);
- option.setOptionalArg(optionalArg);
- option.setArgs(numberOfArgs);
- option.setType(type);
- option.setValueSeparator(valuesep);
- option.setArgName(argName);
- } finally {
- // reset the OptionBuilder properties
- OptionBuilder.reset();
- }
-
- // return the Option instance
- return option;
- }
-}
diff --git a/src/org/apache/commons/cli/OptionGroup.java b/src/org/apache/commons/cli/OptionGroup.java
deleted file mode 100644
index b7d7b817..00000000
--- a/src/org/apache/commons/cli/OptionGroup.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * A group of mutually exclusive options.
- *
- * @version $Id: OptionGroup.java 1669814 2015-03-28 18:09:26Z britter $
- */
-public class OptionGroup implements Serializable {
- /** The serial version UID. */
- private static final long serialVersionUID = 1L;
-
- /** hold the options */
- private final Map optionMap = new HashMap();
-
- /** the name of the selected option */
- private String selected;
-
- /** specified whether this group is required */
- private boolean required;
-
- /**
- * Add the specified Option
to this group.
- *
- * @param option the option to add to this group
- * @return this option group with the option added
- */
- public OptionGroup addOption(Option option) {
- // key - option name
- // value - the option
- optionMap.put(option.getKey(), option);
-
- return this;
- }
-
- /**
- * @return the names of the options in this group as a
- * Collection
- */
- public Collection getNames() {
- // the key set is the collection of names
- return optionMap.keySet();
- }
-
- /**
- * @return the options in this group as a Collection
- */
- public Collection getOptions() {
- // the values are the collection of options
- return optionMap.values();
- }
-
- /**
- * Set the selected option of this group to name
.
- *
- * @param option the option that is selected
- * @throws AlreadySelectedException if an option from this group has
- * already been selected.
- */
- public void setSelected(Option option) throws AlreadySelectedException {
- if (option == null) {
- // reset the option previously selected
- selected = null;
- return;
- }
-
- // if no option has already been selected or the
- // same option is being reselected then set the
- // selected member variable
- if (selected == null || selected.equals(option.getKey())) {
- selected = option.getKey();
- } else {
- throw new AlreadySelectedException(this, option);
- }
- }
-
- /**
- * @return the selected option name
- */
- public String getSelected() {
- return selected;
- }
-
- /**
- * @param required specifies if this group is required
- */
- public void setRequired(boolean required) {
- this.required = required;
- }
-
- /**
- * Returns whether this option group is required.
- *
- * @return whether this option group is required
- */
- public boolean isRequired() {
- return required;
- }
-
- /**
- * Returns the stringified version of this OptionGroup.
- *
- * @return the stringified representation of this group
- */
- @Override
- public String toString() {
- StringBuilder buff = new StringBuilder();
-
- Iterator iter = getOptions().iterator();
-
- buff.append("[");
-
- while (iter.hasNext()) {
- Option option = iter.next();
-
- if (option.getOpt() != null) {
- buff.append("-");
- buff.append(option.getOpt());
- } else {
- buff.append("--");
- buff.append(option.getLongOpt());
- }
-
- if (option.getDescription() != null) {
- buff.append(" ");
- buff.append(option.getDescription());
- }
-
- if (iter.hasNext()) {
- buff.append(", ");
- }
- }
-
- buff.append("]");
-
- return buff.toString();
- }
-}
diff --git a/src/org/apache/commons/cli/OptionValidator.java b/src/org/apache/commons/cli/OptionValidator.java
deleted file mode 100644
index d4d7af49..00000000
--- a/src/org/apache/commons/cli/OptionValidator.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-/**
- * Validates an Option string.
- *
- * @version $Id: OptionValidator.java 1544819 2013-11-23 15:34:31Z tn $
- * @since 1.1
- */
-final class OptionValidator {
- /**
- * Validates whether opt
is a permissible Option
- * shortOpt. The rules that specify if the opt
- * is valid are:
- *
- *
- * a single character opt
that is either
- * ' '(special case), '?', '@' or a letter
- * a multi character opt
that only contains
- * letters.
- *
- *
- * In case {@code opt} is {@code null} no further validation is performed.
- *
- * @param opt The option string to validate, may be null
- * @throws IllegalArgumentException if the Option is not valid.
- */
- static void validateOption(String opt) throws IllegalArgumentException {
- // if opt is NULL do not check further
- if (opt == null) {
- return;
- }
-
- // handle the single character opt
- if (opt.length() == 1) {
- char ch = opt.charAt(0);
-
- if (!isValidOpt(ch)) {
- throw new IllegalArgumentException("Illegal option name '" + ch + "'");
- }
- }
-
- // handle the multi character opt
- else {
- for (char ch : opt.toCharArray()) {
- if (!isValidChar(ch)) {
- throw new IllegalArgumentException("The option '" + opt + "' contains an illegal "
- + "character : '" + ch + "'");
- }
- }
- }
- }
-
- /**
- * Returns whether the specified character is a valid Option.
- *
- * @param c the option to validate
- * @return true if c
is a letter, '?' or '@', otherwise false.
- */
- private static boolean isValidOpt(char c) {
- return isValidChar(c) || c == '?' || c == '@';
- }
-
- /**
- * Returns whether the specified character is a valid character.
- *
- * @param c the character to validate
- * @return true if c
is a letter.
- */
- private static boolean isValidChar(char c) {
- return Character.isJavaIdentifierPart(c);
- }
-}
diff --git a/src/org/apache/commons/cli/Options.java b/src/org/apache/commons/cli/Options.java
deleted file mode 100644
index 62cc43be..00000000
--- a/src/org/apache/commons/cli/Options.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Main entry-point into the library.
- *
- * Options represents a collection of {@link Option} objects, which
- * describe the possible options for a command-line.
- *
- * It may flexibly parse long and short options, with or without
- * values. Additionally, it may parse only a portion of a commandline,
- * allowing for flexible multi-stage parsing.
- *
- * @see org.apache.commons.cli.CommandLine
- *
- * @version $Id: Options.java 1685376 2015-06-14 09:51:59Z britter $
- */
-public class Options implements Serializable {
- /** The serial version UID. */
- private static final long serialVersionUID = 1L;
-
- /** a map of the options with the character key */
- private final Map shortOpts = new LinkedHashMap();
-
- /** a map of the options with the long key */
- private final Map longOpts = new LinkedHashMap();
-
- /** a map of the required options */
- // N.B. This can contain either a String (addOption) or an OptionGroup (addOptionGroup)
- // TODO this seems wrong
- private final List requiredOpts = new ArrayList();
-
- /** a map of the option groups */
- private final Map optionGroups = new HashMap();
-
- /**
- * Add the specified option group.
- *
- * @param group the OptionGroup that is to be added
- * @return the resulting Options instance
- */
- public Options addOptionGroup(OptionGroup group) {
- if (group.isRequired()) {
- requiredOpts.add(group);
- }
-
- for (Option option : group.getOptions()) {
- // an Option cannot be required if it is in an
- // OptionGroup, either the group is required or
- // nothing is required
- option.setRequired(false);
- addOption(option);
-
- optionGroups.put(option.getKey(), group);
- }
-
- return this;
- }
-
- /**
- * Lists the OptionGroups that are members of this Options instance.
- *
- * @return a Collection of OptionGroup instances.
- */
- Collection getOptionGroups() {
- return new HashSet(optionGroups.values());
- }
-
- /**
- * Add an option that only contains a short name.
- * The option does not take an argument.
- *
- * @param opt Short single-character name of the option.
- * @param description Self-documenting description
- * @return the resulting Options instance
- * @since 1.3
- */
- public Options addOption(String opt, String description) {
- addOption(opt, null, false, description);
- return this;
- }
-
- /**
- * Add an option that only contains a short-name.
- * It may be specified as requiring an argument.
- *
- * @param opt Short single-character name of the option.
- * @param hasArg flag signally if an argument is required after this option
- * @param description Self-documenting description
- * @return the resulting Options instance
- */
- public Options addOption(String opt, boolean hasArg, String description) {
- addOption(opt, null, hasArg, description);
- return this;
- }
-
- /**
- * Add an option that contains a short-name and a long-name.
- * It may be specified as requiring an argument.
- *
- * @param opt Short single-character name of the option.
- * @param longOpt Long multi-character name of the option.
- * @param hasArg flag signally if an argument is required after this option
- * @param description Self-documenting description
- * @return the resulting Options instance
- */
- public Options addOption(String opt, String longOpt, boolean hasArg, String description) {
- addOption(new Option(opt, longOpt, hasArg, description));
- return this;
- }
-
- /**
- * Adds an option instance
- *
- * @param opt the option that is to be added
- * @return the resulting Options instance
- */
- public Options addOption(Option opt) {
- String key = opt.getKey();
-
- // add it to the long option list
- if (opt.hasLongOpt()) {
- longOpts.put(opt.getLongOpt(), opt);
- }
-
- // if the option is required add it to the required list
- if (opt.isRequired()) {
- if (requiredOpts.contains(key)) {
- requiredOpts.remove(requiredOpts.indexOf(key));
- }
- requiredOpts.add(key);
- }
-
- shortOpts.put(key, opt);
-
- return this;
- }
-
- /**
- * Retrieve a read-only list of options in this set
- *
- * @return read-only Collection of {@link Option} objects in this descriptor
- */
- public Collection getOptions() {
- return Collections.unmodifiableCollection(helpOptions());
- }
-
- /**
- * Returns the Options for use by the HelpFormatter.
- *
- * @return the List of Options
- */
- List helpOptions() {
- return new ArrayList (shortOpts.values());
- }
-
- /**
- * Returns the required options.
- *
- * @return read-only List of required options
- */
- public List getRequiredOptions() {
- return Collections.unmodifiableList(requiredOpts);
- }
-
- /**
- * Retrieve the {@link Option} matching the long or short name specified.
- * The leading hyphens in the name are ignored (up to 2).
- *
- * @param opt short or long name of the {@link Option}
- * @return the option represented by opt
- */
- public Option getOption(String opt) {
- opt = Util.stripLeadingHyphens(opt);
-
- if (shortOpts.containsKey(opt)) {
- return shortOpts.get(opt);
- }
-
- return longOpts.get(opt);
- }
-
- /**
- * Returns the options with a long name starting with the name specified.
- *
- * @param opt the partial name of the option
- * @return the options matching the partial name specified, or an empty list if none matches
- * @since 1.3
- */
- public List getMatchingOptions(String opt) {
- opt = Util.stripLeadingHyphens(opt);
-
- List matchingOpts = new ArrayList();
-
- // for a perfect match return the single option only
- if (longOpts.keySet().contains(opt)) {
- return Collections.singletonList(opt);
- }
-
- for (String longOpt : longOpts.keySet()) {
- if (longOpt.startsWith(opt)) {
- matchingOpts.add(longOpt);
- }
- }
-
- return matchingOpts;
- }
-
- /**
- * Returns whether the named {@link Option} is a member of this {@link Options}.
- *
- * @param opt short or long name of the {@link Option}
- * @return true if the named {@link Option} is a member of this {@link Options}
- */
- public boolean hasOption(String opt) {
- opt = Util.stripLeadingHyphens(opt);
-
- return shortOpts.containsKey(opt) || longOpts.containsKey(opt);
- }
-
- /**
- * Returns whether the named {@link Option} is a member of this {@link Options}.
- *
- * @param opt long name of the {@link Option}
- * @return true if the named {@link Option} is a member of this {@link Options}
- * @since 1.3
- */
- public boolean hasLongOption(String opt) {
- opt = Util.stripLeadingHyphens(opt);
-
- return longOpts.containsKey(opt);
- }
-
- /**
- * Returns whether the named {@link Option} is a member of this {@link Options}.
- *
- * @param opt short name of the {@link Option}
- * @return true if the named {@link Option} is a member of this {@link Options}
- * @since 1.3
- */
- public boolean hasShortOption(String opt) {
- opt = Util.stripLeadingHyphens(opt);
-
- return shortOpts.containsKey(opt);
- }
-
- /**
- * Returns the OptionGroup the opt
belongs to.
- * @param opt the option whose OptionGroup is being queried.
- *
- * @return the OptionGroup if opt
is part
- * of an OptionGroup, otherwise return null
- */
- public OptionGroup getOptionGroup(Option opt) {
- return optionGroups.get(opt.getKey());
- }
-
- /**
- * Dump state, suitable for debugging.
- *
- * @return Stringified form of this object
- */
- @Override
- public String toString() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("[ Options: [ short ");
- buf.append(shortOpts.toString());
- buf.append(" ] [ long ");
- buf.append(longOpts);
- buf.append(" ]");
-
- return buf.toString();
- }
-}
diff --git a/src/org/apache/commons/cli/ParseException.java b/src/org/apache/commons/cli/ParseException.java
deleted file mode 100644
index 5d8db5ad..00000000
--- a/src/org/apache/commons/cli/ParseException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-/**
- * Base for Exceptions thrown during parsing of a command-line.
- *
- * @version $Id: ParseException.java 1443102 2013-02-06 18:12:16Z tn $
- */
-public class ParseException extends Exception {
- /**
- * This exception {@code serialVersionUID}.
- */
- private static final long serialVersionUID = 9112808380089253192L;
-
- /**
- * Construct a new ParseException
- * with the specified detail message.
- *
- * @param message the detail message
- */
- public ParseException(String message) {
- super(message);
- }
-}
diff --git a/src/org/apache/commons/cli/Parser.java b/src/org/apache/commons/cli/Parser.java
deleted file mode 100644
index e0efe863..00000000
--- a/src/org/apache/commons/cli/Parser.java
+++ /dev/null
@@ -1,377 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Properties;
-
-/**
- * Parser
creates {@link CommandLine}s.
- *
- * @version $Id: Parser.java 1677406 2015-05-03 14:27:31Z britter $
- * @deprecated since 1.3, the two-pass parsing with the flatten method is not enough flexible to handle complex cases
- */
-@Deprecated
-public abstract class Parser implements CommandLineParser {
- /** commandline instance */
- protected CommandLine cmd;
-
- /** current Options */
- private Options options;
-
- /** list of required options strings */
- private List requiredOptions;
-
- protected void setOptions(Options options) {
- this.options = options;
- this.requiredOptions = new ArrayList(options.getRequiredOptions());
- }
-
- protected Options getOptions() {
- return options;
- }
-
- protected List getRequiredOptions() {
- return requiredOptions;
- }
-
- /**
- * Subclasses must implement this method to reduce
- * the arguments
that have been passed to the parse method.
- *
- * @param opts The Options to parse the arguments by.
- * @param arguments The arguments that have to be flattened.
- * @param stopAtNonOption specifies whether to stop
- * flattening when a non option has been encountered
- * @return a String array of the flattened arguments
- * @throws ParseException if there are any problems encountered
- * while parsing the command line tokens.
- */
- protected abstract String[] flatten(Options opts, String[] arguments, boolean stopAtNonOption)
- throws ParseException;
-
- /**
- * Parses the specified arguments
based
- * on the specified {@link Options}.
- *
- * @param options the Options
- * @param arguments the arguments
- * @return the CommandLine
- * @throws ParseException if there are any problems encountered
- * while parsing the command line tokens.
- */
- public CommandLine parse(Options options, String[] arguments) throws ParseException {
- return parse(options, arguments, null, false);
- }
-
- /**
- * Parse the arguments according to the specified options and properties.
- *
- * @param options the specified Options
- * @param arguments the command line arguments
- * @param properties command line option name-value pairs
- * @return the list of atomic option and value tokens
- * @throws ParseException if there are any problems encountered
- * while parsing the command line tokens.
- *
- * @since 1.1
- */
- public CommandLine parse(Options options, String[] arguments, Properties properties) throws ParseException {
- return parse(options, arguments, properties, false);
- }
-
- /**
- * Parses the specified arguments
- * based on the specified {@link Options}.
- *
- * @param options the Options
- * @param arguments the arguments
- * @param stopAtNonOption if true an unrecognized argument stops
- * the parsing and the remaining arguments are added to the
- * {@link CommandLine}s args list. If false an unrecognized
- * argument triggers a ParseException.
- * @return the CommandLine
- * @throws ParseException if an error occurs when parsing the arguments.
- */
- public CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException {
- return parse(options, arguments, null, stopAtNonOption);
- }
-
- /**
- * Parse the arguments according to the specified options and
- * properties.
- *
- * @param options the specified Options
- * @param arguments the command line arguments
- * @param properties command line option name-value pairs
- * @param stopAtNonOption if true an unrecognized argument stops
- * the parsing and the remaining arguments are added to the
- * {@link CommandLine}s args list. If false an unrecognized
- * argument triggers a ParseException.
- *
- * @return the list of atomic option and value tokens
- *
- * @throws ParseException if there are any problems encountered
- * while parsing the command line tokens.
- *
- * @since 1.1
- */
- public CommandLine parse(Options options, String[] arguments, Properties properties, boolean stopAtNonOption)
- throws ParseException {
- // clear out the data in options in case it's been used before (CLI-71)
- for (Option opt : options.helpOptions()) {
- opt.clearValues();
- }
-
- // clear the data from the groups
- for (OptionGroup group : options.getOptionGroups()) {
- group.setSelected(null);
- }
-
- // initialise members
- setOptions(options);
-
- cmd = new CommandLine();
-
- boolean eatTheRest = false;
-
- if (arguments == null) {
- arguments = new String[0];
- }
-
- List tokenList = Arrays.asList(flatten(getOptions(), arguments, stopAtNonOption));
-
- ListIterator iterator = tokenList.listIterator();
-
- // process each flattened token
- while (iterator.hasNext()) {
- String t = iterator.next();
-
- // the value is the double-dash
- if ("--".equals(t)) {
- eatTheRest = true;
- }
-
- // the value is a single dash
- else if ("-".equals(t)) {
- if (stopAtNonOption) {
- eatTheRest = true;
- } else {
- cmd.addArg(t);
- }
- }
-
- // the value is an option
- else if (t.startsWith("-")) {
- if (stopAtNonOption && !getOptions().hasOption(t)) {
- eatTheRest = true;
- cmd.addArg(t);
- } else {
- processOption(t, iterator);
- }
- }
-
- // the value is an argument
- else {
- cmd.addArg(t);
-
- if (stopAtNonOption) {
- eatTheRest = true;
- }
- }
-
- // eat the remaining tokens
- if (eatTheRest) {
- while (iterator.hasNext()) {
- String str = iterator.next();
-
- // ensure only one double-dash is added
- if (!"--".equals(str)) {
- cmd.addArg(str);
- }
- }
- }
- }
-
- processProperties(properties);
- checkRequiredOptions();
-
- return cmd;
- }
-
- /**
- * Sets the values of Options using the values in properties
.
- *
- * @param properties The value properties to be processed.
- * @throws ParseException if there are any problems encountered
- * while processing the properties.
- */
- protected void processProperties(Properties properties) throws ParseException {
- if (properties == null) {
- return;
- }
-
- for (Enumeration> e = properties.propertyNames(); e.hasMoreElements(); ) {
- String option = e.nextElement().toString();
-
- Option opt = options.getOption(option);
- if (opt == null) {
- throw new UnrecognizedOptionException("Default option wasn't defined", option);
- }
-
- // if the option is part of a group, check if another option of the group has been selected
- OptionGroup group = options.getOptionGroup(opt);
- boolean selected = group != null && group.getSelected() != null;
-
- if (!cmd.hasOption(option) && !selected) {
- // get the value from the properties instance
- String value = properties.getProperty(option);
-
- if (opt.hasArg()) {
- if (opt.getValues() == null || opt.getValues().length == 0) {
- try {
- opt.addValueForProcessing(value);
- } catch (RuntimeException exp) //NOPMD
- {
- // if we cannot add the value don't worry about it
- }
- }
- } else if (!("yes".equalsIgnoreCase(value)
- || "true".equalsIgnoreCase(value)
- || "1".equalsIgnoreCase(value))) {
- // if the value is not yes, true or 1 then don't add the
- // option to the CommandLine
- continue;
- }
-
- cmd.addOption(opt);
- updateRequiredOptions(opt);
- }
- }
- }
-
- /**
- * Throws a {@link MissingOptionException} if all of the required options
- * are not present.
- *
- * @throws MissingOptionException if any of the required Options are not present.
- */
- protected void checkRequiredOptions() throws MissingOptionException {
- // if there are required options that have not been processed
- if (!getRequiredOptions().isEmpty()) {
- throw new MissingOptionException(getRequiredOptions());
- }
- }
-
- /**
- * Process the argument values for the specified Option
- * opt
using the values retrieved from the
- * specified iterator iter
.
- *
- * @param opt The current Option
- * @param iter The iterator over the flattened command line Options.
- *
- * @throws ParseException if an argument value is required
- * and it is has not been found.
- */
- public void processArgs(Option opt, ListIterator iter) throws ParseException {
- // loop until an option is found
- while (iter.hasNext()) {
- String str = iter.next();
-
- // found an Option, not an argument
- if (getOptions().hasOption(str) && str.startsWith("-")) {
- iter.previous();
- break;
- }
-
- // found a value
- try {
- opt.addValueForProcessing(Util.stripLeadingAndTrailingQuotes(str));
- } catch (RuntimeException exp) {
- iter.previous();
- break;
- }
- }
-
- if (opt.getValues() == null && !opt.hasOptionalArg()) {
- throw new MissingArgumentException(opt);
- }
- }
-
- /**
- * Process the Option specified by arg
using the values
- * retrieved from the specified iterator iter
.
- *
- * @param arg The String value representing an Option
- * @param iter The iterator over the flattened command line arguments.
- *
- * @throws ParseException if arg
does not represent an Option
- */
- protected void processOption(String arg, ListIterator iter) throws ParseException {
- boolean hasOption = getOptions().hasOption(arg);
-
- // if there is no option throw an UnrecognisedOptionException
- if (!hasOption) {
- throw new UnrecognizedOptionException("Unrecognized option: " + arg, arg);
- }
-
- // get the option represented by arg
- Option opt = (Option) getOptions().getOption(arg).clone();
-
- // update the required options and groups
- updateRequiredOptions(opt);
-
- // if the option takes an argument value
- if (opt.hasArg()) {
- processArgs(opt, iter);
- }
-
- // set the option on the command line
- cmd.addOption(opt);
- }
-
- /**
- * Removes the option or its group from the list of expected elements.
- *
- * @param opt
- */
- private void updateRequiredOptions(Option opt) throws ParseException {
- // if the option is a required option remove the option from
- // the requiredOptions list
- if (opt.isRequired()) {
- getRequiredOptions().remove(opt.getKey());
- }
-
- // if the option is in an OptionGroup make that option the selected
- // option of the group
- if (getOptions().getOptionGroup(opt) != null) {
- OptionGroup group = getOptions().getOptionGroup(opt);
-
- if (group.isRequired()) {
- getRequiredOptions().remove(group);
- }
-
- group.setSelected(opt);
- }
- }
-}
diff --git a/src/org/apache/commons/cli/PatternOptionBuilder.java b/src/org/apache/commons/cli/PatternOptionBuilder.java
deleted file mode 100644
index 7767e378..00000000
--- a/src/org/apache/commons/cli/PatternOptionBuilder.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.net.URL;
-import java.util.Date;
-
-/**
- *
Allows Options to be created from a single String.
- * The pattern contains various single character flags and via
- * an optional punctuation character, their expected type.
- *
- *
- *
- * Overview of PatternOptionBuilder patterns
- * a -a flag
- * b@ -b [classname]
- * c> -c [filename]
- * d+ -d [classname] (creates object via empty constructor)
- * e% -e [number] (creates Double/Long instance depending on existing of a '.')
- * f/ -f [url]
- * g: -g [string]
- *
- *
- *
- * For example, the following allows command line flags of '-v -p string-value -f /dir/file'.
- * The exclamation mark precede a mandatory option.
- *
- *
- *
- * Options options = PatternOptionBuilder.parsePattern("vp:!f/");
- *
- *
- *
- * TODO: These need to break out to OptionType and also to be pluggable.
- *
- *
- * @version $Id: PatternOptionBuilder.java 1677406 2015-05-03 14:27:31Z britter $
- */
-public class PatternOptionBuilder {
- /** String class */
- public static final Class STRING_VALUE = String.class;
-
- /** Object class */
- public static final Class OBJECT_VALUE = Object.class;
-
- /** Number class */
- public static final Class NUMBER_VALUE = Number.class;
-
- /** Date class */
- public static final Class DATE_VALUE = Date.class;
-
- /** Class class */
- public static final Class> CLASS_VALUE = Class.class;
-
- /// can we do this one??
- // is meant to check that the file exists, else it errors.
- // ie) it's for reading not writing.
-
- /** FileInputStream class */
- public static final Class EXISTING_FILE_VALUE = FileInputStream.class;
-
- /** File class */
- public static final Class FILE_VALUE = File.class;
-
- /** File array class */
- public static final Class FILES_VALUE = File[].class;
-
- /** URL class */
- public static final Class URL_VALUE = URL.class;
-
- /**
- * Retrieve the class that ch
represents.
- *
- * @param ch the specified character
- * @return The class that ch
represents
- */
- public static Object getValueClass(char ch) {
- switch (ch) {
- case '@':
- return PatternOptionBuilder.OBJECT_VALUE;
- case ':':
- return PatternOptionBuilder.STRING_VALUE;
- case '%':
- return PatternOptionBuilder.NUMBER_VALUE;
- case '+':
- return PatternOptionBuilder.CLASS_VALUE;
- case '#':
- return PatternOptionBuilder.DATE_VALUE;
- case '<':
- return PatternOptionBuilder.EXISTING_FILE_VALUE;
- case '>':
- return PatternOptionBuilder.FILE_VALUE;
- case '*':
- return PatternOptionBuilder.FILES_VALUE;
- case '/':
- return PatternOptionBuilder.URL_VALUE;
- }
-
- return null;
- }
-
- /**
- * Returns whether ch
is a value code, i.e.
- * whether it represents a class in a pattern.
- *
- * @param ch the specified character
- * @return true if ch
is a value code, otherwise false.
- */
- public static boolean isValueCode(char ch) {
- return ch == '@'
- || ch == ':'
- || ch == '%'
- || ch == '+'
- || ch == '#'
- || ch == '<'
- || ch == '>'
- || ch == '*'
- || ch == '/'
- || ch == '!';
- }
-
- /**
- * Returns the {@link Options} instance represented by pattern
.
- *
- * @param pattern the pattern string
- * @return The {@link Options} instance
- */
- public static Options parsePattern(String pattern) {
- char opt = ' ';
- boolean required = false;
- Class> type = null;
-
- Options options = new Options();
-
- for (int i = 0; i < pattern.length(); i++) {
- char ch = pattern.charAt(i);
-
- // a value code comes after an option and specifies
- // details about it
- if (!isValueCode(ch)) {
- if (opt != ' ') {
- final Option option = Option.builder(String.valueOf(opt))
- .hasArg(type != null)
- .required(required)
- .type(type)
- .build();
-
- // we have a previous one to deal with
- options.addOption(option);
- required = false;
- type = null;
- opt = ' ';
- }
-
- opt = ch;
- } else if (ch == '!') {
- required = true;
- } else {
- type = (Class>) getValueClass(ch);
- }
- }
-
- if (opt != ' ') {
- final Option option = Option.builder(String.valueOf(opt))
- .hasArg(type != null)
- .required(required)
- .type(type)
- .build();
-
- // we have a final one to deal with
- options.addOption(option);
- }
-
- return options;
- }
-}
diff --git a/src/org/apache/commons/cli/PosixParser.java b/src/org/apache/commons/cli/PosixParser.java
deleted file mode 100644
index 3010729a..00000000
--- a/src/org/apache/commons/cli/PosixParser.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * The class PosixParser provides an implementation of the
- * {@link Parser#flatten(Options, String[], boolean) flatten} method.
- *
- * @version $Id: PosixParser.java 1677451 2015-05-03 17:09:29Z ggregory $
- * @deprecated since 1.3, use the {@link DefaultParser} instead
- */
-@Deprecated
-public class PosixParser extends Parser {
- /** holder for flattened tokens */
- private final List tokens = new ArrayList();
-
- /** specifies if bursting should continue */
- private boolean eatTheRest;
-
- /** holder for the current option */
- private Option currentOption;
-
- /** the command line Options */
- private Options options;
-
- /**
- * Resets the members to their original state i.e. remove
- * all of tokens
entries and set eatTheRest
- * to false.
- */
- private void init() {
- eatTheRest = false;
- tokens.clear();
- }
-
- /**
- * An implementation of {@link Parser}'s abstract
- * {@link Parser#flatten(Options, String[], boolean) flatten} method.
- *
- * The following are the rules used by this flatten method.
- *
- * if stopAtNonOption
is true then do not
- * burst anymore of arguments
entries, just add each
- * successive entry without further processing. Otherwise, ignore
- * stopAtNonOption
.
- * if the current arguments
entry is "-- "
- * just add the entry to the list of processed tokens
- * if the current arguments
entry is "- "
- * just add the entry to the list of processed tokens
- * if the current arguments
entry is two characters
- * in length and the first character is "- " then check if this
- * is a valid {@link Option} id. If it is a valid id, then add the
- * entry to the list of processed tokens and set the current {@link Option}
- * member. If it is not a valid id and stopAtNonOption
- * is true, then the remaining entries are copied to the list of
- * processed tokens. Otherwise, the current entry is ignored.
- * if the current arguments
entry is more than two
- * characters in length and the first character is "- " then
- * we need to burst the entry to determine its constituents. For more
- * information on the bursting algorithm see
- * {@link PosixParser#burstToken(String, boolean) burstToken}.
- * if the current arguments
entry is not handled
- * by any of the previous rules, then the entry is added to the list
- * of processed tokens.
- *
- *
- * @param options The command line {@link Options}
- * @param arguments The command line arguments to be parsed
- * @param stopAtNonOption Specifies whether to stop flattening
- * when an non option is found.
- * @return The flattened arguments
String array.
- */
- @Override
- protected String[] flatten(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException {
- init();
- this.options = options;
-
- // an iterator for the command line tokens
- Iterator iter = Arrays.asList(arguments).iterator();
-
- // process each command line token
- while (iter.hasNext()) {
- // get the next command line token
- String token = iter.next();
-
- // single or double hyphen
- if ("-".equals(token) || "--".equals(token)) {
- tokens.add(token);
- }
-
- // handle long option --foo or --foo=bar
- else if (token.startsWith("--")) {
- int pos = token.indexOf('=');
- String opt = pos == -1 ? token : token.substring(0, pos); // --foo
-
- List matchingOpts = options.getMatchingOptions(opt);
-
- if (matchingOpts.isEmpty()) {
- processNonOptionToken(token, stopAtNonOption);
- } else if (matchingOpts.size() > 1) {
- throw new AmbiguousOptionException(opt, matchingOpts);
- } else {
- currentOption = options.getOption(matchingOpts.get(0));
-
- tokens.add("--" + currentOption.getLongOpt());
- if (pos != -1) {
- tokens.add(token.substring(pos + 1));
- }
- }
- } else if (token.startsWith("-")) {
- if (token.length() == 2 || options.hasOption(token)) {
- processOptionToken(token, stopAtNonOption);
- } else if (!options.getMatchingOptions(token).isEmpty()) {
- List matchingOpts = options.getMatchingOptions(token);
- if (matchingOpts.size() > 1) {
- throw new AmbiguousOptionException(token, matchingOpts);
- }
- Option opt = options.getOption(matchingOpts.get(0));
- processOptionToken("-" + opt.getLongOpt(), stopAtNonOption);
- }
- // requires bursting
- else {
- burstToken(token, stopAtNonOption);
- }
- } else {
- processNonOptionToken(token, stopAtNonOption);
- }
-
- gobble(iter);
- }
-
- return tokens.toArray(new String[tokens.size()]);
- }
-
- /**
- * Adds the remaining tokens to the processed tokens list.
- *
- * @param iter An iterator over the remaining tokens
- */
- private void gobble(Iterator iter) {
- if (eatTheRest) {
- while (iter.hasNext()) {
- tokens.add(iter.next());
- }
- }
- }
-
- /**
- * Add the special token "-- " and the current value
- * to the processed tokens list. Then add all the remaining
- * argument
values to the processed tokens list.
- *
- * @param value The current token
- */
- private void processNonOptionToken(String value, boolean stopAtNonOption) {
- if (stopAtNonOption && (currentOption == null || !currentOption.hasArg())) {
- eatTheRest = true;
- tokens.add("--");
- }
-
- tokens.add(value);
- }
-
- /**
- * If an {@link Option} exists for token
then
- * add the token to the processed list.
- *
- * If an {@link Option} does not exist and stopAtNonOption
- * is set then add the remaining tokens to the processed tokens list
- * directly.
- *
- * @param token The current option token
- * @param stopAtNonOption Specifies whether flattening should halt
- * at the first non option.
- */
- private void processOptionToken(String token, boolean stopAtNonOption) {
- if (stopAtNonOption && !options.hasOption(token)) {
- eatTheRest = true;
- }
-
- if (options.hasOption(token)) {
- currentOption = options.getOption(token);
- }
-
- tokens.add(token);
- }
-
- /**
- * Breaks token
into its constituent parts
- * using the following algorithm.
- *
- *
- * ignore the first character ("- ")
- * foreach remaining character check if an {@link Option}
- * exists with that id.
- * if an {@link Option} does exist then add that character
- * prepended with "- " to the list of processed tokens.
- * if the {@link Option} can have an argument value and there
- * are remaining characters in the token then add the remaining
- * characters as a token to the list of processed tokens.
- * if an {@link Option} does NOT exist AND
- * stopAtNonOption
IS set then add the special token
- * "-- " followed by the remaining characters and also
- * the remaining tokens directly to the processed tokens list.
- * if an {@link Option} does NOT exist AND
- * stopAtNonOption
IS NOT set then add that
- * character prepended with "- ".
- *
- *
- * @param token The current token to be burst
- * @param stopAtNonOption Specifies whether to stop processing
- * at the first non-Option encountered.
- */
- protected void burstToken(String token, boolean stopAtNonOption) {
- for (int i = 1; i < token.length(); i++) {
- String ch = String.valueOf(token.charAt(i));
-
- if (options.hasOption(ch)) {
- tokens.add("-" + ch);
- currentOption = options.getOption(ch);
-
- if (currentOption.hasArg() && token.length() != i + 1) {
- tokens.add(token.substring(i + 1));
-
- break;
- }
- } else if (stopAtNonOption) {
- processNonOptionToken(token.substring(i), true);
- break;
- } else {
- tokens.add(token);
- break;
- }
- }
- }
-}
diff --git a/src/org/apache/commons/cli/TypeHandler.java b/src/org/apache/commons/cli/TypeHandler.java
deleted file mode 100644
index 250e7096..00000000
--- a/src/org/apache/commons/cli/TypeHandler.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-import java.io.File;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import java.util.Date;
-
-/**
- * This is a temporary implementation. TypeHandler will handle the
- * pluggableness of OptionTypes and it will direct all of these types
- * of conversion functionalities to ConvertUtils component in Commons
- * already. BeanUtils I think.
- *
- * @version $Id: TypeHandler.java 1677452 2015-05-03 17:10:00Z ggregory $
- */
-public class TypeHandler {
- /**
- * Returns the Object
of type obj
- * with the value of str
.
- *
- * @param str the command line value
- * @param obj the type of argument
- * @return The instance of obj
initialised with
- * the value of str
.
- * @throws ParseException if the value creation for the given object type failed
- */
- public static Object createValue(String str, Object obj) throws ParseException {
- return createValue(str, (Class>) obj);
- }
-
- /**
- * Returns the Object
of type clazz
- * with the value of str
.
- *
- * @param str the command line value
- * @param clazz the type of argument
- * @return The instance of clazz
initialised with
- * the value of str
.
- * @throws ParseException if the value creation for the given class failed
- */
- public static Object createValue(String str, Class> clazz) throws ParseException {
- if (PatternOptionBuilder.STRING_VALUE == clazz) {
- return str;
- } else if (PatternOptionBuilder.OBJECT_VALUE == clazz) {
- return createObject(str);
- } else if (PatternOptionBuilder.NUMBER_VALUE == clazz) {
- return createNumber(str);
- } else if (PatternOptionBuilder.DATE_VALUE == clazz) {
- return createDate(str);
- } else if (PatternOptionBuilder.CLASS_VALUE == clazz) {
- return createClass(str);
- } else if (PatternOptionBuilder.FILE_VALUE == clazz) {
- return createFile(str);
- } else if (PatternOptionBuilder.EXISTING_FILE_VALUE == clazz) {
- return createFile(str);
- } else if (PatternOptionBuilder.FILES_VALUE == clazz) {
- return createFiles(str);
- } else if (PatternOptionBuilder.URL_VALUE == clazz) {
- return createURL(str);
- } else {
- return null;
- }
- }
-
- /**
- * Create an Object from the classname and empty constructor.
- *
- * @param classname the argument value
- * @return the initialised object
- * @throws ParseException if the class could not be found or the object could not be created
- */
- public static Object createObject(String classname) throws ParseException {
- Class> cl;
-
- try {
- cl = Class.forName(classname);
- } catch (ClassNotFoundException cnfe) {
- throw new ParseException("Unable to find the class: " + classname);
- }
-
- try {
- return cl.newInstance();
- } catch (Exception e) {
- throw new ParseException(e.getClass().getName() + "; Unable to create an instance of: " + classname);
- }
- }
-
- /**
- * Create a number from a String. If a . is present, it creates a
- * Double, otherwise a Long.
- *
- * @param str the value
- * @return the number represented by str
- * @throws ParseException if str
is not a number
- */
- public static Number createNumber(String str) throws ParseException {
- try {
- if (str.indexOf('.') != -1) {
- return Double.valueOf(str);
- }
- return Long.valueOf(str);
- } catch (NumberFormatException e) {
- throw new ParseException(e.getMessage());
- }
- }
-
- /**
- * Returns the class whose name is classname
.
- *
- * @param classname the class name
- * @return The class if it is found
- * @throws ParseException if the class could not be found
- */
- public static Class> createClass(String classname) throws ParseException {
- try {
- return Class.forName(classname);
- } catch (ClassNotFoundException e) {
- throw new ParseException("Unable to find the class: " + classname);
- }
- }
-
- /**
- * Returns the date represented by str
.
- *
- * This method is not yet implemented and always throws an
- * {@link UnsupportedOperationException}.
- *
- * @param str the date string
- * @return The date if str
is a valid date string,
- * otherwise return null.
- * @throws UnsupportedOperationException always
- */
- public static Date createDate(String str) {
- throw new UnsupportedOperationException("Not yet implemented");
- }
-
- /**
- * Returns the URL represented by str
.
- *
- * @param str the URL string
- * @return The URL in str
is well-formed
- * @throws ParseException if the URL in str
is not well-formed
- */
- public static URL createURL(String str) throws ParseException {
- try {
- return new URL(str);
- } catch (MalformedURLException e) {
- throw new ParseException("Unable to parse the URL: " + str);
- }
- }
-
- /**
- * Returns the File represented by str
.
- *
- * @param str the File location
- * @return The file represented by str
.
- */
- public static File createFile(String str) {
- return new File(str);
- }
-
- /**
- * Returns the File[] represented by str
.
- *
- * This method is not yet implemented and always throws an
- * {@link UnsupportedOperationException}.
- *
- * @param str the paths to the files
- * @return The File[] represented by str
.
- * @throws UnsupportedOperationException always
- */
- public static File[] createFiles(String str) {
- // to implement/port:
- // return FileW.findFiles(str);
- throw new UnsupportedOperationException("Not yet implemented");
- }
-}
diff --git a/src/org/apache/commons/cli/UnrecognizedOptionException.java b/src/org/apache/commons/cli/UnrecognizedOptionException.java
deleted file mode 100644
index 18d915e3..00000000
--- a/src/org/apache/commons/cli/UnrecognizedOptionException.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-/**
- * Exception thrown during parsing signalling an unrecognized
- * option was seen.
- *
- * @version $Id: UnrecognizedOptionException.java 1443102 2013-02-06 18:12:16Z tn $
- */
-public class UnrecognizedOptionException extends ParseException {
- /**
- * This exception {@code serialVersionUID}.
- */
- private static final long serialVersionUID = -252504690284625623L;
-
- /** The unrecognized option */
- private String option;
-
- /**
- * Construct a new UnrecognizedArgumentException
- * with the specified detail message.
- *
- * @param message the detail message
- */
- public UnrecognizedOptionException(String message) {
- super(message);
- }
-
- /**
- * Construct a new UnrecognizedArgumentException
- * with the specified option and detail message.
- *
- * @param message the detail message
- * @param option the unrecognized option
- * @since 1.2
- */
- public UnrecognizedOptionException(String message, String option) {
- this(message);
- this.option = option;
- }
-
- /**
- * Returns the unrecognized option.
- *
- * @return the related option
- * @since 1.2
- */
- public String getOption() {
- return option;
- }
-}
diff --git a/src/org/apache/commons/cli/Util.java b/src/org/apache/commons/cli/Util.java
deleted file mode 100644
index 4ae370d5..00000000
--- a/src/org/apache/commons/cli/Util.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.cli;
-
-/**
- * Contains useful helper methods for classes within this package.
- *
- * @version $Id: Util.java 1443102 2013-02-06 18:12:16Z tn $
- */
-final class Util {
- /**
- * Remove the hyphens from the beginning of str
and
- * return the new String.
- *
- * @param str The string from which the hyphens should be removed.
- *
- * @return the new String.
- */
- static String stripLeadingHyphens(String str) {
- if (str == null) {
- return null;
- }
- if (str.startsWith("--")) {
- return str.substring(2, str.length());
- } else if (str.startsWith("-")) {
- return str.substring(1, str.length());
- }
-
- return str;
- }
-
- /**
- * Remove the leading and trailing quotes from str
.
- * E.g. if str is '"one two"', then 'one two' is returned.
- *
- * @param str The string from which the leading and trailing quotes
- * should be removed.
- *
- * @return The string without the leading and trailing quotes.
- */
- static String stripLeadingAndTrailingQuotes(String str) {
- int length = str.length();
- if (length > 1 && str.startsWith("\"") && str.endsWith("\"") && str.substring(1, length - 1).indexOf('"') == -1) {
- str = str.substring(1, length - 1);
- }
-
- return str;
- }
-}
diff --git a/src/org/apache/commons/cli/overview.html b/src/org/apache/commons/cli/overview.html
deleted file mode 100644
index 4edd2c5a..00000000
--- a/src/org/apache/commons/cli/overview.html
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-Commons CLI -- version 1.3
-
-The commons-cli package aides in parsing command-line arguments.
-
-Allow command-line arguments to be parsed against a descriptor of
- valid options (long and short), potentially with arguments.
-
-command-line arguments may be of the typical String[]
- form, but also may be a java.util.List
. Indexes allow
- for parsing only a portion of the command-line. Also, functionality
- for parsing the command-line in phases is built in, allowing for
- 'cvs-style' command-lines, where some global options are specified
- before a 'command' argument, and command-specific options are
- specified after the command argument:
-
-
-
- myApp -p <port> command -p <printer>
-
-
-
-
-
The homepage for the project is
- Apache Commons/
-
diff --git a/src/org/apache/commons/cli/package-info.java b/src/org/apache/commons/cli/package-info.java
deleted file mode 100644
index fef42159..00000000
--- a/src/org/apache/commons/cli/package-info.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Commons CLI 1.3
- *
- * @version $Id: package-info.java 1443102 2013-02-06 18:12:16Z tn $
- */
-
-/**
- * Commons CLI 1.3
- *
- * @version $Id: package-info.java 1443102 2013-02-06 18:12:16Z tn $
- */
-package org.apache.commons.cli;
diff --git a/src/org/apache/commons/codec/BinaryDecoder.java b/src/org/apache/commons/codec/BinaryDecoder.java
deleted file mode 100644
index 151df254..00000000
--- a/src/org/apache/commons/codec/BinaryDecoder.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec;
-
-/**
- * Defines common decoding methods for byte array decoders.
- *
- * @version $Id$
- */
-public interface BinaryDecoder extends Decoder {
-
- /**
- * Decodes a byte array and returns the results as a byte array.
- *
- * @param source A byte array which has been encoded with the appropriate encoder
- * @return a byte array that contains decoded content
- * @throws DecoderException A decoder exception is thrown if a Decoder encounters a failure condition during the decode process.
- */
- byte[] decode(byte[] source) throws DecoderException;
-}
-
diff --git a/src/org/apache/commons/codec/BinaryEncoder.java b/src/org/apache/commons/codec/BinaryEncoder.java
deleted file mode 100644
index 9746b154..00000000
--- a/src/org/apache/commons/codec/BinaryEncoder.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec;
-
-/**
- * Defines common encoding methods for byte array encoders.
- *
- * @version $Id$
- */
-public interface BinaryEncoder extends Encoder {
-
- /**
- * Encodes a byte array and return the encoded data as a byte array.
- *
- * @param source Data to be encoded
- * @return A byte array containing the encoded data
- * @throws EncoderException thrown if the Encoder encounters a failure condition during the encoding process.
- */
- byte[] encode(byte[] source) throws EncoderException;
-}
-
diff --git a/src/org/apache/commons/codec/CharEncoding.java b/src/org/apache/commons/codec/CharEncoding.java
deleted file mode 100644
index e40b7970..00000000
--- a/src/org/apache/commons/codec/CharEncoding.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec;
-
-/**
- * Character encoding names required of every implementation of the Java platform.
- *
- * From the Java documentation Standard charsets :
- *
- * Every implementation of the Java platform is required to support the following character encodings. Consult the
- * release documentation for your implementation to see if any other encodings are supported. Consult the release
- * documentation for your implementation to see if any other encodings are supported.
- *
- *
- *
- * US-ASCII
- * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.
- * ISO-8859-1
- * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
- * UTF-8
- * Eight-bit Unicode Transformation Format.
- * UTF-16BE
- * Sixteen-bit Unicode Transformation Format, big-endian byte order.
- * UTF-16LE
- * Sixteen-bit Unicode Transformation Format, little-endian byte order.
- * UTF-16
- * Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either order
- * accepted on input, big-endian used on output.)
- *
- *
- * This perhaps would best belong in the [lang] project. Even if a similar interface is defined in [lang], it is not
- * foreseen that [codec] would be made to depend on [lang].
- *
- *
- * This class is immutable and thread-safe.
- *
- *
- * @version $Id$
- * @see Standard charsets
- * @since 1.4
- */
-public class CharEncoding {
- /**
- * CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- */
- public static final String ISO_8859_1 = "ISO-8859-1";
-
- /**
- * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set.
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- */
- public static final String US_ASCII = "US-ASCII";
-
- /**
- * Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark
- * (either order accepted on input, big-endian used on output)
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- */
- public static final String UTF_16 = "UTF-16";
-
- /**
- * Sixteen-bit Unicode Transformation Format, big-endian byte order.
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- */
- public static final String UTF_16BE = "UTF-16BE";
-
- /**
- * Sixteen-bit Unicode Transformation Format, little-endian byte order.
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- */
- public static final String UTF_16LE = "UTF-16LE";
-
- /**
- * Eight-bit Unicode Transformation Format.
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- */
- public static final String UTF_8 = "UTF-8";
-}
diff --git a/src/org/apache/commons/codec/Charsets.java b/src/org/apache/commons/codec/Charsets.java
deleted file mode 100644
index 7a829b97..00000000
--- a/src/org/apache/commons/codec/Charsets.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.codec;
-
-import java.nio.charset.Charset;
-
-/**
- * Charsets required of every implementation of the Java platform.
- *
- * From the Java documentation Standard
- * charsets :
- *
- * Every implementation of the Java platform is required to support the following character encodings. Consult the
- * release documentation for your implementation to see if any other encodings are supported. Consult the release
- * documentation for your implementation to see if any other encodings are supported.
- *
- *
- *
- * US-ASCII
- * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.
- * ISO-8859-1
- * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
- * UTF-8
- * Eight-bit Unicode Transformation Format.
- * UTF-16BE
- * Sixteen-bit Unicode Transformation Format, big-endian byte order.
- * UTF-16LE
- * Sixteen-bit Unicode Transformation Format, little-endian byte order.
- * UTF-16
- * Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either order
- * accepted on input, big-endian used on output.)
- *
- *
- * This perhaps would best belong in the Commons Lang project. Even if a similar class is defined in Commons Lang, it is
- * not foreseen that Commons Codec would be made to depend on Commons Lang.
- *
- *
- * This class is immutable and thread-safe.
- *
- *
- * @version $Id: CharEncoding.java 1173287 2011-09-20 18:16:19Z ggregory $
- * @see Standard charsets
- * @since 1.7
- */
-public class Charsets {
-
- //
- // This class should only contain Charset instances for required encodings. This guarantees that it will load
- // correctly and without delay on all Java platforms.
- //
-
- /**
- * Returns the given Charset or the default Charset if the given Charset is null.
- *
- * @param charset A charset or null.
- * @return the given Charset or the default Charset if the given Charset is null
- */
- public static Charset toCharset(final Charset charset) {
- return charset == null ? Charset.defaultCharset() : charset;
- }
-
- /**
- * Returns a Charset for the named charset. If the name is null, return the default Charset.
- *
- * @param charset The name of the requested charset, may be null.
- * @return a Charset for the named charset
- * @throws java.nio.charset.UnsupportedCharsetException If the named charset is unavailable
- */
- public static Charset toCharset(final String charset) {
- return charset == null ? Charset.defaultCharset() : Charset.forName(charset);
- }
-
- /**
- * CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets#ISO_8859_1} instead
- */
- @Deprecated
- public static final Charset ISO_8859_1 = Charset.forName(CharEncoding.ISO_8859_1);
-
- /**
- * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set.
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets#US_ASCII} instead
- */
- @Deprecated
- public static final Charset US_ASCII = Charset.forName(CharEncoding.US_ASCII);
-
- /**
- * Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark
- * (either order accepted on input, big-endian used on output)
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets#UTF_16} instead
- */
- @Deprecated
- public static final Charset UTF_16 = Charset.forName(CharEncoding.UTF_16);
-
- /**
- * Sixteen-bit Unicode Transformation Format, big-endian byte order.
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets#UTF_16BE} instead
- */
- @Deprecated
- public static final Charset UTF_16BE = Charset.forName(CharEncoding.UTF_16BE);
-
- /**
- * Sixteen-bit Unicode Transformation Format, little-endian byte order.
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets#UTF_16LE} instead
- */
- @Deprecated
- public static final Charset UTF_16LE = Charset.forName(CharEncoding.UTF_16LE);
-
- /**
- * Eight-bit Unicode Transformation Format.
- *
- * Every implementation of the Java platform is required to support this character encoding.
- *
- * @see Standard charsets
- * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets#UTF_8}
- */
- @Deprecated
- public static final Charset UTF_8 = Charset.forName(CharEncoding.UTF_8);
-}
diff --git a/src/org/apache/commons/codec/Decoder.java b/src/org/apache/commons/codec/Decoder.java
deleted file mode 100644
index 664f0ddf..00000000
--- a/src/org/apache/commons/codec/Decoder.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec;
-
-/**
- * Provides the highest level of abstraction for Decoders.
- *
- * This is the sister interface of {@link Encoder}. All Decoders implement this common generic interface.
- * Allows a user to pass a generic Object to any Decoder implementation in the codec package.
- *
- * One of the two interfaces at the center of the codec package.
- *
- * @version $Id$
- */
-public interface Decoder {
-
- /**
- * Decodes an "encoded" Object and returns a "decoded" Object. Note that the implementation of this interface will
- * try to cast the Object parameter to the specific type expected by a particular Decoder implementation. If a
- * {@link ClassCastException} occurs this decode method will throw a DecoderException.
- *
- * @param source the object to decode
- * @return a 'decoded" object
- * @throws DecoderException a decoder exception can be thrown for any number of reasons. Some good candidates are that the
- * parameter passed to this method is null, a param cannot be cast to the appropriate type for a
- * specific encoder.
- */
- Object decode(Object source) throws DecoderException;
-}
-
diff --git a/src/org/apache/commons/codec/DecoderException.java b/src/org/apache/commons/codec/DecoderException.java
deleted file mode 100644
index 252b78a2..00000000
--- a/src/org/apache/commons/codec/DecoderException.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec;
-
-/**
- * Thrown when there is a failure condition during the decoding process. This exception is thrown when a {@link Decoder}
- * encounters a decoding specific exception such as invalid data, or characters outside of the expected range.
- *
- * @version $Id$
- */
-public class DecoderException extends Exception {
-
- /**
- * Declares the Serial Version Uid.
- *
- * @see Always Declare Serial Version Uid
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * Constructs a new exception with null
as its detail message. The cause is not initialized, and may
- * subsequently be initialized by a call to {@link #initCause}.
- *
- * @since 1.4
- */
- public DecoderException() {
- super();
- }
-
- /**
- * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
- * be initialized by a call to {@link #initCause}.
- *
- * @param message The detail message which is saved for later retrieval by the {@link #getMessage()} method.
- */
- public DecoderException(final String message) {
- super(message);
- }
-
- /**
- * Constructs a new exception with the specified detail message and cause.
- *
- * Note that the detail message associated with cause
is not automatically incorporated into this
- * exception's detail message.
- *
- * @param message The detail message which is saved for later retrieval by the {@link #getMessage()} method.
- * @param cause The cause which is saved for later retrieval by the {@link #getCause()} method. A null
- * value is permitted, and indicates that the cause is nonexistent or unknown.
- * @since 1.4
- */
- public DecoderException(final String message, final Throwable cause) {
- super(message, cause);
- }
-
- /**
- * Constructs a new exception with the specified cause and a detail message of (cause==null ?
- * null : cause.toString())
(which typically contains the class and detail message of cause
).
- * This constructor is useful for exceptions that are little more than wrappers for other throwables.
- *
- * @param cause The cause which is saved for later retrieval by the {@link #getCause()} method. A null
- * value is permitted, and indicates that the cause is nonexistent or unknown.
- * @since 1.4
- */
- public DecoderException(final Throwable cause) {
- super(cause);
- }
-}
diff --git a/src/org/apache/commons/codec/Encoder.java b/src/org/apache/commons/codec/Encoder.java
deleted file mode 100644
index dc630355..00000000
--- a/src/org/apache/commons/codec/Encoder.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec;
-
-/**
- * Provides the highest level of abstraction for Encoders.
- *
- * This is the sister interface of {@link Decoder}. Every implementation of Encoder provides this
- * common generic interface which allows a user to pass a generic Object to any Encoder implementation
- * in the codec package.
- *
- * @version $Id$
- */
-public interface Encoder {
-
- /**
- * Encodes an "Object" and returns the encoded content as an Object. The Objects here may just be
- * byte[]
or String
s depending on the implementation used.
- *
- * @param source An object to encode
- * @return An "encoded" Object
- * @throws EncoderException An encoder exception is thrown if the encoder experiences a failure condition during the encoding
- * process.
- */
- Object encode(Object source) throws EncoderException;
-}
-
diff --git a/src/org/apache/commons/codec/EncoderException.java b/src/org/apache/commons/codec/EncoderException.java
deleted file mode 100644
index c38eaf61..00000000
--- a/src/org/apache/commons/codec/EncoderException.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec;
-
-/**
- * Thrown when there is a failure condition during the encoding process. This exception is thrown when an
- * {@link Encoder} encounters a encoding specific exception such as invalid data, inability to calculate a checksum,
- * characters outside of the expected range.
- *
- * @version $Id$
- */
-public class EncoderException extends Exception {
-
- /**
- * Declares the Serial Version Uid.
- *
- * @see Always Declare Serial Version Uid
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * Constructs a new exception with null
as its detail message. The cause is not initialized, and may
- * subsequently be initialized by a call to {@link #initCause}.
- *
- * @since 1.4
- */
- public EncoderException() {
- super();
- }
-
- /**
- * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
- * be initialized by a call to {@link #initCause}.
- *
- * @param message a useful message relating to the encoder specific error.
- */
- public EncoderException(final String message) {
- super(message);
- }
-
- /**
- * Constructs a new exception with the specified detail message and cause.
- *
- *
- * Note that the detail message associated with cause
is not automatically incorporated into this
- * exception's detail message.
- *
- *
- * @param message The detail message which is saved for later retrieval by the {@link #getMessage()} method.
- * @param cause The cause which is saved for later retrieval by the {@link #getCause()} method. A null
- * value is permitted, and indicates that the cause is nonexistent or unknown.
- * @since 1.4
- */
- public EncoderException(final String message, final Throwable cause) {
- super(message, cause);
- }
-
- /**
- * Constructs a new exception with the specified cause and a detail message of (cause==null ?
- * null : cause.toString())
(which typically contains the class and detail message of cause
).
- * This constructor is useful for exceptions that are little more than wrappers for other throwables.
- *
- * @param cause The cause which is saved for later retrieval by the {@link #getCause()} method. A null
- * value is permitted, and indicates that the cause is nonexistent or unknown.
- * @since 1.4
- */
- public EncoderException(final Throwable cause) {
- super(cause);
- }
-}
diff --git a/src/org/apache/commons/codec/StringDecoder.java b/src/org/apache/commons/codec/StringDecoder.java
deleted file mode 100644
index c682afff..00000000
--- a/src/org/apache/commons/codec/StringDecoder.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec;
-
-/**
- * Defines common decoding methods for String decoders.
- *
- * @version $Id$
- */
-public interface StringDecoder extends Decoder {
-
- /**
- * Decodes a String and returns a String.
- *
- * @param source the String to decode
- * @return the encoded String
- * @throws DecoderException thrown if there is an error condition during the Encoding process.
- */
- String decode(String source) throws DecoderException;
-}
-
diff --git a/src/org/apache/commons/codec/StringEncoder.java b/src/org/apache/commons/codec/StringEncoder.java
deleted file mode 100644
index 7b7a421f..00000000
--- a/src/org/apache/commons/codec/StringEncoder.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec;
-
-/**
- * Defines common encoding methods for String encoders.
- *
- * @version $Id$
- */
-public interface StringEncoder extends Encoder {
-
- /**
- * Encodes a String and returns a String.
- *
- * @param source the String to encode
- * @return the encoded String
- * @throws EncoderException thrown if there is an error condition during the encoding process.
- */
- String encode(String source) throws EncoderException;
-}
-
diff --git a/src/org/apache/commons/codec/StringEncoderComparator.java b/src/org/apache/commons/codec/StringEncoderComparator.java
deleted file mode 100644
index 630f7b7b..00000000
--- a/src/org/apache/commons/codec/StringEncoderComparator.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec;
-
-import java.util.Comparator;
-
-/**
- * Compares Strings using a {@link StringEncoder}. This comparator is used to sort Strings by an encoding scheme such as
- * Soundex, Metaphone, etc. This class can come in handy if one need to sort Strings by an encoded form of a name such
- * as Soundex.
- *
- *
This class is immutable and thread-safe.
- *
- * @version $Id$
- */
-@SuppressWarnings("rawtypes")
-// TODO ought to implement Comparator but that's not possible whilst maintaining binary compatibility.
-public class StringEncoderComparator implements Comparator {
-
- /**
- * Internal encoder instance.
- */
- private final StringEncoder stringEncoder;
-
- /**
- * Constructs a new instance.
- *
- * @deprecated Creating an instance without a {@link StringEncoder} leads to a {@link NullPointerException}. Will be
- * removed in 2.0.
- */
- @Deprecated
- public StringEncoderComparator() {
- this.stringEncoder = null; // Trying to use this will cause things to break
- }
-
- /**
- * Constructs a new instance with the given algorithm.
- *
- * @param stringEncoder the StringEncoder used for comparisons.
- */
- public StringEncoderComparator(final StringEncoder stringEncoder) {
- this.stringEncoder = stringEncoder;
- }
-
- /**
- * Compares two strings based not on the strings themselves, but on an encoding of the two strings using the
- * StringEncoder this Comparator was created with.
- *
- * If an {@link EncoderException} is encountered, return 0
.
- *
- * @param o1 the object to compare
- * @param o2 the object to compare to
- * @return the Comparable.compareTo() return code or 0 if an encoding error was caught.
- * @see Comparable
- */
- @Override
- public int compare(final Object o1, final Object o2) {
-
- int compareCode = 0;
-
- try {
- @SuppressWarnings("unchecked") // May fail with CCE if encode returns something that is not Comparable
- // However this was always the case.
- final Comparable> s1 = (Comparable>) this.stringEncoder.encode(o1);
- final Comparable> s2 = (Comparable>) this.stringEncoder.encode(o2);
- compareCode = s1.compareTo(s2);
- } catch (final EncoderException ee) {
- compareCode = 0;
- }
- return compareCode;
- }
-}
diff --git a/src/org/apache/commons/codec/binary/Base32.java b/src/org/apache/commons/codec/binary/Base32.java
deleted file mode 100644
index 95518bf1..00000000
--- a/src/org/apache/commons/codec/binary/Base32.java
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-/**
- * Provides Base32 encoding and decoding as defined by RFC 4648 .
- *
- *
- * The class can be parameterized in the following manner with various constructors:
- *
- *
- * Whether to use the "base32hex" variant instead of the default "base32"
- * Line length: Default 76. Line length that aren't multiples of 8 will still essentially end up being multiples of
- * 8 in the encoded data.
- * Line separator: Default is CRLF ("\r\n")
- *
- *
- * This class operates directly on byte streams, and not character streams.
- *
- *
- * This class is thread-safe.
- *
- *
- * @version $Id$
- * @see RFC 4648
- * @since 1.5
- */
-public class Base32 extends BaseNCodec {
-
- /**
- * BASE32 characters are 5 bits in length.
- * They are formed by taking a block of five octets to form a 40-bit string,
- * which is converted into eight BASE32 characters.
- */
- private static final int BITS_PER_ENCODED_BYTE = 5;
- private static final int BYTES_PER_ENCODED_BLOCK = 8;
- private static final int BYTES_PER_UNENCODED_BLOCK = 5;
-
- /**
- * Chunk separator per RFC 2045 section 2.1.
- *
- * @see RFC 2045 section 2.1
- */
- private static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
-
- /**
- * This array is a lookup table that translates Unicode characters drawn from the "Base32 Alphabet" (as specified
- * in Table 3 of RFC 4648) into their 5-bit positive integer equivalents. Characters that are not in the Base32
- * alphabet but fall within the bounds of the array are translated to -1.
- */
- private static final byte[] DECODE_TABLE = {
- // 0 1 2 3 4 5 6 7 8 9 A B C D E F
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20-2f
- -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, // 30-3f 2-7
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40-4f A-O
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 50-5a P-Z
- };
-
- /**
- * This array is a lookup table that translates 5-bit positive integer index values into their "Base32 Alphabet"
- * equivalents as specified in Table 3 of RFC 4648.
- */
- private static final byte[] ENCODE_TABLE = {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- '2', '3', '4', '5', '6', '7',
- };
-
- /**
- * This array is a lookup table that translates Unicode characters drawn from the "Base32 Hex Alphabet" (as
- * specified in Table 4 of RFC 4648) into their 5-bit positive integer equivalents. Characters that are not in the
- * Base32 Hex alphabet but fall within the bounds of the array are translated to -1.
- */
- private static final byte[] HEX_DECODE_TABLE = {
- // 0 1 2 3 4 5 6 7 8 9 A B C D E F
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20-2f
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 30-3f 2-7
- -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 40-4f A-O
- 25, 26, 27, 28, 29, 30, 31, // 50-57 P-V
- };
-
- /**
- * This array is a lookup table that translates 5-bit positive integer index values into their
- * "Base32 Hex Alphabet" equivalents as specified in Table 4 of RFC 4648.
- */
- private static final byte[] HEX_ENCODE_TABLE = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
- };
-
- /**
- * Mask used to extract 5 bits, used when encoding Base32 bytes
- */
- private static final int MASK_5BITS = 0x1f;
-
- // The static final fields above are used for the original static byte[] methods on Base32.
- // The private member fields below are used with the new streaming approach, which requires
- // some state be preserved between calls of encode() and decode().
-
- /**
- * Place holder for the bytes we're dealing with for our based logic.
- * Bitwise operations store and extract the encoding or decoding from this variable.
- */
-
- /**
- * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
- * decodeSize = {@link #BYTES_PER_ENCODED_BLOCK} - 1 + lineSeparator.length;
- */
- private final int decodeSize;
-
- /**
- * Decode table to use.
- */
- private final byte[] decodeTable;
-
- /**
- * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
- * encodeSize = {@link #BYTES_PER_ENCODED_BLOCK} + lineSeparator.length;
- */
- private final int encodeSize;
-
- /**
- * Encode table to use.
- */
- private final byte[] encodeTable;
-
- /**
- * Line separator for encoding. Not used when decoding. Only used if lineLength > 0.
- */
- private final byte[] lineSeparator;
-
- /**
- * Creates a Base32 codec used for decoding and encoding.
- *
- * When encoding the line length is 0 (no chunking).
- *
- */
- public Base32() {
- this(false);
- }
-
- /**
- * Creates a Base32 codec used for decoding and encoding.
- *
- * When encoding the line length is 0 (no chunking).
- *
- *
- * @param pad byte used as padding byte.
- */
- public Base32(final byte pad) {
- this(false, pad);
- }
-
- /**
- * Creates a Base32 codec used for decoding and encoding.
- *
- * When encoding the line length is 0 (no chunking).
- *
- *
- * @param useHex if {@code true} then use Base32 Hex alphabet
- */
- public Base32(final boolean useHex) {
- this(0, null, useHex, PAD_DEFAULT);
- }
-
- /**
- * Creates a Base32 codec used for decoding and encoding.
- *
- * When encoding the line length is 0 (no chunking).
- *
- *
- * @param useHex if {@code true} then use Base32 Hex alphabet
- * @param pad byte used as padding byte.
- */
- public Base32(final boolean useHex, final byte pad) {
- this(0, null, useHex, pad);
- }
-
- /**
- * Creates a Base32 codec used for decoding and encoding.
- *
- * When encoding the line length is given in the constructor, the line separator is CRLF.
- *
- *
- * @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
- * 8). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
- * decoding.
- */
- public Base32(final int lineLength) {
- this(lineLength, CHUNK_SEPARATOR);
- }
-
- /**
- * Creates a Base32 codec used for decoding and encoding.
- *
- * When encoding the line length and line separator are given in the constructor.
- *
- *
- * Line lengths that aren't multiples of 8 will still essentially end up being multiples of 8 in the encoded data.
- *
- *
- * @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
- * 8). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
- * decoding.
- * @param lineSeparator Each line of encoded data will end with this sequence of bytes.
- * @throws IllegalArgumentException The provided lineSeparator included some Base32 characters. That's not going to work!
- */
- public Base32(final int lineLength, final byte[] lineSeparator) {
- this(lineLength, lineSeparator, false, PAD_DEFAULT);
- }
-
- /**
- * Creates a Base32 / Base32 Hex codec used for decoding and encoding.
- *
- * When encoding the line length and line separator are given in the constructor.
- *
- *
- * Line lengths that aren't multiples of 8 will still essentially end up being multiples of 8 in the encoded data.
- *
- *
- * @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
- * 8). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
- * decoding.
- * @param lineSeparator Each line of encoded data will end with this sequence of bytes.
- * @param useHex if {@code true}, then use Base32 Hex alphabet, otherwise use Base32 alphabet
- * @throws IllegalArgumentException The provided lineSeparator included some Base32 characters. That's not going to work! Or the
- * lineLength > 0 and lineSeparator is null.
- */
- public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex) {
- this(lineLength, lineSeparator, useHex, PAD_DEFAULT);
- }
-
- /**
- * Creates a Base32 / Base32 Hex codec used for decoding and encoding.
- *
- * When encoding the line length and line separator are given in the constructor.
- *
- *
- * Line lengths that aren't multiples of 8 will still essentially end up being multiples of 8 in the encoded data.
- *
- *
- * @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
- * 8). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
- * decoding.
- * @param lineSeparator Each line of encoded data will end with this sequence of bytes.
- * @param useHex if {@code true}, then use Base32 Hex alphabet, otherwise use Base32 alphabet
- * @param pad byte used as padding byte.
- * @throws IllegalArgumentException The provided lineSeparator included some Base32 characters. That's not going to work! Or the
- * lineLength > 0 and lineSeparator is null.
- */
- public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte pad) {
- super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength,
- lineSeparator == null ? 0 : lineSeparator.length, pad);
- if (useHex) {
- this.encodeTable = HEX_ENCODE_TABLE;
- this.decodeTable = HEX_DECODE_TABLE;
- } else {
- this.encodeTable = ENCODE_TABLE;
- this.decodeTable = DECODE_TABLE;
- }
- if (lineLength > 0) {
- if (lineSeparator == null) {
- throw new IllegalArgumentException("lineLength " + lineLength + " > 0, but lineSeparator is null");
- }
- // Must be done after initializing the tables
- if (containsAlphabetOrPad(lineSeparator)) {
- final String sep = StringUtils.newStringUtf8(lineSeparator);
- throw new IllegalArgumentException("lineSeparator must not contain Base32 characters: [" + sep + "]");
- }
- this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length;
- this.lineSeparator = new byte[lineSeparator.length];
- System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
- } else {
- this.encodeSize = BYTES_PER_ENCODED_BLOCK;
- this.lineSeparator = null;
- }
- this.decodeSize = this.encodeSize - 1;
-
- if (isInAlphabet(pad) || isWhiteSpace(pad)) {
- throw new IllegalArgumentException("pad must not be in alphabet or whitespace");
- }
- }
-
- /**
- *
- * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once
- * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1"
- * call is not necessary when decoding, but it doesn't hurt, either.
- *
- *
- * Ignores all non-Base32 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are
- * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in,
- * garbage-out philosophy: it will not check the provided data for validity.
- *
- *
- * @param in byte[] array of ascii data to Base32 decode.
- * @param inPos Position to start reading data from.
- * @param inAvail Amount of bytes available from input for encoding.
- * @param context the context to be used
- *
- * Output is written to {@link Context#buffer} as 8-bit octets, using {@link Context#pos} as the buffer position
- */
- @Override
- void decode(final byte[] in, int inPos, final int inAvail, final Context context) {
- // package protected for access from I/O streams
-
- if (context.eof) {
- return;
- }
- if (inAvail < 0) {
- context.eof = true;
- }
- for (int i = 0; i < inAvail; i++) {
- final byte b = in[inPos++];
- if (b == pad) {
- // We're done.
- context.eof = true;
- break;
- } else {
- final byte[] buffer = ensureBufferSize(decodeSize, context);
- if (b >= 0 && b < this.decodeTable.length) {
- final int result = this.decodeTable[b];
- if (result >= 0) {
- context.modulus = (context.modulus + 1) % BYTES_PER_ENCODED_BLOCK;
- // collect decoded bytes
- context.lbitWorkArea = (context.lbitWorkArea << BITS_PER_ENCODED_BYTE) + result;
- if (context.modulus == 0) { // we can output the 5 bytes
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 32) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 24) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 16) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 8) & MASK_8BITS);
- buffer[context.pos++] = (byte) (context.lbitWorkArea & MASK_8BITS);
- }
- }
- }
- }
- }
-
- // Two forms of EOF as far as Base32 decoder is concerned: actual
- // EOF (-1) and first time '=' character is encountered in stream.
- // This approach makes the '=' padding characters completely optional.
- if (context.eof && context.modulus >= 2) { // if modulus < 2, nothing to do
- final byte[] buffer = ensureBufferSize(decodeSize, context);
-
- // we ignore partial bytes, i.e. only multiples of 8 count
- switch (context.modulus) {
- case 2: // 10 bits, drop 2 and output one byte
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 2) & MASK_8BITS);
- break;
- case 3: // 15 bits, drop 7 and output 1 byte
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 7) & MASK_8BITS);
- break;
- case 4: // 20 bits = 2*8 + 4
- context.lbitWorkArea = context.lbitWorkArea >> 4; // drop 4 bits
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 8) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.lbitWorkArea) & MASK_8BITS);
- break;
- case 5: // 25bits = 3*8 + 1
- context.lbitWorkArea = context.lbitWorkArea >> 1;
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 16) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 8) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.lbitWorkArea) & MASK_8BITS);
- break;
- case 6: // 30bits = 3*8 + 6
- context.lbitWorkArea = context.lbitWorkArea >> 6;
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 16) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 8) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.lbitWorkArea) & MASK_8BITS);
- break;
- case 7: // 35 = 4*8 +3
- context.lbitWorkArea = context.lbitWorkArea >> 3;
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 24) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 16) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 8) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.lbitWorkArea) & MASK_8BITS);
- break;
- default:
- // modulus can be 0-7, and we excluded 0,1 already
- throw new IllegalStateException("Impossible modulus " + context.modulus);
- }
- }
- }
-
- /**
- *
- * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with
- * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, so flush last
- * remaining bytes (if not multiple of 5).
- *
- *
- * @param in byte[] array of binary data to Base32 encode.
- * @param inPos Position to start reading data from.
- * @param inAvail Amount of bytes available from input for encoding.
- * @param context the context to be used
- */
- @Override
- void encode(final byte[] in, int inPos, final int inAvail, final Context context) {
- // package protected for access from I/O streams
-
- if (context.eof) {
- return;
- }
- // inAvail < 0 is how we're informed of EOF in the underlying data we're
- // encoding.
- if (inAvail < 0) {
- context.eof = true;
- if (0 == context.modulus && lineLength == 0) {
- return; // no leftovers to process and not using chunking
- }
- final byte[] buffer = ensureBufferSize(encodeSize, context);
- final int savedPos = context.pos;
- switch (context.modulus) { // % 5
- case 0:
- break;
- case 1: // Only 1 octet; take top 5 bits then remainder
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 3) & MASK_5BITS]; // 8-1*5 = 3
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea << 2) & MASK_5BITS]; // 5-3=2
- buffer[context.pos++] = pad;
- buffer[context.pos++] = pad;
- buffer[context.pos++] = pad;
- buffer[context.pos++] = pad;
- buffer[context.pos++] = pad;
- buffer[context.pos++] = pad;
- break;
- case 2: // 2 octets = 16 bits to use
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 11) & MASK_5BITS]; // 16-1*5 = 11
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 6) & MASK_5BITS]; // 16-2*5 = 6
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 1) & MASK_5BITS]; // 16-3*5 = 1
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea << 4) & MASK_5BITS]; // 5-1 = 4
- buffer[context.pos++] = pad;
- buffer[context.pos++] = pad;
- buffer[context.pos++] = pad;
- buffer[context.pos++] = pad;
- break;
- case 3: // 3 octets = 24 bits to use
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 19) & MASK_5BITS]; // 24-1*5 = 19
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 14) & MASK_5BITS]; // 24-2*5 = 14
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 9) & MASK_5BITS]; // 24-3*5 = 9
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 4) & MASK_5BITS]; // 24-4*5 = 4
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea << 1) & MASK_5BITS]; // 5-4 = 1
- buffer[context.pos++] = pad;
- buffer[context.pos++] = pad;
- buffer[context.pos++] = pad;
- break;
- case 4: // 4 octets = 32 bits to use
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 27) & MASK_5BITS]; // 32-1*5 = 27
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 22) & MASK_5BITS]; // 32-2*5 = 22
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 17) & MASK_5BITS]; // 32-3*5 = 17
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 12) & MASK_5BITS]; // 32-4*5 = 12
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 7) & MASK_5BITS]; // 32-5*5 = 7
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 2) & MASK_5BITS]; // 32-6*5 = 2
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea << 3) & MASK_5BITS]; // 5-2 = 3
- buffer[context.pos++] = pad;
- break;
- default:
- throw new IllegalStateException("Impossible modulus " + context.modulus);
- }
- context.currentLinePos += context.pos - savedPos; // keep track of current line position
- // if currentPos == 0 we are at the start of a line, so don't add CRLF
- if (lineLength > 0 && context.currentLinePos > 0) { // add chunk separator if required
- System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
- context.pos += lineSeparator.length;
- }
- } else {
- for (int i = 0; i < inAvail; i++) {
- final byte[] buffer = ensureBufferSize(encodeSize, context);
- context.modulus = (context.modulus + 1) % BYTES_PER_UNENCODED_BLOCK;
- int b = in[inPos++];
- if (b < 0) {
- b += 256;
- }
- context.lbitWorkArea = (context.lbitWorkArea << 8) + b; // BITS_PER_BYTE
- if (0 == context.modulus) { // we have enough bytes to create our output
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 35) & MASK_5BITS];
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 30) & MASK_5BITS];
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 25) & MASK_5BITS];
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 20) & MASK_5BITS];
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 15) & MASK_5BITS];
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 10) & MASK_5BITS];
- buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 5) & MASK_5BITS];
- buffer[context.pos++] = encodeTable[(int) context.lbitWorkArea & MASK_5BITS];
- context.currentLinePos += BYTES_PER_ENCODED_BLOCK;
- if (lineLength > 0 && lineLength <= context.currentLinePos) {
- System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
- context.pos += lineSeparator.length;
- context.currentLinePos = 0;
- }
- }
- }
- }
- }
-
- /**
- * Returns whether or not the {@code octet} is in the Base32 alphabet.
- *
- * @param octet The value to test
- * @return {@code true} if the value is defined in the the Base32 alphabet {@code false} otherwise.
- */
- @Override
- public boolean isInAlphabet(final byte octet) {
- return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
- }
-}
diff --git a/src/org/apache/commons/codec/binary/Base32InputStream.java b/src/org/apache/commons/codec/binary/Base32InputStream.java
deleted file mode 100644
index 77979fbc..00000000
--- a/src/org/apache/commons/codec/binary/Base32InputStream.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-import java.io.InputStream;
-
-/**
- * Provides Base32 encoding and decoding in a streaming fashion (unlimited size). When encoding the default lineLength
- * is 76 characters and the default lineEnding is CRLF, but these can be overridden by using the appropriate
- * constructor.
- *
- * The default behaviour of the Base32InputStream is to DECODE, whereas the default behaviour of the Base32OutputStream
- * is to ENCODE, but this behaviour can be overridden by using a different constructor.
- *
- *
- * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode
- * character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc).
- *
- *
- * @version $Id$
- * @see RFC 4648
- * @since 1.5
- */
-public class Base32InputStream extends BaseNCodecInputStream {
-
- /**
- * Creates a Base32InputStream such that all data read is Base32-decoded from the original provided InputStream.
- *
- * @param in InputStream to wrap.
- */
- public Base32InputStream(final InputStream in) {
- this(in, false);
- }
-
- /**
- * Creates a Base32InputStream such that all data read is either Base32-encoded or Base32-decoded from the original
- * provided InputStream.
- *
- * @param in InputStream to wrap.
- * @param doEncode true if we should encode all data read from us, false if we should decode.
- */
- public Base32InputStream(final InputStream in, final boolean doEncode) {
- super(in, new Base32(false), doEncode);
- }
-
- /**
- * Creates a Base32InputStream such that all data read is either Base32-encoded or Base32-decoded from the original
- * provided InputStream.
- *
- * @param in InputStream to wrap.
- * @param doEncode true if we should encode all data read from us, false if we should decode.
- * @param lineLength If doEncode is true, each line of encoded data will contain lineLength characters (rounded down to
- * nearest multiple of 4). If lineLength <= 0, the encoded data is not divided into lines. If doEncode
- * is false, lineLength is ignored.
- * @param lineSeparator If doEncode is true, each line of encoded data will be terminated with this byte sequence (e.g. \r\n).
- * If lineLength <= 0, the lineSeparator is not used. If doEncode is false lineSeparator is ignored.
- */
- public Base32InputStream(final InputStream in, final boolean doEncode,
- final int lineLength, final byte[] lineSeparator) {
- super(in, new Base32(lineLength, lineSeparator), doEncode);
- }
-}
diff --git a/src/org/apache/commons/codec/binary/Base32OutputStream.java b/src/org/apache/commons/codec/binary/Base32OutputStream.java
deleted file mode 100644
index 377f263e..00000000
--- a/src/org/apache/commons/codec/binary/Base32OutputStream.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-import java.io.OutputStream;
-
-/**
- * Provides Base32 encoding and decoding in a streaming fashion (unlimited size). When encoding the default lineLength
- * is 76 characters and the default lineEnding is CRLF, but these can be overridden by using the appropriate
- * constructor.
- *
- * The default behaviour of the Base32OutputStream is to ENCODE, whereas the default behaviour of the Base32InputStream
- * is to DECODE. But this behaviour can be overridden by using a different constructor.
- *
- *
- * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode
- * character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc).
- *
- *
- * Note: It is mandatory to close the stream after the last byte has been written to it, otherwise the
- * final padding will be omitted and the resulting data will be incomplete/inconsistent.
- *
- *
- * @version $Id$
- * @see RFC 4648
- * @since 1.5
- */
-public class Base32OutputStream extends BaseNCodecOutputStream {
-
- /**
- * Creates a Base32OutputStream such that all data written is Base32-encoded to the original provided OutputStream.
- *
- * @param out OutputStream to wrap.
- */
- public Base32OutputStream(final OutputStream out) {
- this(out, true);
- }
-
- /**
- * Creates a Base32OutputStream such that all data written is either Base32-encoded or Base32-decoded to the
- * original provided OutputStream.
- *
- * @param out OutputStream to wrap.
- * @param doEncode true if we should encode all data written to us, false if we should decode.
- */
- public Base32OutputStream(final OutputStream out, final boolean doEncode) {
- super(out, new Base32(false), doEncode);
- }
-
- /**
- * Creates a Base32OutputStream such that all data written is either Base32-encoded or Base32-decoded to the
- * original provided OutputStream.
- *
- * @param out OutputStream to wrap.
- * @param doEncode true if we should encode all data written to us, false if we should decode.
- * @param lineLength If doEncode is true, each line of encoded data will contain lineLength characters (rounded down to
- * nearest multiple of 4). If lineLength <= 0, the encoded data is not divided into lines. If doEncode
- * is false, lineLength is ignored.
- * @param lineSeparator If doEncode is true, each line of encoded data will be terminated with this byte sequence (e.g. \r\n).
- * If lineLength <= 0, the lineSeparator is not used. If doEncode is false lineSeparator is ignored.
- */
- public Base32OutputStream(final OutputStream out, final boolean doEncode,
- final int lineLength, final byte[] lineSeparator) {
- super(out, new Base32(lineLength, lineSeparator), doEncode);
- }
-}
diff --git a/src/org/apache/commons/codec/binary/Base64.java b/src/org/apache/commons/codec/binary/Base64.java
deleted file mode 100644
index f6fe508d..00000000
--- a/src/org/apache/commons/codec/binary/Base64.java
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-import java.math.BigInteger;
-
-/**
- * Provides Base64 encoding and decoding as defined by RFC 2045 .
- *
- *
- * This class implements section 6.8. Base64 Content-Transfer-Encoding from RFC 2045 Multipurpose
- * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies by Freed and Borenstein.
- *
- *
- * The class can be parameterized in the following manner with various constructors:
- *
- *
- * URL-safe mode: Default off.
- * Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of
- * 4 in the encoded data.
- * Line separator: Default is CRLF ("\r\n")
- *
- *
- * The URL-safe parameter is only applied to encode operations. Decoding seamlessly handles both modes.
- *
- *
- * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only
- * encode/decode character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252,
- * UTF-8, etc).
- *
- *
- * This class is thread-safe.
- *
- *
- * @version $Id$
- * @see RFC 2045
- * @since 1.0
- */
-public class Base64 extends BaseNCodec {
-
- /**
- * BASE32 characters are 6 bits in length.
- * They are formed by taking a block of 3 octets to form a 24-bit string,
- * which is converted into 4 BASE64 characters.
- */
- private static final int BITS_PER_ENCODED_BYTE = 6;
- private static final int BYTES_PER_UNENCODED_BLOCK = 3;
- private static final int BYTES_PER_ENCODED_BLOCK = 4;
-
- /**
- * Chunk separator per RFC 2045 section 2.1.
- *
- *
- * N.B. The next major release may break compatibility and make this field private.
- *
- *
- * @see RFC 2045 section 2.1
- */
- static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
-
- /**
- * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet"
- * equivalents as specified in Table 1 of RFC 2045.
- *
- * Thanks to "commons" project in ws.apache.org for this code.
- * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
- */
- private static final byte[] STANDARD_ENCODE_TABLE = {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
- };
-
- /**
- * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and /
- * changed to - and _ to make the encoded Base64 results more URL-SAFE.
- * This table is only used when the Base64's mode is set to URL-SAFE.
- */
- private static final byte[] URL_SAFE_ENCODE_TABLE = {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
- };
-
- /**
- * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified
- * in Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64
- * alphabet but fall within the bounds of the array are translated to -1.
- *
- * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both
- * URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit).
- *
- * Thanks to "commons" project in ws.apache.org for this code.
- * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
- */
- private static final byte[] DECODE_TABLE = {
- // 0 1 2 3 4 5 6 7 8 9 A B C D E F
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, // 20-2f + - /
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 30-3f 0-9
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40-4f A-O
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, // 50-5f P-Z _
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6f a-o
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 // 70-7a p-z
- };
-
- /**
- * Base64 uses 6-bit fields.
- */
- /**
- * Mask used to extract 6 bits, used when encoding
- */
- private static final int MASK_6BITS = 0x3f;
-
- // The static final fields above are used for the original static byte[] methods on Base64.
- // The private member fields below are used with the new streaming approach, which requires
- // some state be preserved between calls of encode() and decode().
-
- /**
- * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able
- * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch
- * between the two modes.
- */
- private final byte[] encodeTable;
-
- // Only one decode table currently; keep for consistency with Base32 code
- private final byte[] decodeTable = DECODE_TABLE;
-
- /**
- * Line separator for encoding. Not used when decoding. Only used if lineLength > 0.
- */
- private final byte[] lineSeparator;
-
- /**
- * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
- * decodeSize = 3 + lineSeparator.length;
- */
- private final int decodeSize;
-
- /**
- * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
- * encodeSize = 4 + lineSeparator.length;
- */
- private final int encodeSize;
-
- /**
- * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
- *
- * When encoding the line length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE.
- *
- *
- *
- * When decoding all variants are supported.
- *
- */
- public Base64() {
- this(0);
- }
-
- /**
- * Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode.
- *
- * When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE.
- *
- *
- *
- * When decoding all variants are supported.
- *
- *
- * @param urlSafe if true
, URL-safe encoding is used. In most cases this should be set to
- * false
.
- * @since 1.4
- */
- public Base64(final boolean urlSafe) {
- this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe);
- }
-
- /**
- * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
- *
- * When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is
- * STANDARD_ENCODE_TABLE.
- *
- *
- * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
- *
- *
- * When decoding all variants are supported.
- *
- *
- * @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
- * 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
- * decoding.
- * @since 1.4
- */
- public Base64(final int lineLength) {
- this(lineLength, CHUNK_SEPARATOR);
- }
-
- /**
- * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
- *
- * When encoding the line length and line separator are given in the constructor, and the encoding table is
- * STANDARD_ENCODE_TABLE.
- *
- *
- * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
- *
- *
- * When decoding all variants are supported.
- *
- *
- * @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
- * 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
- * decoding.
- * @param lineSeparator Each line of encoded data will end with this sequence of bytes.
- * @throws IllegalArgumentException Thrown when the provided lineSeparator included some base64 characters.
- * @since 1.4
- */
- public Base64(final int lineLength, final byte[] lineSeparator) {
- this(lineLength, lineSeparator, false);
- }
-
- /**
- * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
- *
- * When encoding the line length and line separator are given in the constructor, and the encoding table is
- * STANDARD_ENCODE_TABLE.
- *
- *
- * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
- *
- *
- * When decoding all variants are supported.
- *
- *
- * @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
- * 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
- * decoding.
- * @param lineSeparator Each line of encoded data will end with this sequence of bytes.
- * @param urlSafe Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode
- * operations. Decoding seamlessly handles both modes.
- * Note: no padding is added when using the URL-safe alphabet.
- * @throws IllegalArgumentException The provided lineSeparator included some base64 characters. That's not going to work!
- * @since 1.4
- */
- public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) {
- super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK,
- lineLength,
- lineSeparator == null ? 0 : lineSeparator.length);
- // TODO could be simplified if there is no requirement to reject invalid line sep when length <=0
- // @see test case Base64Test.testConstructors()
- if (lineSeparator != null) {
- if (containsAlphabetOrPad(lineSeparator)) {
- final String sep = StringUtils.newStringUtf8(lineSeparator);
- throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]");
- }
- if (lineLength > 0) { // null line-sep forces no chunking rather than throwing IAE
- this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length;
- this.lineSeparator = new byte[lineSeparator.length];
- System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
- } else {
- this.encodeSize = BYTES_PER_ENCODED_BLOCK;
- this.lineSeparator = null;
- }
- } else {
- this.encodeSize = BYTES_PER_ENCODED_BLOCK;
- this.lineSeparator = null;
- }
- this.decodeSize = this.encodeSize - 1;
- this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
- }
-
- /**
- * Returns our current encode mode. True if we're URL-SAFE, false otherwise.
- *
- * @return true if we're in URL-SAFE mode, false otherwise.
- * @since 1.4
- */
- public boolean isUrlSafe() {
- return this.encodeTable == URL_SAFE_ENCODE_TABLE;
- }
-
- /**
- *
- * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with
- * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, to flush last
- * remaining bytes (if not multiple of 3).
- *
- * Note: no padding is added when encoding using the URL-safe alphabet.
- *
- * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
- * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
- *
- *
- * @param in byte[] array of binary data to base64 encode.
- * @param inPos Position to start reading data from.
- * @param inAvail Amount of bytes available from input for encoding.
- * @param context the context to be used
- */
- @Override
- void encode(final byte[] in, int inPos, final int inAvail, final Context context) {
- if (context.eof) {
- return;
- }
- // inAvail < 0 is how we're informed of EOF in the underlying data we're
- // encoding.
- if (inAvail < 0) {
- context.eof = true;
- if (0 == context.modulus && lineLength == 0) {
- return; // no leftovers to process and not using chunking
- }
- final byte[] buffer = ensureBufferSize(encodeSize, context);
- final int savedPos = context.pos;
- switch (context.modulus) { // 0-2
- case 0: // nothing to do here
- break;
- case 1: // 8 bits = 6 + 2
- // top 6 bits:
- buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 2) & MASK_6BITS];
- // remaining 2:
- buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 4) & MASK_6BITS];
- // URL-SAFE skips the padding to further reduce size.
- if (encodeTable == STANDARD_ENCODE_TABLE) {
- buffer[context.pos++] = pad;
- buffer[context.pos++] = pad;
- }
- break;
-
- case 2: // 16 bits = 6 + 6 + 4
- buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 10) & MASK_6BITS];
- buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 4) & MASK_6BITS];
- buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 2) & MASK_6BITS];
- // URL-SAFE skips the padding to further reduce size.
- if (encodeTable == STANDARD_ENCODE_TABLE) {
- buffer[context.pos++] = pad;
- }
- break;
- default:
- throw new IllegalStateException("Impossible modulus " + context.modulus);
- }
- context.currentLinePos += context.pos - savedPos; // keep track of current line position
- // if currentPos == 0 we are at the start of a line, so don't add CRLF
- if (lineLength > 0 && context.currentLinePos > 0) {
- System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
- context.pos += lineSeparator.length;
- }
- } else {
- for (int i = 0; i < inAvail; i++) {
- final byte[] buffer = ensureBufferSize(encodeSize, context);
- context.modulus = (context.modulus + 1) % BYTES_PER_UNENCODED_BLOCK;
- int b = in[inPos++];
- if (b < 0) {
- b += 256;
- }
- context.ibitWorkArea = (context.ibitWorkArea << 8) + b; // BITS_PER_BYTE
- if (0 == context.modulus) { // 3 bytes = 24 bits = 4 * 6 bits to extract
- buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 18) & MASK_6BITS];
- buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 12) & MASK_6BITS];
- buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 6) & MASK_6BITS];
- buffer[context.pos++] = encodeTable[context.ibitWorkArea & MASK_6BITS];
- context.currentLinePos += BYTES_PER_ENCODED_BLOCK;
- if (lineLength > 0 && lineLength <= context.currentLinePos) {
- System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
- context.pos += lineSeparator.length;
- context.currentLinePos = 0;
- }
- }
- }
- }
- }
-
- /**
- *
- * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once
- * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1"
- * call is not necessary when decoding, but it doesn't hurt, either.
- *
- *
- * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are
- * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in,
- * garbage-out philosophy: it will not check the provided data for validity.
- *
- *
- * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
- * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
- *
- *
- * @param in byte[] array of ascii data to base64 decode.
- * @param inPos Position to start reading data from.
- * @param inAvail Amount of bytes available from input for encoding.
- * @param context the context to be used
- */
- @Override
- void decode(final byte[] in, int inPos, final int inAvail, final Context context) {
- if (context.eof) {
- return;
- }
- if (inAvail < 0) {
- context.eof = true;
- }
- for (int i = 0; i < inAvail; i++) {
- final byte[] buffer = ensureBufferSize(decodeSize, context);
- final byte b = in[inPos++];
- if (b == pad) {
- // We're done.
- context.eof = true;
- break;
- } else {
- if (b >= 0 && b < DECODE_TABLE.length) {
- final int result = DECODE_TABLE[b];
- if (result >= 0) {
- context.modulus = (context.modulus + 1) % BYTES_PER_ENCODED_BLOCK;
- context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result;
- if (context.modulus == 0) {
- buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 16) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
- buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS);
- }
- }
- }
- }
- }
-
- // Two forms of EOF as far as base64 decoder is concerned: actual
- // EOF (-1) and first time '=' character is encountered in stream.
- // This approach makes the '=' padding characters completely optional.
- if (context.eof && context.modulus != 0) {
- final byte[] buffer = ensureBufferSize(decodeSize, context);
-
- // We have some spare bits remaining
- // Output all whole multiples of 8 bits and ignore the rest
- switch (context.modulus) {
-// case 0 : // impossible, as excluded above
- case 1: // 6 bits - ignore entirely
- // TODO not currently tested; perhaps it is impossible?
- break;
- case 2: // 12 bits = 8 + 4
- context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits
- buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
- break;
- case 3: // 18 bits = 8 + 8 + 2
- context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits
- buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
- buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
- break;
- default:
- throw new IllegalStateException("Impossible modulus " + context.modulus);
- }
- }
- }
-
- /**
- * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the
- * method treats whitespace as valid.
- *
- * @param arrayOctet byte array to test
- * @return true
if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
- * false
, otherwise
- * @deprecated 1.5 Use {@link #isBase64(byte[])}, will be removed in 2.0.
- */
- @Deprecated
- public static boolean isArrayByteBase64(final byte[] arrayOctet) {
- return isBase64(arrayOctet);
- }
-
- /**
- * Returns whether or not the octet
is in the base 64 alphabet.
- *
- * @param octet The value to test
- * @return true
if the value is defined in the the base 64 alphabet, false
otherwise.
- * @since 1.4
- */
- public static boolean isBase64(final byte octet) {
- return octet == PAD_DEFAULT || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1);
- }
-
- /**
- * Tests a given String to see if it contains only valid characters within the Base64 alphabet. Currently the
- * method treats whitespace as valid.
- *
- * @param base64 String to test
- * @return true
if all characters in the String are valid characters in the Base64 alphabet or if
- * the String is empty; false
, otherwise
- * @since 1.5
- */
- public static boolean isBase64(final String base64) {
- return isBase64(StringUtils.getBytesUtf8(base64));
- }
-
- /**
- * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the
- * method treats whitespace as valid.
- *
- * @param arrayOctet byte array to test
- * @return true
if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
- * false
, otherwise
- * @since 1.5
- */
- public static boolean isBase64(final byte[] arrayOctet) {
- for (int i = 0; i < arrayOctet.length; i++) {
- if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Encodes binary data using the base64 algorithm but does not chunk the output.
- *
- * @param binaryData binary data to encode
- * @return byte[] containing Base64 characters in their UTF-8 representation.
- */
- public static byte[] encodeBase64(final byte[] binaryData) {
- return encodeBase64(binaryData, false);
- }
-
- /**
- * Encodes binary data using the base64 algorithm but does not chunk the output.
- *
- * NOTE: We changed the behaviour of this method from multi-line chunking (commons-codec-1.4) to
- * single-line non-chunking (commons-codec-1.5).
- *
- * @param binaryData binary data to encode
- * @return String containing Base64 characters.
- * @since 1.4 (NOTE: 1.4 chunked the output, whereas 1.5 does not).
- */
- public static String encodeBase64String(final byte[] binaryData) {
- return StringUtils.newStringUtf8(encodeBase64(binaryData, false));
- }
-
- /**
- * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
- * url-safe variation emits - and _ instead of + and / characters.
- * Note: no padding is added.
- *
- * @param binaryData binary data to encode
- * @return byte[] containing Base64 characters in their UTF-8 representation.
- * @since 1.4
- */
- public static byte[] encodeBase64URLSafe(final byte[] binaryData) {
- return encodeBase64(binaryData, false, true);
- }
-
- /**
- * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
- * url-safe variation emits - and _ instead of + and / characters.
- * Note: no padding is added.
- *
- * @param binaryData binary data to encode
- * @return String containing Base64 characters
- * @since 1.4
- */
- public static String encodeBase64URLSafeString(final byte[] binaryData) {
- return StringUtils.newStringUtf8(encodeBase64(binaryData, false, true));
- }
-
- /**
- * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks
- *
- * @param binaryData binary data to encode
- * @return Base64 characters chunked in 76 character blocks
- */
- public static byte[] encodeBase64Chunked(final byte[] binaryData) {
- return encodeBase64(binaryData, true);
- }
-
- /**
- * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
- *
- * @param binaryData Array containing binary data to encode.
- * @param isChunked if true
this encoder will chunk the base64 output into 76 character blocks
- * @return Base64-encoded data.
- * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
- */
- public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked) {
- return encodeBase64(binaryData, isChunked, false);
- }
-
- /**
- * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
- *
- * @param binaryData Array containing binary data to encode.
- * @param isChunked if true
this encoder will chunk the base64 output into 76 character blocks
- * @param urlSafe if true
this encoder will emit - and _ instead of the usual + and / characters.
- * Note: no padding is added when encoding using the URL-safe alphabet.
- * @return Base64-encoded data.
- * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
- * @since 1.4
- */
- public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe) {
- return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE);
- }
-
- /**
- * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
- *
- * @param binaryData Array containing binary data to encode.
- * @param isChunked if true
this encoder will chunk the base64 output into 76 character blocks
- * @param urlSafe if true
this encoder will emit - and _ instead of the usual + and / characters.
- * Note: no padding is added when encoding using the URL-safe alphabet.
- * @param maxResultSize The maximum result size to accept.
- * @return Base64-encoded data.
- * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than maxResultSize
- * @since 1.4
- */
- public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked,
- final boolean urlSafe, final int maxResultSize) {
- if (binaryData == null || binaryData.length == 0) {
- return binaryData;
- }
-
- // Create this so can use the super-class method
- // Also ensures that the same roundings are performed by the ctor and the code
- final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe);
- final long len = b64.getEncodedLength(binaryData);
- if (len > maxResultSize) {
- throw new IllegalArgumentException("Input array too big, the output array would be bigger (" +
- len +
- ") than the specified maximum size of " +
- maxResultSize);
- }
-
- return b64.encode(binaryData);
- }
-
- /**
- * Decodes a Base64 String into octets.
- *
- * Note: this method seamlessly handles data encoded in URL-safe or normal mode.
- *
- *
- * @param base64String String containing Base64 data
- * @return Array containing decoded data.
- * @since 1.4
- */
- public static byte[] decodeBase64(final String base64String) {
- return new Base64().decode(base64String);
- }
-
- /**
- * Decodes Base64 data into octets.
- *
- * Note: this method seamlessly handles data encoded in URL-safe or normal mode.
- *
- *
- * @param base64Data Byte array containing Base64 data
- * @return Array containing decoded data.
- */
- public static byte[] decodeBase64(final byte[] base64Data) {
- return new Base64().decode(base64Data);
- }
-
- // Implementation of the Encoder Interface
-
- // Implementation of integer encoding used for crypto
-
- /**
- * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature.
- *
- * @param pArray a byte array containing base64 character data
- * @return A BigInteger
- * @since 1.4
- */
- public static BigInteger decodeInteger(final byte[] pArray) {
- return new BigInteger(1, decodeBase64(pArray));
- }
-
- /**
- * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature.
- *
- * @param bigInt a BigInteger
- * @return A byte array containing base64 character data
- * @throws NullPointerException if null is passed in
- * @since 1.4
- */
- public static byte[] encodeInteger(final BigInteger bigInt) {
- if (bigInt == null) {
- throw new NullPointerException("encodeInteger called with null parameter");
- }
- return encodeBase64(toIntegerBytes(bigInt), false);
- }
-
- /**
- * Returns a byte-array representation of a BigInteger
without sign bit.
- *
- * @param bigInt BigInteger
to be converted
- * @return a byte array representation of the BigInteger parameter
- */
- static byte[] toIntegerBytes(final BigInteger bigInt) {
- int bitlen = bigInt.bitLength();
- // round bitlen
- bitlen = ((bitlen + 7) >> 3) << 3;
- final byte[] bigBytes = bigInt.toByteArray();
-
- if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) {
- return bigBytes;
- }
- // set up params for copying everything but sign bit
- int startSrc = 0;
- int len = bigBytes.length;
-
- // if bigInt is exactly byte-aligned, just skip signbit in copy
- if ((bigInt.bitLength() % 8) == 0) {
- startSrc = 1;
- len--;
- }
- final int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec
- final byte[] resizedBytes = new byte[bitlen / 8];
- System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len);
- return resizedBytes;
- }
-
- /**
- * Returns whether or not the octet
is in the Base64 alphabet.
- *
- * @param octet The value to test
- * @return true
if the value is defined in the the Base64 alphabet false
otherwise.
- */
- @Override
- protected boolean isInAlphabet(final byte octet) {
- return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
- }
-}
diff --git a/src/org/apache/commons/codec/binary/Base64InputStream.java b/src/org/apache/commons/codec/binary/Base64InputStream.java
deleted file mode 100644
index 448eb30e..00000000
--- a/src/org/apache/commons/codec/binary/Base64InputStream.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-import java.io.InputStream;
-
-/**
- * Provides Base64 encoding and decoding in a streaming fashion (unlimited size). When encoding the default lineLength
- * is 76 characters and the default lineEnding is CRLF, but these can be overridden by using the appropriate
- * constructor.
- *
- * The default behaviour of the Base64InputStream is to DECODE, whereas the default behaviour of the Base64OutputStream
- * is to ENCODE, but this behaviour can be overridden by using a different constructor.
- *
- *
- * This class implements section 6.8. Base64 Content-Transfer-Encoding from RFC 2045 Multipurpose
- * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies by Freed and Borenstein.
- *
- *
- * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode
- * character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc).
- *
- *
- * @version $Id$
- * @see RFC 2045
- * @since 1.4
- */
-public class Base64InputStream extends BaseNCodecInputStream {
-
- /**
- * Creates a Base64InputStream such that all data read is Base64-decoded from the original provided InputStream.
- *
- * @param in InputStream to wrap.
- */
- public Base64InputStream(final InputStream in) {
- this(in, false);
- }
-
- /**
- * Creates a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original
- * provided InputStream.
- *
- * @param in InputStream to wrap.
- * @param doEncode true if we should encode all data read from us, false if we should decode.
- */
- public Base64InputStream(final InputStream in, final boolean doEncode) {
- super(in, new Base64(false), doEncode);
- }
-
- /**
- * Creates a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original
- * provided InputStream.
- *
- * @param in InputStream to wrap.
- * @param doEncode true if we should encode all data read from us, false if we should decode.
- * @param lineLength If doEncode is true, each line of encoded data will contain lineLength characters (rounded down to
- * nearest multiple of 4). If lineLength <= 0, the encoded data is not divided into lines. If doEncode
- * is false, lineLength is ignored.
- * @param lineSeparator If doEncode is true, each line of encoded data will be terminated with this byte sequence (e.g. \r\n).
- * If lineLength <= 0, the lineSeparator is not used. If doEncode is false lineSeparator is ignored.
- */
- public Base64InputStream(final InputStream in, final boolean doEncode,
- final int lineLength, final byte[] lineSeparator) {
- super(in, new Base64(lineLength, lineSeparator), doEncode);
- }
-}
diff --git a/src/org/apache/commons/codec/binary/Base64OutputStream.java b/src/org/apache/commons/codec/binary/Base64OutputStream.java
deleted file mode 100644
index 5acbc130..00000000
--- a/src/org/apache/commons/codec/binary/Base64OutputStream.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-import java.io.OutputStream;
-
-/**
- * Provides Base64 encoding and decoding in a streaming fashion (unlimited size). When encoding the default lineLength
- * is 76 characters and the default lineEnding is CRLF, but these can be overridden by using the appropriate
- * constructor.
- *
- * The default behaviour of the Base64OutputStream is to ENCODE, whereas the default behaviour of the Base64InputStream
- * is to DECODE. But this behaviour can be overridden by using a different constructor.
- *
- *
- * This class implements section 6.8. Base64 Content-Transfer-Encoding from RFC 2045 Multipurpose
- * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies by Freed and Borenstein.
- *
- *
- * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode
- * character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc).
- *
- *
- * Note: It is mandatory to close the stream after the last byte has been written to it, otherwise the
- * final padding will be omitted and the resulting data will be incomplete/inconsistent.
- *
- *
- * @version $Id$
- * @see RFC 2045
- * @since 1.4
- */
-public class Base64OutputStream extends BaseNCodecOutputStream {
-
- /**
- * Creates a Base64OutputStream such that all data written is Base64-encoded to the original provided OutputStream.
- *
- * @param out OutputStream to wrap.
- */
- public Base64OutputStream(final OutputStream out) {
- this(out, true);
- }
-
- /**
- * Creates a Base64OutputStream such that all data written is either Base64-encoded or Base64-decoded to the
- * original provided OutputStream.
- *
- * @param out OutputStream to wrap.
- * @param doEncode true if we should encode all data written to us, false if we should decode.
- */
- public Base64OutputStream(final OutputStream out, final boolean doEncode) {
- super(out, new Base64(false), doEncode);
- }
-
- /**
- * Creates a Base64OutputStream such that all data written is either Base64-encoded or Base64-decoded to the
- * original provided OutputStream.
- *
- * @param out OutputStream to wrap.
- * @param doEncode true if we should encode all data written to us, false if we should decode.
- * @param lineLength If doEncode is true, each line of encoded data will contain lineLength characters (rounded down to
- * nearest multiple of 4). If lineLength <= 0, the encoded data is not divided into lines. If doEncode
- * is false, lineLength is ignored.
- * @param lineSeparator If doEncode is true, each line of encoded data will be terminated with this byte sequence (e.g. \r\n).
- * If lineLength <= 0, the lineSeparator is not used. If doEncode is false lineSeparator is ignored.
- */
- public Base64OutputStream(final OutputStream out, final boolean doEncode,
- final int lineLength, final byte[] lineSeparator) {
- super(out, new Base64(lineLength, lineSeparator), doEncode);
- }
-}
diff --git a/src/org/apache/commons/codec/binary/BaseNCodec.java b/src/org/apache/commons/codec/binary/BaseNCodec.java
deleted file mode 100644
index cbdd79c5..00000000
--- a/src/org/apache/commons/codec/binary/BaseNCodec.java
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-import java.util.Arrays;
-
-import org.apache.commons.codec.BinaryDecoder;
-import org.apache.commons.codec.BinaryEncoder;
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.EncoderException;
-
-/**
- * Abstract superclass for Base-N encoders and decoders.
- *
- *
- * This class is thread-safe.
- *
- *
- * @version $Id$
- */
-public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
-
- /**
- * Holds thread context so classes can be thread-safe.
- *
- * This class is not itself thread-safe; each thread must allocate its own copy.
- *
- * @since 1.7
- */
- static class Context {
-
- /**
- * Place holder for the bytes we're dealing with for our based logic.
- * Bitwise operations store and extract the encoding or decoding from this variable.
- */
- int ibitWorkArea;
-
- /**
- * Place holder for the bytes we're dealing with for our based logic.
- * Bitwise operations store and extract the encoding or decoding from this variable.
- */
- long lbitWorkArea;
-
- /**
- * Buffer for streaming.
- */
- byte[] buffer;
-
- /**
- * Position where next character should be written in the buffer.
- */
- int pos;
-
- /**
- * Position where next character should be read from the buffer.
- */
- int readPos;
-
- /**
- * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this object becomes useless,
- * and must be thrown away.
- */
- boolean eof;
-
- /**
- * Variable tracks how many characters have been written to the current line. Only used when encoding. We use
- * it to make sure each encoded line never goes beyond lineLength (if lineLength > 0).
- */
- int currentLinePos;
-
- /**
- * Writes to the buffer only occur after every 3/5 reads when encoding, and every 4/8 reads when decoding. This
- * variable helps track that.
- */
- int modulus;
-
- Context() {
- }
-
- /**
- * Returns a String useful for debugging (especially within a debugger.)
- *
- * @return a String useful for debugging.
- */
- @SuppressWarnings("boxing") // OK to ignore boxing here
- @Override
- public String toString() {
- return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " +
- "modulus=%s, pos=%s, readPos=%s]", this.getClass().getSimpleName(), Arrays.toString(buffer),
- currentLinePos, eof, ibitWorkArea, lbitWorkArea, modulus, pos, readPos);
- }
- }
-
- /**
- * EOF
- *
- * @since 1.7
- */
- static final int EOF = -1;
-
- /**
- * MIME chunk size per RFC 2045 section 6.8.
- *
- *
- * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
- * equal signs.
- *
- *
- * @see RFC 2045 section 6.8
- */
- public static final int MIME_CHUNK_SIZE = 76;
-
- /**
- * PEM chunk size per RFC 1421 section 4.3.2.4.
- *
- *
- * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
- * equal signs.
- *
- *
- * @see RFC 1421 section 4.3.2.4
- */
- public static final int PEM_CHUNK_SIZE = 64;
-
- private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;
-
- /**
- * Defines the default buffer size - currently {@value}
- * - must be large enough for at least one encoded block+separator
- */
- private static final int DEFAULT_BUFFER_SIZE = 8192;
-
- /**
- * Mask used to extract 8 bits, used in decoding bytes
- */
- protected static final int MASK_8BITS = 0xff;
-
- /**
- * Byte used to pad output.
- */
- protected static final byte PAD_DEFAULT = '='; // Allow static access to default
-
- /**
- * @deprecated Use {@link #pad}. Will be removed in 2.0.
- */
- @Deprecated
- protected final byte PAD = PAD_DEFAULT; // instance variable just in case it needs to vary later
-
- protected final byte pad; // instance variable just in case it needs to vary later
-
- /**
- * Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32
- */
- private final int unencodedBlockSize;
-
- /**
- * Number of bytes in each full block of encoded data, e.g. 3 for Base64 and 8 for Base32
- */
- private final int encodedBlockSize;
-
- /**
- * Chunksize for encoding. Not used when decoding.
- * A value of zero or less implies no chunking of the encoded data.
- * Rounded down to nearest multiple of encodedBlockSize.
- */
- protected final int lineLength;
-
- /**
- * Size of chunk separator. Not used unless {@link #lineLength} > 0.
- */
- private final int chunkSeparatorLength;
-
- /**
- * Note lineLength
is rounded down to the nearest multiple of {@link #encodedBlockSize}
- * If chunkSeparatorLength
is zero, then chunking is disabled.
- *
- * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3)
- * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4)
- * @param lineLength if > 0, use chunking with a length lineLength
- * @param chunkSeparatorLength the chunk separator length, if relevant
- */
- protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize,
- final int lineLength, final int chunkSeparatorLength) {
- this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, PAD_DEFAULT);
- }
-
- /**
- * Note lineLength
is rounded down to the nearest multiple of {@link #encodedBlockSize}
- * If chunkSeparatorLength
is zero, then chunking is disabled.
- *
- * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3)
- * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4)
- * @param lineLength if > 0, use chunking with a length lineLength
- * @param chunkSeparatorLength the chunk separator length, if relevant
- * @param pad byte used as padding byte.
- */
- protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize,
- final int lineLength, final int chunkSeparatorLength, final byte pad) {
- this.unencodedBlockSize = unencodedBlockSize;
- this.encodedBlockSize = encodedBlockSize;
- final boolean useChunking = lineLength > 0 && chunkSeparatorLength > 0;
- this.lineLength = useChunking ? (lineLength / encodedBlockSize) * encodedBlockSize : 0;
- this.chunkSeparatorLength = chunkSeparatorLength;
-
- this.pad = pad;
- }
-
- /**
- * Returns true if this object has buffered data for reading.
- *
- * @param context the context to be used
- * @return true if there is data still available for reading.
- */
- boolean hasData(final Context context) { // package protected for access from I/O streams
- return context.buffer != null;
- }
-
- /**
- * Returns the amount of buffered data available for reading.
- *
- * @param context the context to be used
- * @return The amount of buffered data available for reading.
- */
- int available(final Context context) { // package protected for access from I/O streams
- return context.buffer != null ? context.pos - context.readPos : 0;
- }
-
- /**
- * Get the default buffer size. Can be overridden.
- *
- * @return {@link #DEFAULT_BUFFER_SIZE}
- */
- protected int getDefaultBufferSize() {
- return DEFAULT_BUFFER_SIZE;
- }
-
- /**
- * Increases our buffer by the {@link #DEFAULT_BUFFER_RESIZE_FACTOR}.
- *
- * @param context the context to be used
- */
- private byte[] resizeBuffer(final Context context) {
- if (context.buffer == null) {
- context.buffer = new byte[getDefaultBufferSize()];
- context.pos = 0;
- context.readPos = 0;
- } else {
- final byte[] b = new byte[context.buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR];
- System.arraycopy(context.buffer, 0, b, 0, context.buffer.length);
- context.buffer = b;
- }
- return context.buffer;
- }
-
- /**
- * Ensure that the buffer has room for size
bytes
- *
- * @param size minimum spare space required
- * @param context the context to be used
- * @return the buffer
- */
- protected byte[] ensureBufferSize(final int size, final Context context) {
- if ((context.buffer == null) || (context.buffer.length < context.pos + size)) {
- return resizeBuffer(context);
- }
- return context.buffer;
- }
-
- /**
- * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail
- * bytes. Returns how many bytes were actually extracted.
- *
- * Package protected for access from I/O streams.
- *
- * @param b byte[] array to extract the buffered data into.
- * @param bPos position in byte[] array to start extraction at.
- * @param bAvail amount of bytes we're allowed to extract. We may extract fewer (if fewer are available).
- * @param context the context to be used
- * @return The number of bytes successfully extracted into the provided byte[] array.
- */
- int readResults(final byte[] b, final int bPos, final int bAvail, final Context context) {
- if (context.buffer != null) {
- final int len = Math.min(available(context), bAvail);
- System.arraycopy(context.buffer, context.readPos, b, bPos, len);
- context.readPos += len;
- if (context.readPos >= context.pos) {
- context.buffer = null; // so hasData() will return false, and this method can return -1
- }
- return len;
- }
- return context.eof ? EOF : 0;
- }
-
- /**
- * Checks if a byte value is whitespace or not.
- * Whitespace is taken to mean: space, tab, CR, LF
- *
- * @param byteToCheck the byte to check
- * @return true if byte is whitespace, false otherwise
- */
- protected static boolean isWhiteSpace(final byte byteToCheck) {
- switch (byteToCheck) {
- case ' ':
- case '\n':
- case '\r':
- case '\t':
- return true;
- default:
- return false;
- }
- }
-
- /**
- * Encodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of
- * the Encoder interface, and will throw an EncoderException if the supplied object is not of type byte[].
- *
- * @param obj Object to encode
- * @return An object (of type byte[]) containing the Base-N encoded data which corresponds to the byte[] supplied.
- * @throws EncoderException if the parameter supplied is not of type byte[]
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (!(obj instanceof byte[])) {
- throw new EncoderException("Parameter supplied to Base-N encode is not a byte[]");
- }
- return encode((byte[]) obj);
- }
-
- /**
- * Encodes a byte[] containing binary data, into a String containing characters in the Base-N alphabet.
- * Uses UTF8 encoding.
- *
- * @param pArray a byte array containing binary data
- * @return A String containing only Base-N character data
- */
- public String encodeToString(final byte[] pArray) {
- return StringUtils.newStringUtf8(encode(pArray));
- }
-
- /**
- * Encodes a byte[] containing binary data, into a String containing characters in the appropriate alphabet.
- * Uses UTF8 encoding.
- *
- * @param pArray a byte array containing binary data
- * @return String containing only character data in the appropriate alphabet.
- */
- public String encodeAsString(final byte[] pArray) {
- return StringUtils.newStringUtf8(encode(pArray));
- }
-
- /**
- * Decodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of
- * the Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[] or String.
- *
- * @param obj Object to decode
- * @return An object (of type byte[]) containing the binary data which corresponds to the byte[] or String
- * supplied.
- * @throws DecoderException if the parameter supplied is not of type byte[]
- */
- @Override
- public Object decode(final Object obj) throws DecoderException {
- if (obj instanceof byte[]) {
- return decode((byte[]) obj);
- } else if (obj instanceof String) {
- return decode((String) obj);
- } else {
- throw new DecoderException("Parameter supplied to Base-N decode is not a byte[] or a String");
- }
- }
-
- /**
- * Decodes a String containing characters in the Base-N alphabet.
- *
- * @param pArray A String containing Base-N character data
- * @return a byte array containing binary data
- */
- public byte[] decode(final String pArray) {
- return decode(StringUtils.getBytesUtf8(pArray));
- }
-
- /**
- * Decodes a byte[] containing characters in the Base-N alphabet.
- *
- * @param pArray A byte array containing Base-N character data
- * @return a byte array containing binary data
- */
- @Override
- public byte[] decode(final byte[] pArray) {
- if (pArray == null || pArray.length == 0) {
- return pArray;
- }
- final Context context = new Context();
- decode(pArray, 0, pArray.length, context);
- decode(pArray, 0, EOF, context); // Notify decoder of EOF.
- final byte[] result = new byte[context.pos];
- readResults(result, 0, result.length, context);
- return result;
- }
-
- /**
- * Encodes a byte[] containing binary data, into a byte[] containing characters in the alphabet.
- *
- * @param pArray a byte array containing binary data
- * @return A byte array containing only the basen alphabetic character data
- */
- @Override
- public byte[] encode(final byte[] pArray) {
- if (pArray == null || pArray.length == 0) {
- return pArray;
- }
- final Context context = new Context();
- encode(pArray, 0, pArray.length, context);
- encode(pArray, 0, EOF, context); // Notify encoder of EOF.
- final byte[] buf = new byte[context.pos - context.readPos];
- readResults(buf, 0, buf.length, context);
- return buf;
- }
-
- // package protected for access from I/O streams
- abstract void encode(byte[] pArray, int i, int length, Context context);
-
- // package protected for access from I/O streams
- abstract void decode(byte[] pArray, int i, int length, Context context);
-
- /**
- * Returns whether or not the octet
is in the current alphabet.
- * Does not allow whitespace or pad.
- *
- * @param value The value to test
- * @return true
if the value is defined in the current alphabet, false
otherwise.
- */
- protected abstract boolean isInAlphabet(byte value);
-
- /**
- * Tests a given byte array to see if it contains only valid characters within the alphabet.
- * The method optionally treats whitespace and pad as valid.
- *
- * @param arrayOctet byte array to test
- * @param allowWSPad if true
, then whitespace and PAD are also allowed
- * @return true
if all bytes are valid characters in the alphabet or if the byte array is empty;
- * false
, otherwise
- */
- public boolean isInAlphabet(final byte[] arrayOctet, final boolean allowWSPad) {
- for (int i = 0; i < arrayOctet.length; i++) {
- if (!isInAlphabet(arrayOctet[i]) &&
- (!allowWSPad || (arrayOctet[i] != pad) && !isWhiteSpace(arrayOctet[i]))) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Tests a given String to see if it contains only valid characters within the alphabet.
- * The method treats whitespace and PAD as valid.
- *
- * @param basen String to test
- * @return true
if all characters in the String are valid characters in the alphabet or if
- * the String is empty; false
, otherwise
- * @see #isInAlphabet(byte[], boolean)
- */
- public boolean isInAlphabet(final String basen) {
- return isInAlphabet(StringUtils.getBytesUtf8(basen), true);
- }
-
- /**
- * Tests a given byte array to see if it contains any characters within the alphabet or PAD.
- *
- * Intended for use in checking line-ending arrays
- *
- * @param arrayOctet byte array to test
- * @return true
if any byte is a valid character in the alphabet or PAD; false
otherwise
- */
- protected boolean containsAlphabetOrPad(final byte[] arrayOctet) {
- if (arrayOctet == null) {
- return false;
- }
- for (final byte element : arrayOctet) {
- if (pad == element || isInAlphabet(element)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Calculates the amount of space needed to encode the supplied array.
- *
- * @param pArray byte[] array which will later be encoded
- * @return amount of space needed to encoded the supplied array.
- * Returns a long since a max-len array will require > Integer.MAX_VALUE
- */
- public long getEncodedLength(final byte[] pArray) {
- // Calculate non-chunked size - rounded up to allow for padding
- // cast to long is needed to avoid possibility of overflow
- long len = ((pArray.length + unencodedBlockSize - 1) / unencodedBlockSize) * (long) encodedBlockSize;
- if (lineLength > 0) { // We're using chunking
- // Round up to nearest multiple
- len += ((len + lineLength - 1) / lineLength) * chunkSeparatorLength;
- }
- return len;
- }
-}
diff --git a/src/org/apache/commons/codec/binary/BaseNCodecInputStream.java b/src/org/apache/commons/codec/binary/BaseNCodecInputStream.java
deleted file mode 100644
index 75433eb3..00000000
--- a/src/org/apache/commons/codec/binary/BaseNCodecInputStream.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-import static org.apache.commons.codec.binary.BaseNCodec.EOF;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.commons.codec.binary.BaseNCodec.Context;
-
-/**
- * Abstract superclass for Base-N input streams.
- *
- * @version $Id$
- * @since 1.5
- */
-public class BaseNCodecInputStream extends FilterInputStream {
-
- private final BaseNCodec baseNCodec;
-
- private final boolean doEncode;
-
- private final byte[] singleByte = new byte[1];
-
- private final Context context = new Context();
-
- protected BaseNCodecInputStream(final InputStream in, final BaseNCodec baseNCodec, final boolean doEncode) {
- super(in);
- this.doEncode = doEncode;
- this.baseNCodec = baseNCodec;
- }
-
- /**
- * {@inheritDoc}
- *
- * @return 0
if the {@link InputStream} has reached EOF
,
- * 1
otherwise
- * @since 1.7
- */
- @Override
- public int available() throws IOException {
- // Note: the logic is similar to the InflaterInputStream:
- // as long as we have not reached EOF, indicate that there is more
- // data available. As we do not know for sure how much data is left,
- // just return 1 as a safe guess.
-
- return context.eof ? 0 : 1;
- }
-
- /**
- * Marks the current position in this input stream.
- *
The {@link #mark} method of {@link BaseNCodecInputStream} does nothing.
- *
- * @param readLimit the maximum limit of bytes that can be read before the mark position becomes invalid.
- * @since 1.7
- */
- @Override
- public synchronized void mark(final int readLimit) {
- }
-
- /**
- * {@inheritDoc}
- *
- * @return always returns false
- */
- @Override
- public boolean markSupported() {
- return false; // not an easy job to support marks
- }
-
- /**
- * Reads one byte
from this input stream.
- *
- * @return the byte as an integer in the range 0 to 255. Returns -1 if EOF has been reached.
- * @throws IOException if an I/O error occurs.
- */
- @Override
- public int read() throws IOException {
- int r = read(singleByte, 0, 1);
- while (r == 0) {
- r = read(singleByte, 0, 1);
- }
- if (r > 0) {
- final byte b = singleByte[0];
- return b < 0 ? 256 + b : b;
- }
- return EOF;
- }
-
- /**
- * Attempts to read len
bytes into the specified b
array starting at offset
- * from this InputStream.
- *
- * @param b destination byte array
- * @param offset where to start writing the bytes
- * @param len maximum number of bytes to read
- * @return number of bytes read
- * @throws IOException if an I/O error occurs.
- * @throws NullPointerException if the byte array parameter is null
- * @throws IndexOutOfBoundsException if offset, len or buffer size are invalid
- */
- @Override
- public int read(final byte b[], final int offset, final int len) throws IOException {
- if (b == null) {
- throw new NullPointerException();
- } else if (offset < 0 || len < 0) {
- throw new IndexOutOfBoundsException();
- } else if (offset > b.length || offset + len > b.length) {
- throw new IndexOutOfBoundsException();
- } else if (len == 0) {
- return 0;
- } else {
- int readLen = 0;
- /*
- Rationale for while-loop on (readLen == 0):
- -----
- Base32.readResults() usually returns > 0 or EOF (-1). In the
- rare case where it returns 0, we just keep trying.
-
- This is essentially an undocumented contract for InputStream
- implementors that want their code to work properly with
- java.io.InputStreamReader, since the latter hates it when
- InputStream.read(byte[]) returns a zero. Unfortunately our
- readResults() call must return 0 if a large amount of the data
- being decoded was non-base32, so this while-loop enables proper
- interop with InputStreamReader for that scenario.
- -----
- This is a fix for CODEC-101
- */
- while (readLen == 0) {
- if (!baseNCodec.hasData(context)) {
- final byte[] buf = new byte[doEncode ? 4096 : 8192];
- final int c = in.read(buf);
- if (doEncode) {
- baseNCodec.encode(buf, 0, c, context);
- } else {
- baseNCodec.decode(buf, 0, c, context);
- }
- }
- readLen = baseNCodec.readResults(b, offset, len, context);
- }
- return readLen;
- }
- }
-
- /**
- * Repositions this stream to the position at the time the mark method was last called on this input stream.
- *
- * The {@link #reset} method of {@link BaseNCodecInputStream} does nothing except throw an {@link IOException}.
- *
- * @throws IOException if this method is invoked
- * @since 1.7
- */
- @Override
- public synchronized void reset() throws IOException {
- throw new IOException("mark/reset not supported");
- }
-
- /**
- * {@inheritDoc}
- *
- * @throws IllegalArgumentException if the provided skip length is negative
- * @since 1.7
- */
- @Override
- public long skip(final long n) throws IOException {
- if (n < 0) {
- throw new IllegalArgumentException("Negative skip length: " + n);
- }
-
- // skip in chunks of 512 bytes
- final byte[] b = new byte[512];
- long todo = n;
-
- while (todo > 0) {
- int len = (int) Math.min(b.length, todo);
- len = this.read(b, 0, len);
- if (len == EOF) {
- break;
- }
- todo -= len;
- }
-
- return n - todo;
- }
-}
diff --git a/src/org/apache/commons/codec/binary/BaseNCodecOutputStream.java b/src/org/apache/commons/codec/binary/BaseNCodecOutputStream.java
deleted file mode 100644
index 25a851c1..00000000
--- a/src/org/apache/commons/codec/binary/BaseNCodecOutputStream.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-import static org.apache.commons.codec.binary.BaseNCodec.EOF;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.commons.codec.binary.BaseNCodec.Context;
-
-/**
- * Abstract superclass for Base-N output streams.
- *
- * To write the EOF marker without closing the stream, call {@link #eof()} or use an Apache Commons IO CloseShieldOutputStream .
- *
- *
- * @version $Id$
- * @since 1.5
- */
-public class BaseNCodecOutputStream extends FilterOutputStream {
-
- private final boolean doEncode;
-
- private final BaseNCodec baseNCodec;
-
- private final byte[] singleByte = new byte[1];
-
- private final Context context = new Context();
-
- // TODO should this be protected?
- public BaseNCodecOutputStream(final OutputStream out, final BaseNCodec basedCodec, final boolean doEncode) {
- super(out);
- this.baseNCodec = basedCodec;
- this.doEncode = doEncode;
- }
-
- /**
- * Writes the specified byte
to this output stream.
- *
- * @param i source byte
- * @throws IOException if an I/O error occurs.
- */
- @Override
- public void write(final int i) throws IOException {
- singleByte[0] = (byte) i;
- write(singleByte, 0, 1);
- }
-
- /**
- * Writes len
bytes from the specified b
array starting at offset
to this
- * output stream.
- *
- * @param b source byte array
- * @param offset where to start reading the bytes
- * @param len maximum number of bytes to write
- * @throws IOException if an I/O error occurs.
- * @throws NullPointerException if the byte array parameter is null
- * @throws IndexOutOfBoundsException if offset, len or buffer size are invalid
- */
- @Override
- public void write(final byte b[], final int offset, final int len) throws IOException {
- if (b == null) {
- throw new NullPointerException();
- } else if (offset < 0 || len < 0) {
- throw new IndexOutOfBoundsException();
- } else if (offset > b.length || offset + len > b.length) {
- throw new IndexOutOfBoundsException();
- } else if (len > 0) {
- if (doEncode) {
- baseNCodec.encode(b, offset, len, context);
- } else {
- baseNCodec.decode(b, offset, len, context);
- }
- flush(false);
- }
- }
-
- /**
- * Flushes this output stream and forces any buffered output bytes to be written out to the stream. If propagate is
- * true, the wrapped stream will also be flushed.
- *
- * @param propagate boolean flag to indicate whether the wrapped OutputStream should also be flushed.
- * @throws IOException if an I/O error occurs.
- */
- private void flush(final boolean propagate) throws IOException {
- final int avail = baseNCodec.available(context);
- if (avail > 0) {
- final byte[] buf = new byte[avail];
- final int c = baseNCodec.readResults(buf, 0, avail, context);
- if (c > 0) {
- out.write(buf, 0, c);
- }
- }
- if (propagate) {
- out.flush();
- }
- }
-
- /**
- * Flushes this output stream and forces any buffered output bytes to be written out to the stream.
- *
- * @throws IOException if an I/O error occurs.
- */
- @Override
- public void flush() throws IOException {
- flush(true);
- }
-
- /**
- * Closes this output stream and releases any system resources associated with the stream.
- *
- * To write the EOF marker without closing the stream, call {@link #eof()} or use an
- * Apache Commons IO CloseShieldOutputStream .
- *
- *
- * @throws IOException if an I/O error occurs.
- */
- @Override
- public void close() throws IOException {
- eof();
- flush();
- out.close();
- }
-
- /**
- * Writes EOF.
- *
- * @throws IOException if an I/O error occurs.
- * @since 1.11
- */
- public void eof() throws IOException {
- // Notify encoder of EOF (-1).
- if (doEncode) {
- baseNCodec.encode(singleByte, 0, EOF, context);
- } else {
- baseNCodec.decode(singleByte, 0, EOF, context);
- }
- }
-}
diff --git a/src/org/apache/commons/codec/binary/BinaryCodec.java b/src/org/apache/commons/codec/binary/BinaryCodec.java
deleted file mode 100644
index eccbc9f9..00000000
--- a/src/org/apache/commons/codec/binary/BinaryCodec.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-import org.apache.commons.codec.BinaryDecoder;
-import org.apache.commons.codec.BinaryEncoder;
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.EncoderException;
-
-/**
- * Converts between byte arrays and strings of "0"s and "1"s.
- *
- *
This class is immutable and thread-safe.
- *
- * TODO: may want to add more bit vector functions like and/or/xor/nand
- * TODO: also might be good to generate boolean[] from byte[] et cetera.
- *
- * @version $Id$
- * @since 1.3
- */
-public class BinaryCodec implements BinaryDecoder, BinaryEncoder {
- /*
- * tried to avoid using ArrayUtils to minimize dependencies while using these empty arrays - dep is just not worth
- * it.
- */
- /**
- * Empty char array.
- */
- private static final char[] EMPTY_CHAR_ARRAY = new char[0];
-
- /**
- * Empty byte array.
- */
- private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
-
- /**
- * Mask for bit 0 of a byte.
- */
- private static final int BIT_0 = 1;
-
- /**
- * Mask for bit 1 of a byte.
- */
- private static final int BIT_1 = 0x02;
-
- /**
- * Mask for bit 2 of a byte.
- */
- private static final int BIT_2 = 0x04;
-
- /**
- * Mask for bit 3 of a byte.
- */
- private static final int BIT_3 = 0x08;
-
- /**
- * Mask for bit 4 of a byte.
- */
- private static final int BIT_4 = 0x10;
-
- /**
- * Mask for bit 5 of a byte.
- */
- private static final int BIT_5 = 0x20;
-
- /**
- * Mask for bit 6 of a byte.
- */
- private static final int BIT_6 = 0x40;
-
- /**
- * Mask for bit 7 of a byte.
- */
- private static final int BIT_7 = 0x80;
-
- private static final int[] BITS = {BIT_0, BIT_1, BIT_2, BIT_3, BIT_4, BIT_5, BIT_6, BIT_7};
-
- /**
- * Converts an array of raw binary data into an array of ASCII 0 and 1 characters.
- *
- * @param raw the raw binary data to convert
- * @return 0 and 1 ASCII character bytes one for each bit of the argument
- * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
- */
- @Override
- public byte[] encode(final byte[] raw) {
- return toAsciiBytes(raw);
- }
-
- /**
- * Converts an array of raw binary data into an array of ASCII 0 and 1 chars.
- *
- * @param raw the raw binary data to convert
- * @return 0 and 1 ASCII character chars one for each bit of the argument
- * @throws EncoderException if the argument is not a byte[]
- * @see org.apache.commons.codec.Encoder#encode(Object)
- */
- @Override
- public Object encode(final Object raw) throws EncoderException {
- if (!(raw instanceof byte[])) {
- throw new EncoderException("argument not a byte array");
- }
- return toAsciiChars((byte[]) raw);
- }
-
- /**
- * Decodes a byte array where each byte represents an ASCII '0' or '1'.
- *
- * @param ascii each byte represents an ASCII '0' or '1'
- * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
- * @throws DecoderException if argument is not a byte[], char[] or String
- * @see org.apache.commons.codec.Decoder#decode(Object)
- */
- @Override
- public Object decode(final Object ascii) throws DecoderException {
- if (ascii == null) {
- return EMPTY_BYTE_ARRAY;
- }
- if (ascii instanceof byte[]) {
- return fromAscii((byte[]) ascii);
- }
- if (ascii instanceof char[]) {
- return fromAscii((char[]) ascii);
- }
- if (ascii instanceof String) {
- return fromAscii(((String) ascii).toCharArray());
- }
- throw new DecoderException("argument not a byte array");
- }
-
- /**
- * Decodes a byte array where each byte represents an ASCII '0' or '1'.
- *
- * @param ascii each byte represents an ASCII '0' or '1'
- * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
- * @see org.apache.commons.codec.Decoder#decode(Object)
- */
- @Override
- public byte[] decode(final byte[] ascii) {
- return fromAscii(ascii);
- }
-
- /**
- * Decodes a String where each char of the String represents an ASCII '0' or '1'.
- *
- * @param ascii String of '0' and '1' characters
- * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
- * @see org.apache.commons.codec.Decoder#decode(Object)
- */
- public byte[] toByteArray(final String ascii) {
- if (ascii == null) {
- return EMPTY_BYTE_ARRAY;
- }
- return fromAscii(ascii.toCharArray());
- }
-
- // ------------------------------------------------------------------------
- //
- // static codec operations
- //
- // ------------------------------------------------------------------------
-
- /**
- * Decodes a char array where each char represents an ASCII '0' or '1'.
- *
- * @param ascii each char represents an ASCII '0' or '1'
- * @return the raw encoded binary where each bit corresponds to a char in the char array argument
- */
- public static byte[] fromAscii(final char[] ascii) {
- if (ascii == null || ascii.length == 0) {
- return EMPTY_BYTE_ARRAY;
- }
- // get length/8 times bytes with 3 bit shifts to the right of the length
- final byte[] l_raw = new byte[ascii.length >> 3];
- /*
- * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
- * loop.
- */
- for (int ii = 0, jj = ascii.length - 1; ii < l_raw.length; ii++, jj -= 8) {
- for (int bits = 0; bits < BITS.length; ++bits) {
- if (ascii[jj - bits] == '1') {
- l_raw[ii] |= BITS[bits];
- }
- }
- }
- return l_raw;
- }
-
- /**
- * Decodes a byte array where each byte represents an ASCII '0' or '1'.
- *
- * @param ascii each byte represents an ASCII '0' or '1'
- * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
- */
- public static byte[] fromAscii(final byte[] ascii) {
- if (isEmpty(ascii)) {
- return EMPTY_BYTE_ARRAY;
- }
- // get length/8 times bytes with 3 bit shifts to the right of the length
- final byte[] l_raw = new byte[ascii.length >> 3];
- /*
- * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
- * loop.
- */
- for (int ii = 0, jj = ascii.length - 1; ii < l_raw.length; ii++, jj -= 8) {
- for (int bits = 0; bits < BITS.length; ++bits) {
- if (ascii[jj - bits] == '1') {
- l_raw[ii] |= BITS[bits];
- }
- }
- }
- return l_raw;
- }
-
- /**
- * Returns true
if the given array is null
or empty (size 0.)
- *
- * @param array the source array
- * @return true
if the given array is null
or empty (size 0.)
- */
- private static boolean isEmpty(final byte[] array) {
- return array == null || array.length == 0;
- }
-
- /**
- * Converts an array of raw binary data into an array of ASCII 0 and 1 character bytes - each byte is a truncated
- * char.
- *
- * @param raw the raw binary data to convert
- * @return an array of 0 and 1 character bytes for each bit of the argument
- * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
- */
- public static byte[] toAsciiBytes(final byte[] raw) {
- if (isEmpty(raw)) {
- return EMPTY_BYTE_ARRAY;
- }
- // get 8 times the bytes with 3 bit shifts to the left of the length
- final byte[] l_ascii = new byte[raw.length << 3];
- /*
- * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
- * loop.
- */
- for (int ii = 0, jj = l_ascii.length - 1; ii < raw.length; ii++, jj -= 8) {
- for (int bits = 0; bits < BITS.length; ++bits) {
- if ((raw[ii] & BITS[bits]) == 0) {
- l_ascii[jj - bits] = '0';
- } else {
- l_ascii[jj - bits] = '1';
- }
- }
- }
- return l_ascii;
- }
-
- /**
- * Converts an array of raw binary data into an array of ASCII 0 and 1 characters.
- *
- * @param raw the raw binary data to convert
- * @return an array of 0 and 1 characters for each bit of the argument
- * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
- */
- public static char[] toAsciiChars(final byte[] raw) {
- if (isEmpty(raw)) {
- return EMPTY_CHAR_ARRAY;
- }
- // get 8 times the bytes with 3 bit shifts to the left of the length
- final char[] l_ascii = new char[raw.length << 3];
- /*
- * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
- * loop.
- */
- for (int ii = 0, jj = l_ascii.length - 1; ii < raw.length; ii++, jj -= 8) {
- for (int bits = 0; bits < BITS.length; ++bits) {
- if ((raw[ii] & BITS[bits]) == 0) {
- l_ascii[jj - bits] = '0';
- } else {
- l_ascii[jj - bits] = '1';
- }
- }
- }
- return l_ascii;
- }
-
- /**
- * Converts an array of raw binary data into a String of ASCII 0 and 1 characters.
- *
- * @param raw the raw binary data to convert
- * @return a String of 0 and 1 characters representing the binary data
- * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
- */
- public static String toAsciiString(final byte[] raw) {
- return new String(toAsciiChars(raw));
- }
-}
diff --git a/src/org/apache/commons/codec/binary/CharSequenceUtils.java b/src/org/apache/commons/codec/binary/CharSequenceUtils.java
deleted file mode 100644
index 063753b2..00000000
--- a/src/org/apache/commons/codec/binary/CharSequenceUtils.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.codec.binary;
-
-/**
- *
- * Operations on {@link CharSequence} that are null
safe.
- *
- *
- * Copied from Apache Commons Lang r1586295 on April 10, 2014 (day of 3.3.2 release).
- *
- *
- * @see CharSequence
- * @since 1.10
- */
-public class CharSequenceUtils {
-
- /**
- * Green implementation of regionMatches.
- *
- * @param cs the CharSequence
to be processed
- * @param ignoreCase whether or not to be case insensitive
- * @param thisStart the index to start on the cs
CharSequence
- * @param substring the CharSequence
to be looked for
- * @param start the index to start on the substring
CharSequence
- * @param length character length of the region
- * @return whether the region matched
- */
- static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart,
- final CharSequence substring, final int start, final int length) {
- if (cs instanceof String && substring instanceof String) {
- return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length);
- }
- int index1 = thisStart;
- int index2 = start;
- int tmpLen = length;
-
- while (tmpLen-- > 0) {
- char c1 = cs.charAt(index1++);
- char c2 = substring.charAt(index2++);
-
- if (c1 == c2) {
- continue;
- }
-
- if (!ignoreCase) {
- return false;
- }
-
- // The same check as in String.regionMatches():
- if (Character.toUpperCase(c1) != Character.toUpperCase(c2) &&
- Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
- return false;
- }
- }
-
- return true;
- }
-}
diff --git a/src/org/apache/commons/codec/binary/Hex.java b/src/org/apache/commons/codec/binary/Hex.java
deleted file mode 100644
index 8f7584e8..00000000
--- a/src/org/apache/commons/codec/binary/Hex.java
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-
-import org.apache.commons.codec.BinaryDecoder;
-import org.apache.commons.codec.BinaryEncoder;
-import org.apache.commons.codec.CharEncoding;
-import org.apache.commons.codec.Charsets;
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.EncoderException;
-
-/**
- * Converts hexadecimal Strings. The charset used for certain operation can be set, the default is set in
- * {@link #DEFAULT_CHARSET_NAME}
- *
- * This class is thread-safe.
- *
- * @version $Id$
- * @since 1.1
- */
-public class Hex implements BinaryEncoder, BinaryDecoder {
-
- /**
- * Default charset name is {@link Charsets#UTF_8}
- *
- * @since 1.7
- */
- public static final Charset DEFAULT_CHARSET = Charsets.UTF_8;
-
- /**
- * Default charset name is {@link CharEncoding#UTF_8}
- *
- * @since 1.4
- */
- public static final String DEFAULT_CHARSET_NAME = CharEncoding.UTF_8;
-
- /**
- * Used to build output as Hex
- */
- private static final char[] DIGITS_LOWER =
- {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-
- /**
- * Used to build output as Hex
- */
- private static final char[] DIGITS_UPPER =
- {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
-
- /**
- * Converts an array of characters representing hexadecimal values into an array of bytes of those same values. The
- * returned array will be half the length of the passed array, as it takes two characters to represent any given
- * byte. An exception is thrown if the passed char array has an odd number of elements.
- *
- * @param data An array of characters containing hexadecimal digits
- * @return A byte array containing binary data decoded from the supplied char array.
- * @throws DecoderException Thrown if an odd number or illegal of characters is supplied
- */
- public static byte[] decodeHex(final char[] data) throws DecoderException {
-
- final int len = data.length;
-
- if ((len & 0x01) != 0) {
- throw new DecoderException("Odd number of characters.");
- }
-
- final byte[] out = new byte[len >> 1];
-
- // two characters form the hex value.
- for (int i = 0, j = 0; j < len; i++) {
- int f = toDigit(data[j], j) << 4;
- j++;
- f = f | toDigit(data[j], j);
- j++;
- out[i] = (byte) (f & 0xFF);
- }
-
- return out;
- }
-
- /**
- * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
- * The returned array will be double the length of the passed array, as it takes two characters to represent any
- * given byte.
- *
- * @param data a byte[] to convert to Hex characters
- * @return A char[] containing hexadecimal characters
- */
- public static char[] encodeHex(final byte[] data) {
- return encodeHex(data, true);
- }
-
- /**
- * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order.
- * The returned array will be double the length of the passed array, as it takes two characters to represent any
- * given byte.
- *
- * @param data a byte buffer to convert to Hex characters
- * @return A char[] containing hexadecimal characters
- * @since 1.11
- */
- public static char[] encodeHex(final ByteBuffer data) {
- return encodeHex(data, true);
- }
-
- /**
- * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
- * The returned array will be double the length of the passed array, as it takes two characters to represent any
- * given byte.
- *
- * @param data a byte[] to convert to Hex characters
- * @param toLowerCase true
converts to lowercase, false
to uppercase
- * @return A char[] containing hexadecimal characters
- * @since 1.4
- */
- public static char[] encodeHex(final byte[] data, final boolean toLowerCase) {
- return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
- }
-
- /**
- * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order.
- * The returned array will be double the length of the passed array, as it takes two characters to represent any
- * given byte.
- *
- * @param data a byte buffer to convert to Hex characters
- * @param toLowerCase true
converts to lowercase, false
to uppercase
- * @return A char[] containing hexadecimal characters
- * @since 1.11
- */
- public static char[] encodeHex(final ByteBuffer data, final boolean toLowerCase) {
- return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
- }
-
- /**
- * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
- * The returned array will be double the length of the passed array, as it takes two characters to represent any
- * given byte.
- *
- * @param data a byte[] to convert to Hex characters
- * @param toDigits the output alphabet
- * @return A char[] containing hexadecimal characters
- * @since 1.4
- */
- protected static char[] encodeHex(final byte[] data, final char[] toDigits) {
- final int l = data.length;
- final char[] out = new char[l << 1];
- // two characters form the hex value.
- for (int i = 0, j = 0; i < l; i++) {
- out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
- out[j++] = toDigits[0x0F & data[i]];
- }
- return out;
- }
-
- /**
- * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order.
- * The returned array will be double the length of the passed array, as it takes two characters to represent any
- * given byte.
- *
- * @param data a byte buffer to convert to Hex characters
- * @param toDigits the output alphabet
- * @return A char[] containing hexadecimal characters
- * @since 1.11
- */
- protected static char[] encodeHex(final ByteBuffer data, final char[] toDigits) {
- return encodeHex(data.array(), toDigits);
- }
-
- /**
- * Converts an array of bytes into a String representing the hexadecimal values of each byte in order. The returned
- * String will be double the length of the passed array, as it takes two characters to represent any given byte.
- *
- * @param data a byte[] to convert to Hex characters
- * @return A String containing hexadecimal characters
- * @since 1.4
- */
- public static String encodeHexString(final byte[] data) {
- return new String(encodeHex(data));
- }
-
- /**
- * Converts a byte buffer into a String representing the hexadecimal values of each byte in order. The returned
- * String will be double the length of the passed array, as it takes two characters to represent any given byte.
- *
- * @param data a byte buffer to convert to Hex characters
- * @return A String containing hexadecimal characters
- * @since 1.11
- */
- public static String encodeHexString(final ByteBuffer data) {
- return new String(encodeHex(data));
- }
-
- /**
- * Converts a hexadecimal character to an integer.
- *
- * @param ch A character to convert to an integer digit
- * @param index The index of the character in the source
- * @return An integer
- * @throws DecoderException Thrown if ch is an illegal hex character
- */
- protected static int toDigit(final char ch, final int index) throws DecoderException {
- final int digit = Character.digit(ch, 16);
- if (digit == -1) {
- throw new DecoderException("Illegal hexadecimal character " + ch + " at index " + index);
- }
- return digit;
- }
-
- private final Charset charset;
-
- /**
- * Creates a new codec with the default charset name {@link #DEFAULT_CHARSET}
- */
- public Hex() {
- // use default encoding
- this.charset = DEFAULT_CHARSET;
- }
-
- /**
- * Creates a new codec with the given Charset.
- *
- * @param charset the charset.
- * @since 1.7
- */
- public Hex(final Charset charset) {
- this.charset = charset;
- }
-
- /**
- * Creates a new codec with the given charset name.
- *
- * @param charsetName the charset name.
- * @throws java.nio.charset.UnsupportedCharsetException If the named charset is unavailable
- * @since 1.4
- * @since 1.7 throws UnsupportedCharsetException if the named charset is unavailable
- */
- public Hex(final String charsetName) {
- this(Charset.forName(charsetName));
- }
-
- /**
- * Converts an array of character bytes representing hexadecimal values into an array of bytes of those same values.
- * The returned array will be half the length of the passed array, as it takes two characters to represent any given
- * byte. An exception is thrown if the passed char array has an odd number of elements.
- *
- * @param array An array of character bytes containing hexadecimal digits
- * @return A byte array containing binary data decoded from the supplied byte array (representing characters).
- * @throws DecoderException Thrown if an odd number of characters is supplied to this function
- * @see #decodeHex(char[])
- */
- @Override
- public byte[] decode(final byte[] array) throws DecoderException {
- return decodeHex(new String(array, getCharset()).toCharArray());
- }
-
- /**
- * Converts a buffer of character bytes representing hexadecimal values into an array of bytes of those same values.
- * The returned array will be half the length of the passed array, as it takes two characters to represent any given
- * byte. An exception is thrown if the passed char array has an odd number of elements.
- *
- * @param buffer An array of character bytes containing hexadecimal digits
- * @return A byte array containing binary data decoded from the supplied byte array (representing characters).
- * @throws DecoderException Thrown if an odd number of characters is supplied to this function
- * @see #decodeHex(char[])
- * @since 1.11
- */
- public byte[] decode(final ByteBuffer buffer) throws DecoderException {
- return decodeHex(new String(buffer.array(), getCharset()).toCharArray());
- }
-
- /**
- * Converts a String or an array of character bytes representing hexadecimal values into an array of bytes of those
- * same values. The returned array will be half the length of the passed String or array, as it takes two characters
- * to represent any given byte. An exception is thrown if the passed char array has an odd number of elements.
- *
- * @param object A String, ByteBuffer, byte[], or an array of character bytes containing hexadecimal digits
- * @return A byte array containing binary data decoded from the supplied byte array (representing characters).
- * @throws DecoderException Thrown if an odd number of characters is supplied to this function or the object is not a String or
- * char[]
- * @see #decodeHex(char[])
- */
- @Override
- public Object decode(final Object object) throws DecoderException {
- if (object instanceof String) {
- return decode(((String) object).toCharArray());
- } else if (object instanceof byte[]) {
- return decode((byte[]) object);
- } else if (object instanceof ByteBuffer) {
- return decode((ByteBuffer) object);
- } else {
- try {
- return decodeHex((char[]) object);
- } catch (final ClassCastException e) {
- throw new DecoderException(e.getMessage(), e);
- }
- }
- }
-
- /**
- * Converts an array of bytes into an array of bytes for the characters representing the hexadecimal values of each
- * byte in order. The returned array will be double the length of the passed array, as it takes two characters to
- * represent any given byte.
- *
- * The conversion from hexadecimal characters to the returned bytes is performed with the charset named by
- * {@link #getCharset()}.
- *
- *
- * @param array a byte[] to convert to Hex characters
- * @return A byte[] containing the bytes of the hexadecimal characters
- * @see #encodeHex(byte[])
- * @since 1.7 No longer throws IllegalStateException if the charsetName is invalid.
- */
- @Override
- public byte[] encode(final byte[] array) {
- return encodeHexString(array).getBytes(this.getCharset());
- }
-
- /**
- * Converts byte buffer into an array of bytes for the characters representing the hexadecimal values of each
- * byte in order. The returned array will be double the length of the passed array, as it takes two characters to
- * represent any given byte.
- *
- * The conversion from hexadecimal characters to the returned bytes is performed with the charset named by
- * {@link #getCharset()}.
- *
- *
- * @param array a byte buffer to convert to Hex characters
- * @return A byte[] containing the bytes of the hexadecimal characters
- * @see #encodeHex(byte[])
- * @since 1.11
- */
- public byte[] encode(final ByteBuffer array) {
- return encodeHexString(array).getBytes(this.getCharset());
- }
-
- /**
- * Converts a String or an array of bytes into an array of characters representing the hexadecimal values of each
- * byte in order. The returned array will be double the length of the passed String or array, as it takes two
- * characters to represent any given byte.
- *
- * The conversion from hexadecimal characters to bytes to be encoded to performed with the charset named by
- * {@link #getCharset()}.
- *
- *
- * @param object a String, ByteBuffer, or byte[] to convert to Hex characters
- * @return A char[] containing hexadecimal characters
- * @throws EncoderException Thrown if the given object is not a String or byte[]
- * @see #encodeHex(byte[])
- */
- @Override
- public Object encode(final Object object) throws EncoderException {
- byte[] byteArray;
- if (object instanceof String) {
- byteArray = ((String) object).getBytes(this.getCharset());
- } else if (object instanceof ByteBuffer) {
- byteArray = ((ByteBuffer) object).array();
- } else {
- try {
- byteArray = (byte[]) object;
- } catch (final ClassCastException e) {
- throw new EncoderException(e.getMessage(), e);
- }
- }
- return encodeHex(byteArray);
- }
-
- /**
- * Gets the charset.
- *
- * @return the charset.
- * @since 1.7
- */
- public Charset getCharset() {
- return this.charset;
- }
-
- /**
- * Gets the charset name.
- *
- * @return the charset name.
- * @since 1.4
- */
- public String getCharsetName() {
- return this.charset.name();
- }
-
- /**
- * Returns a string representation of the object, which includes the charset name.
- *
- * @return a string representation of the object.
- */
- @Override
- public String toString() {
- return super.toString() + "[charsetName=" + this.charset + "]";
- }
-}
diff --git a/src/org/apache/commons/codec/binary/StringUtils.java b/src/org/apache/commons/codec/binary/StringUtils.java
deleted file mode 100644
index 958e05a1..00000000
--- a/src/org/apache/commons/codec/binary/StringUtils.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.binary;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-
-import org.apache.commons.codec.CharEncoding;
-import org.apache.commons.codec.Charsets;
-
-/**
- * Converts String to and from bytes using the encodings required by the Java specification. These encodings are
- * specified in
- * Standard charsets .
- *
- *
This class is immutable and thread-safe.
- *
- * @version $Id$
- * @see CharEncoding
- * @see Standard charsets
- * @since 1.4
- */
-public class StringUtils {
-
- /**
- *
- * Compares two CharSequences, returning true
if they represent equal sequences of characters.
- *
- *
- *
- * null
s are handled without exceptions. Two null
references are considered to be equal.
- * The comparison is case sensitive.
- *
- *
- *
- * StringUtils.equals(null, null) = true
- * StringUtils.equals(null, "abc") = false
- * StringUtils.equals("abc", null) = false
- * StringUtils.equals("abc", "abc") = true
- * StringUtils.equals("abc", "ABC") = false
- *
- *
- *
- * Copied from Apache Commons Lang r1583482 on April 10, 2014 (day of 3.3.2 release).
- *
- *
- * @param cs1 the first CharSequence, may be null
- * @param cs2 the second CharSequence, may be null
- * @return true
if the CharSequences are equal (case-sensitive), or both null
- * @see Object#equals(Object)
- * @since 1.10
- */
- public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
- if (cs1 == cs2) {
- return true;
- }
- if (cs1 == null || cs2 == null) {
- return false;
- }
- if (cs1 instanceof String && cs2 instanceof String) {
- return cs1.equals(cs2);
- }
- return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, Math.max(cs1.length(), cs2.length()));
- }
-
- /**
- * Calls {@link String#getBytes(Charset)}
- *
- * @param string The string to encode (if null, return null).
- * @param charset The {@link Charset} to encode the String
- * @return the encoded bytes
- */
- private static byte[] getBytes(final String string, final Charset charset) {
- if (string == null) {
- return null;
- }
- return string.getBytes(charset);
- }
-
- /**
- * Calls {@link String#getBytes(Charset)}
- *
- * @param string The string to encode (if null, return null).
- * @param charset The {@link Charset} to encode the String
- * @return the encoded bytes
- * @since 1.11
- */
- private static ByteBuffer getByteBuffer(final String string, final Charset charset) {
- if (string == null) {
- return null;
- }
- return ByteBuffer.wrap(string.getBytes(charset));
- }
-
- /**
- * Encodes the given string into a byte buffer using the UTF-8 charset, storing the result into a new byte
- * array.
- *
- * @param string the String to encode, may be null
- * @return encoded bytes, or null
if the input string was null
- * @throws NullPointerException Thrown if {@link Charsets#UTF_8} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @see Standard charsets
- * @see #getBytesUnchecked(String, String)
- * @since 1.11
- */
- public static ByteBuffer getByteBufferUtf8(final String string) {
- return getByteBuffer(string, Charsets.UTF_8);
- }
-
- /**
- * Encodes the given string into a sequence of bytes using the ISO-8859-1 charset, storing the result into a new
- * byte array.
- *
- * @param string the String to encode, may be null
- * @return encoded bytes, or null
if the input string was null
- * @throws NullPointerException Thrown if {@link Charsets#ISO_8859_1} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @see Standard charsets
- * @see #getBytesUnchecked(String, String)
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static byte[] getBytesIso8859_1(final String string) {
- return getBytes(string, Charsets.ISO_8859_1);
- }
-
-
- /**
- * Encodes the given string into a sequence of bytes using the named charset, storing the result into a new byte
- * array.
- *
- * This method catches {@link UnsupportedEncodingException} and rethrows it as {@link IllegalStateException}, which
- * should never happen for a required charset name. Use this method when the encoding is required to be in the JRE.
- *
- *
- * @param string the String to encode, may be null
- * @param charsetName The name of a required {@link java.nio.charset.Charset}
- * @return encoded bytes, or null
if the input string was null
- * @throws IllegalStateException Thrown when a {@link UnsupportedEncodingException} is caught, which should never happen for a
- * required charset name.
- * @see CharEncoding
- * @see String#getBytes(String)
- */
- public static byte[] getBytesUnchecked(final String string, final String charsetName) {
- if (string == null) {
- return null;
- }
- try {
- return string.getBytes(charsetName);
- } catch (final UnsupportedEncodingException e) {
- throw StringUtils.newIllegalStateException(charsetName, e);
- }
- }
-
- /**
- * Encodes the given string into a sequence of bytes using the US-ASCII charset, storing the result into a new byte
- * array.
- *
- * @param string the String to encode, may be null
- * @return encoded bytes, or null
if the input string was null
- * @throws NullPointerException Thrown if {@link Charsets#US_ASCII} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @see Standard charsets
- * @see #getBytesUnchecked(String, String)
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static byte[] getBytesUsAscii(final String string) {
- return getBytes(string, Charsets.US_ASCII);
- }
-
- /**
- * Encodes the given string into a sequence of bytes using the UTF-16 charset, storing the result into a new byte
- * array.
- *
- * @param string the String to encode, may be null
- * @return encoded bytes, or null
if the input string was null
- * @throws NullPointerException Thrown if {@link Charsets#UTF_16} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @see Standard charsets
- * @see #getBytesUnchecked(String, String)
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static byte[] getBytesUtf16(final String string) {
- return getBytes(string, Charsets.UTF_16);
- }
-
- /**
- * Encodes the given string into a sequence of bytes using the UTF-16BE charset, storing the result into a new byte
- * array.
- *
- * @param string the String to encode, may be null
- * @return encoded bytes, or null
if the input string was null
- * @throws NullPointerException Thrown if {@link Charsets#UTF_16BE} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @see Standard charsets
- * @see #getBytesUnchecked(String, String)
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static byte[] getBytesUtf16Be(final String string) {
- return getBytes(string, Charsets.UTF_16BE);
- }
-
- /**
- * Encodes the given string into a sequence of bytes using the UTF-16LE charset, storing the result into a new byte
- * array.
- *
- * @param string the String to encode, may be null
- * @return encoded bytes, or null
if the input string was null
- * @throws NullPointerException Thrown if {@link Charsets#UTF_16LE} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @see Standard charsets
- * @see #getBytesUnchecked(String, String)
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static byte[] getBytesUtf16Le(final String string) {
- return getBytes(string, Charsets.UTF_16LE);
- }
-
- /**
- * Encodes the given string into a sequence of bytes using the UTF-8 charset, storing the result into a new byte
- * array.
- *
- * @param string the String to encode, may be null
- * @return encoded bytes, or null
if the input string was null
- * @throws NullPointerException Thrown if {@link Charsets#UTF_8} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @see Standard charsets
- * @see #getBytesUnchecked(String, String)
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static byte[] getBytesUtf8(final String string) {
- return getBytes(string, Charsets.UTF_8);
- }
-
- private static IllegalStateException newIllegalStateException(final String charsetName,
- final UnsupportedEncodingException e) {
- return new IllegalStateException(charsetName + ": " + e);
- }
-
- /**
- * Constructs a new String
by decoding the specified array of bytes using the given charset.
- *
- * @param bytes The bytes to be decoded into characters
- * @param charset The {@link Charset} to encode the String
- * @return A new String
decoded from the specified array of bytes using the given charset,
- * or null
if the input byte array was null
.
- * @throws NullPointerException Thrown if {@link Charsets#UTF_8} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- */
- private static String newString(final byte[] bytes, final Charset charset) {
- return bytes == null ? null : new String(bytes, charset);
- }
-
- /**
- * Constructs a new String
by decoding the specified array of bytes using the given charset.
- *
- * This method catches {@link UnsupportedEncodingException} and re-throws it as {@link IllegalStateException}, which
- * should never happen for a required charset name. Use this method when the encoding is required to be in the JRE.
- *
- *
- * @param bytes The bytes to be decoded into characters, may be null
- * @param charsetName The name of a required {@link java.nio.charset.Charset}
- * @return A new String
decoded from the specified array of bytes using the given charset,
- * or null
if the input byte array was null
.
- * @throws IllegalStateException Thrown when a {@link UnsupportedEncodingException} is caught, which should never happen for a
- * required charset name.
- * @see CharEncoding
- * @see String#String(byte[], String)
- */
- public static String newString(final byte[] bytes, final String charsetName) {
- if (bytes == null) {
- return null;
- }
- try {
- return new String(bytes, charsetName);
- } catch (final UnsupportedEncodingException e) {
- throw StringUtils.newIllegalStateException(charsetName, e);
- }
- }
-
- /**
- * Constructs a new String
by decoding the specified array of bytes using the ISO-8859-1 charset.
- *
- * @param bytes The bytes to be decoded into characters, may be null
- * @return A new String
decoded from the specified array of bytes using the ISO-8859-1 charset, or
- * null
if the input byte array was null
.
- * @throws NullPointerException Thrown if {@link Charsets#ISO_8859_1} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static String newStringIso8859_1(final byte[] bytes) {
- return new String(bytes, Charsets.ISO_8859_1);
- }
-
- /**
- * Constructs a new String
by decoding the specified array of bytes using the US-ASCII charset.
- *
- * @param bytes The bytes to be decoded into characters
- * @return A new String
decoded from the specified array of bytes using the US-ASCII charset,
- * or null
if the input byte array was null
.
- * @throws NullPointerException Thrown if {@link Charsets#US_ASCII} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static String newStringUsAscii(final byte[] bytes) {
- return new String(bytes, Charsets.US_ASCII);
- }
-
- /**
- * Constructs a new String
by decoding the specified array of bytes using the UTF-16 charset.
- *
- * @param bytes The bytes to be decoded into characters
- * @return A new String
decoded from the specified array of bytes using the UTF-16 charset
- * or null
if the input byte array was null
.
- * @throws NullPointerException Thrown if {@link Charsets#UTF_16} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static String newStringUtf16(final byte[] bytes) {
- return new String(bytes, Charsets.UTF_16);
- }
-
- /**
- * Constructs a new String
by decoding the specified array of bytes using the UTF-16BE charset.
- *
- * @param bytes The bytes to be decoded into characters
- * @return A new String
decoded from the specified array of bytes using the UTF-16BE charset,
- * or null
if the input byte array was null
.
- * @throws NullPointerException Thrown if {@link Charsets#UTF_16BE} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static String newStringUtf16Be(final byte[] bytes) {
- return new String(bytes, Charsets.UTF_16BE);
- }
-
- /**
- * Constructs a new String
by decoding the specified array of bytes using the UTF-16LE charset.
- *
- * @param bytes The bytes to be decoded into characters
- * @return A new String
decoded from the specified array of bytes using the UTF-16LE charset,
- * or null
if the input byte array was null
.
- * @throws NullPointerException Thrown if {@link Charsets#UTF_16LE} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static String newStringUtf16Le(final byte[] bytes) {
- return new String(bytes, Charsets.UTF_16LE);
- }
-
- /**
- * Constructs a new String
by decoding the specified array of bytes using the UTF-8 charset.
- *
- * @param bytes The bytes to be decoded into characters
- * @return A new String
decoded from the specified array of bytes using the UTF-8 charset,
- * or null
if the input byte array was null
.
- * @throws NullPointerException Thrown if {@link Charsets#UTF_8} is not initialized, which should never happen since it is
- * required by the Java platform specification.
- * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
- */
- public static String newStringUtf8(final byte[] bytes) {
- return newString(bytes, Charsets.UTF_8);
- }
-}
diff --git a/src/org/apache/commons/codec/binary/package.html b/src/org/apache/commons/codec/binary/package.html
deleted file mode 100644
index 354b0d84..00000000
--- a/src/org/apache/commons/codec/binary/package.html
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-Base64, Base32, Binary, and Hexadecimal String encoding and decoding.
-
-
diff --git a/src/org/apache/commons/codec/digest/B64.java b/src/org/apache/commons/codec/digest/B64.java
deleted file mode 100644
index 8db01a87..00000000
--- a/src/org/apache/commons/codec/digest/B64.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.codec.digest;
-
-import java.util.Random;
-
-/**
- * Base64 like method to convert binary bytes into ASCII chars.
- *
- * TODO: Can Base64 be reused?
- *
- *
- * This class is immutable and thread-safe.
- *
- *
- * @version $Id$
- * @since 1.7
- */
-class B64 {
-
- /**
- * Table with characters for Base64 transformation.
- */
- static final String B64T = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
- /**
- * Base64 like conversion of bytes to ASCII chars.
- *
- * @param b2 A byte from the result.
- * @param b1 A byte from the result.
- * @param b0 A byte from the result.
- * @param outLen The number of expected output chars.
- * @param buffer Where the output chars is appended to.
- */
- static void b64from24bit(final byte b2, final byte b1, final byte b0, final int outLen,
- final StringBuilder buffer) {
- // The bit masking is necessary because the JVM byte type is signed!
- int w = ((b2 << 16) & 0x00ffffff) | ((b1 << 8) & 0x00ffff) | (b0 & 0xff);
- // It's effectively a "for" loop but kept to resemble the original C code.
- int n = outLen;
- while (n-- > 0) {
- buffer.append(B64T.charAt(w & 0x3f));
- w >>= 6;
- }
- }
-
- /**
- * Generates a string of random chars from the B64T set.
- *
- * @param num Number of chars to generate.
- */
- static String getRandomSalt(final int num) {
- final StringBuilder saltString = new StringBuilder();
- for (int i = 1; i <= num; i++) {
- saltString.append(B64T.charAt(new Random().nextInt(B64T.length())));
- }
- return saltString.toString();
- }
-}
diff --git a/src/org/apache/commons/codec/digest/Crypt.java b/src/org/apache/commons/codec/digest/Crypt.java
deleted file mode 100644
index 435114fb..00000000
--- a/src/org/apache/commons/codec/digest/Crypt.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.codec.digest;
-
-import org.apache.commons.codec.Charsets;
-
-/**
- * GNU libc crypt(3) compatible hash method.
- *
- * See {@link #crypt(String, String)} for further details.
- *
- * This class is immutable and thread-safe.
- *
- * @version $Id$
- * @since 1.7
- */
-public class Crypt {
-
- /**
- * Encrypts a password in a crypt(3) compatible way.
- *
- * A random salt and the default algorithm (currently SHA-512) are used. See {@link #crypt(String, String)} for
- * details.
- *
- * @param keyBytes plaintext password
- * @return hash value
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String crypt(final byte[] keyBytes) {
- return crypt(keyBytes, null);
- }
-
- /**
- * Encrypts a password in a crypt(3) compatible way.
- *
- * If no salt is provided, a random salt and the default algorithm (currently SHA-512) will be used. See
- * {@link #crypt(String, String)} for details.
- *
- * @param keyBytes plaintext password
- * @param salt salt value
- * @return hash value
- * @throws IllegalArgumentException if the salt does not match the allowed pattern
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String crypt(final byte[] keyBytes, final String salt) {
- if (salt == null) {
- return Sha2Crypt.sha512Crypt(keyBytes);
- } else if (salt.startsWith(Sha2Crypt.SHA512_PREFIX)) {
- return Sha2Crypt.sha512Crypt(keyBytes, salt);
- } else if (salt.startsWith(Sha2Crypt.SHA256_PREFIX)) {
- return Sha2Crypt.sha256Crypt(keyBytes, salt);
- } else if (salt.startsWith(Md5Crypt.MD5_PREFIX)) {
- return Md5Crypt.md5Crypt(keyBytes, salt);
- } else {
- return UnixCrypt.crypt(keyBytes, salt);
- }
- }
-
- /**
- * Calculates the digest using the strongest crypt(3) algorithm.
- *
- * A random salt and the default algorithm (currently SHA-512) are used.
- *
- * @param key plaintext password
- * @return hash value
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- * @see #crypt(String, String)
- */
- public static String crypt(final String key) {
- return crypt(key, null);
- }
-
- /**
- * Encrypts a password in a crypt(3) compatible way.
- *
- * The exact algorithm depends on the format of the salt string:
- *
- * SHA-512 salts start with {@code $6$} and are up to 16 chars long.
- * SHA-256 salts start with {@code $5$} and are up to 16 chars long
- * MD5 salts start with {@code $1$} and are up to 8 chars long
- * DES, the traditional UnixCrypt algorithm is used with only 2 chars
- * Only the first 8 chars of the passwords are used in the DES algorithm!
- *
- * The magic strings {@code "$apr1$"} and {@code "$2a$"} are not recognized by this method as its output should be
- * identical with that of the libc implementation.
- *
- * The rest of the salt string is drawn from the set {@code [a-zA-Z0-9./]} and is cut at the maximum length of if a
- * {@code "$"} sign is encountered. It is therefore valid to enter a complete hash value as salt to e.g. verify a
- * password with:
- *
- *
- * storedPwd.equals(crypt(enteredPwd, storedPwd))
- *
- *
- * The resulting string starts with the marker string ({@code $6$}), continues with the salt value and ends with a
- * {@code "$"} sign followed by the actual hash value. For DES the string only contains the salt and actual hash.
- * It's total length is dependent on the algorithm used:
- *
- * SHA-512: 106 chars
- * SHA-256: 63 chars
- * MD5: 34 chars
- * DES: 13 chars
- *
- *
- * Example:
- *
- *
- * crypt("secret", "$1$xxxx") => "$1$xxxx$aMkevjfEIpa35Bh3G4bAc."
- * crypt("secret", "xx") => "xxWAum7tHdIUw"
- *
- *
- * This method comes in a variation that accepts a byte[] array to support input strings that are not encoded in
- * UTF-8 but e.g. in ISO-8859-1 where equal characters result in different byte values.
- *
- * @param key plaintext password as entered by the used
- * @param salt salt value
- * @return hash value, i.e. encrypted password including the salt string
- * @throws IllegalArgumentException if the salt does not match the allowed pattern
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught. *
- * @see "The man page of the libc crypt (3) function."
- */
- public static String crypt(final String key, final String salt) {
- return crypt(key.getBytes(Charsets.UTF_8), salt);
- }
-}
diff --git a/src/org/apache/commons/codec/digest/DigestUtils.java b/src/org/apache/commons/codec/digest/DigestUtils.java
deleted file mode 100644
index ce91fbcd..00000000
--- a/src/org/apache/commons/codec/digest/DigestUtils.java
+++ /dev/null
@@ -1,1037 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.digest;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.codec.binary.StringUtils;
-
-/**
- * Operations to simplify common {@link java.security.MessageDigest} tasks.
- * This class is immutable and thread-safe.
- *
- * @version $Id$
- */
-public class DigestUtils {
-
- private static final int STREAM_BUFFER_LENGTH = 1024;
-
- /**
- * Read through an ByteBuffer and returns the digest for the data
- *
- * @param messageDigest The MessageDigest to use (e.g. MD5)
- * @param data Data to digest
- * @return the digest
- * @throws IOException On error reading from the stream
- */
- private static byte[] digest(final MessageDigest messageDigest, final ByteBuffer data) {
- messageDigest.update(data);
- return messageDigest.digest();
- }
-
- /**
- * Read through an InputStream and returns the digest for the data
- *
- * @param digest The MessageDigest to use (e.g. MD5)
- * @param data Data to digest
- * @return the digest
- * @throws IOException On error reading from the stream
- */
- private static byte[] digest(final MessageDigest digest, final InputStream data) throws IOException {
- return updateDigest(digest, data).digest();
- }
-
- /**
- * Returns a MessageDigest
for the given algorithm
.
- *
- * @param algorithm the name of the algorithm requested. See Appendix A in the Java Cryptography Architecture Reference Guide for information about standard
- * algorithm names.
- * @return A digest instance.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught.
- * @see MessageDigest#getInstance(String)
- */
- public static MessageDigest getDigest(final String algorithm) {
- try {
- return MessageDigest.getInstance(algorithm);
- } catch (final NoSuchAlgorithmException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Returns an MD2 MessageDigest.
- *
- * @return An MD2 digest instance.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught, which should never happen because MD2 is a
- * built-in algorithm
- * @see MessageDigestAlgorithms#MD2
- * @since 1.7
- */
- public static MessageDigest getMd2Digest() {
- return getDigest(MessageDigestAlgorithms.MD2);
- }
-
- /**
- * Returns an MD5 MessageDigest.
- *
- * @return An MD5 digest instance.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught, which should never happen because MD5 is a
- * built-in algorithm
- * @see MessageDigestAlgorithms#MD5
- */
- public static MessageDigest getMd5Digest() {
- return getDigest(MessageDigestAlgorithms.MD5);
- }
-
- /**
- * Returns an SHA-1 digest.
- *
- * @return An SHA-1 digest instance.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught, which should never happen because SHA-1 is a
- * built-in algorithm
- * @see MessageDigestAlgorithms#SHA_1
- * @since 1.7
- */
- public static MessageDigest getSha1Digest() {
- return getDigest(MessageDigestAlgorithms.SHA_1);
- }
-
- /**
- * Returns an SHA-224 digest.
- *
- * Java 8 only.
- *
- *
- * @return An SHA-224 digest instance.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught on Java 7 and older, SHA-224 is a built-in
- * algorithm on Java 8
- * @see MessageDigestAlgorithms#SHA_224
- */
- public static MessageDigest getSha224Digest() {
- return getDigest(MessageDigestAlgorithms.SHA_224);
- }
-
- /**
- * Returns an SHA-256 digest.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @return An SHA-256 digest instance.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught, which should never happen because SHA-256 is a
- * built-in algorithm
- * @see MessageDigestAlgorithms#SHA_256
- */
- public static MessageDigest getSha256Digest() {
- return getDigest(MessageDigestAlgorithms.SHA_256);
- }
-
- /**
- * Returns an SHA-384 digest.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @return An SHA-384 digest instance.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught, which should never happen because SHA-384 is a
- * built-in algorithm
- * @see MessageDigestAlgorithms#SHA_384
- */
- public static MessageDigest getSha384Digest() {
- return getDigest(MessageDigestAlgorithms.SHA_384);
- }
-
- /**
- * Returns an SHA-512 digest.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @return An SHA-512 digest instance.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught, which should never happen because SHA-512 is a
- * built-in algorithm
- * @see MessageDigestAlgorithms#SHA_512
- */
- public static MessageDigest getSha512Digest() {
- return getDigest(MessageDigestAlgorithms.SHA_512);
- }
-
- /**
- * Returns an SHA-1 digest.
- *
- * @return An SHA-1 digest instance.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught
- * @deprecated Use {@link #getSha1Digest()}
- */
- @Deprecated
- public static MessageDigest getShaDigest() {
- return getSha1Digest();
- }
-
- /**
- * Calculates the MD2 digest and returns the value as a 16 element byte[]
.
- *
- * @param data Data to digest
- * @return MD2 digest
- * @since 1.7
- */
- public static byte[] md2(final byte[] data) {
- return getMd2Digest().digest(data);
- }
-
- /**
- * Calculates the MD2 digest and returns the value as a 16 element byte[]
.
- *
- * @param data Data to digest
- * @return MD2 digest
- * @since 1.11
- */
- public static byte[] md2(final ByteBuffer data) {
- return digest(getMd2Digest(), data);
- }
-
- /**
- * Calculates the MD2 digest and returns the value as a 16 element byte[]
.
- *
- * @param data Data to digest
- * @return MD2 digest
- * @throws IOException On error reading from the stream
- * @since 1.7
- */
- public static byte[] md2(final InputStream data) throws IOException {
- return digest(getMd2Digest(), data);
- }
-
- /**
- * Calculates the MD2 digest and returns the value as a 16 element byte[]
.
- *
- * @param data Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
- * @return MD2 digest
- * @since 1.7
- */
- public static byte[] md2(final String data) {
- return md2(StringUtils.getBytesUtf8(data));
- }
-
- /**
- * Calculates the MD2 digest and returns the value as a 32 character hex string.
- *
- * @param data Data to digest
- * @return MD2 digest as a hex string
- * @since 1.7
- */
- public static String md2Hex(final byte[] data) {
- return Hex.encodeHexString(md2(data));
- }
-
- /**
- * Calculates the MD2 digest and returns the value as a 32 character hex string.
- *
- * @param data Data to digest
- * @return MD2 digest as a hex string
- * @since 1.11
- */
- public static String md2Hex(final ByteBuffer data) {
- return Hex.encodeHexString(md2(data));
- }
-
- /**
- * Calculates the MD2 digest and returns the value as a 32 character hex string.
- *
- * @param data Data to digest
- * @return MD2 digest as a hex string
- * @throws IOException On error reading from the stream
- * @since 1.7
- */
- public static String md2Hex(final InputStream data) throws IOException {
- return Hex.encodeHexString(md2(data));
- }
-
- /**
- * Calculates the MD2 digest and returns the value as a 32 character hex string.
- *
- * @param data Data to digest
- * @return MD2 digest as a hex string
- * @since 1.7
- */
- public static String md2Hex(final String data) {
- return Hex.encodeHexString(md2(data));
- }
-
- /**
- * Calculates the MD5 digest and returns the value as a 16 element byte[]
.
- *
- * @param data Data to digest
- * @return MD5 digest
- */
- public static byte[] md5(final byte[] data) {
- return getMd5Digest().digest(data);
- }
-
- /**
- * Calculates the MD5 digest and returns the value as a 16 element byte[]
.
- *
- * @param data Data to digest
- * @return MD5 digest
- * @since 1.11
- */
- public static byte[] md5(final ByteBuffer data) {
- return digest(getMd5Digest(), data);
- }
-
- /**
- * Calculates the MD5 digest and returns the value as a 16 element byte[]
.
- *
- * @param data Data to digest
- * @return MD5 digest
- * @throws IOException On error reading from the stream
- * @since 1.4
- */
- public static byte[] md5(final InputStream data) throws IOException {
- return digest(getMd5Digest(), data);
- }
-
- /**
- * Calculates the MD5 digest and returns the value as a 16 element byte[]
.
- *
- * @param data Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
- * @return MD5 digest
- */
- public static byte[] md5(final String data) {
- return md5(StringUtils.getBytesUtf8(data));
- }
-
- /**
- * Calculates the MD5 digest and returns the value as a 32 character hex string.
- *
- * @param data Data to digest
- * @return MD5 digest as a hex string
- */
- public static String md5Hex(final byte[] data) {
- return Hex.encodeHexString(md5(data));
- }
-
- /**
- * Calculates the MD5 digest and returns the value as a 32 character hex string.
- *
- * @param data Data to digest
- * @return MD5 digest as a hex string
- * @since 1.11
- */
- public static String md5Hex(final ByteBuffer data) {
- return Hex.encodeHexString(md5(data));
- }
-
- /**
- * Calculates the MD5 digest and returns the value as a 32 character hex string.
- *
- * @param data Data to digest
- * @return MD5 digest as a hex string
- * @throws IOException On error reading from the stream
- * @since 1.4
- */
- public static String md5Hex(final InputStream data) throws IOException {
- return Hex.encodeHexString(md5(data));
- }
-
- /**
- * Calculates the MD5 digest and returns the value as a 32 character hex string.
- *
- * @param data Data to digest
- * @return MD5 digest as a hex string
- */
- public static String md5Hex(final String data) {
- return Hex.encodeHexString(md5(data));
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a byte[]
.
- *
- * @param data Data to digest
- * @return SHA-1 digest
- * @deprecated Use {@link #sha1(byte[])}
- */
- @Deprecated
- public static byte[] sha(final byte[] data) {
- return sha1(data);
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a byte[]
.
- *
- * @param data Data to digest
- * @return SHA-1 digest
- * @throws IOException On error reading from the stream
- * @since 1.4
- * @deprecated Use {@link #sha1(InputStream)}
- */
- @Deprecated
- public static byte[] sha(final InputStream data) throws IOException {
- return sha1(data);
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a byte[]
.
- *
- * @param data Data to digest
- * @return SHA-1 digest
- * @deprecated Use {@link #sha1(String)}
- */
- @Deprecated
- public static byte[] sha(final String data) {
- return sha1(data);
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a byte[]
.
- *
- * @param data Data to digest
- * @return SHA-1 digest
- * @since 1.7
- */
- public static byte[] sha1(final byte[] data) {
- return getSha1Digest().digest(data);
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a byte[]
.
- *
- * @param data Data to digest
- * @return SHA-1 digest
- * @since 1.11
- */
- public static byte[] sha1(final ByteBuffer data) {
- return digest(getSha1Digest(), data);
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a byte[]
.
- *
- * @param data Data to digest
- * @return SHA-1 digest
- * @throws IOException On error reading from the stream
- * @since 1.7
- */
- public static byte[] sha1(final InputStream data) throws IOException {
- return digest(getSha1Digest(), data);
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a byte[]
.
- *
- * @param data Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
- * @return SHA-1 digest
- */
- public static byte[] sha1(final String data) {
- return sha1(StringUtils.getBytesUtf8(data));
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a hex string.
- *
- * @param data Data to digest
- * @return SHA-1 digest as a hex string
- * @since 1.7
- */
- public static String sha1Hex(final byte[] data) {
- return Hex.encodeHexString(sha1(data));
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a hex string.
- *
- * @param data Data to digest
- * @return SHA-1 digest as a hex string
- * @since 1.11
- */
- public static String sha1Hex(final ByteBuffer data) {
- return Hex.encodeHexString(sha1(data));
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a hex string.
- *
- * @param data Data to digest
- * @return SHA-1 digest as a hex string
- * @throws IOException On error reading from the stream
- * @since 1.7
- */
- public static String sha1Hex(final InputStream data) throws IOException {
- return Hex.encodeHexString(sha1(data));
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a hex string.
- *
- * @param data Data to digest
- * @return SHA-1 digest as a hex string
- * @since 1.7
- */
- public static String sha1Hex(final String data) {
- return Hex.encodeHexString(sha1(data));
- }
-
- /**
- * Calculates the SHA-224 digest and returns the value as a byte[]
.
- *
- * Throws a {@link IllegalArgumentException} on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-224 digest
- * @throws IllegalArgumentException thrown on JRE versions prior to 1.8.0.
- * @since 1.11
- */
- public static byte[] sha224(final byte[] data) {
- return getSha224Digest().digest(data);
- }
-
- /**
- * Calculates the SHA-224 digest and returns the value as a byte[]
.
- *
- * @param data Data to digest
- * @return SHA-224 digest
- * @throws IllegalArgumentException thrown on JRE versions prior to 1.8.0.
- * @since 1.11
- */
- public static byte[] sha224(final ByteBuffer data) {
- return digest(getSha224Digest(), data);
- }
-
- /**
- * Calculates the SHA-224 digest and returns the value as a byte[]
.
- *
- * Throws a {@link IllegalArgumentException} on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-224 digest
- * @throws IOException On error reading from the stream
- * @throws IllegalArgumentException thrown on JRE versions prior to 1.8.0.
- * @since 1.11
- */
- public static byte[] sha224(final InputStream data) throws IOException {
- return digest(getSha224Digest(), data);
- }
-
- /**
- * Calculates the SHA-224 digest and returns the value as a byte[]
.
- *
- * Throws a {@link IllegalArgumentException} on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
- * @return SHA-224 digest
- * @throws IllegalArgumentException thrown on JRE versions prior to 1.8.0.
- * @since 1.11
- */
- public static byte[] sha224(final String data) {
- return sha224(StringUtils.getBytesUtf8(data));
- }
-
- /**
- * Calculates the SHA-224 digest and returns the value as a hex string.
- *
- * Throws a {@link IllegalArgumentException} on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-224 digest as a hex string
- * @throws IllegalArgumentException thrown on JRE versions prior to 1.8.0.
- * @since 1.11
- */
- public static String sha224Hex(final byte[] data) {
- return Hex.encodeHexString(sha224(data));
- }
-
- /**
- * Calculates the SHA-224 digest and returns the value as a hex string.
- *
- * Throws a {@link IllegalArgumentException} on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-224 digest as a hex string
- * @throws IllegalArgumentException thrown on JRE versions prior to 1.8.0.
- * @since 1.11
- */
- public static String sha224Hex(final ByteBuffer data) {
- return Hex.encodeHexString(sha224(data));
- }
-
- /**
- * Calculates the SHA-224 digest and returns the value as a hex string.
- *
- * Throws a {@link IllegalArgumentException} on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-224 digest as a hex string
- * @throws IOException On error reading from the stream
- * @throws IllegalArgumentException thrown on JRE versions prior to 1.8.0.
- * @since 1.11
- */
- public static String sha224Hex(final InputStream data) throws IOException {
- return Hex.encodeHexString(sha224(data));
- }
-
- /**
- * Calculates the SHA-224 digest and returns the value as a hex string.
- *
- * Throws a {@link IllegalArgumentException} on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-224 digest as a hex string
- * @throws IllegalArgumentException thrown on JRE versions prior to 1.8.0.
- * @since 1.11
- */
- public static String sha224Hex(final String data) {
- return Hex.encodeHexString(sha224(data));
- }
-
- /**
- * Calculates the SHA-256 digest and returns the value as a byte[]
.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-256 digest
- * @since 1.4
- */
- public static byte[] sha256(final byte[] data) {
- return getSha256Digest().digest(data);
- }
-
- /**
- * Calculates the SHA-256 digest and returns the value as a byte[]
.
- *
- * @param data Data to digest
- * @return SHA-256 digest
- * @since 1.11
- */
- public static byte[] sha256(final ByteBuffer data) {
- return digest(getSha256Digest(), data);
- }
-
- /**
- * Calculates the SHA-256 digest and returns the value as a byte[]
.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-256 digest
- * @throws IOException On error reading from the stream
- * @since 1.4
- */
- public static byte[] sha256(final InputStream data) throws IOException {
- return digest(getSha256Digest(), data);
- }
-
- /**
- * Calculates the SHA-256 digest and returns the value as a byte[]
.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
- * @return SHA-256 digest
- * @since 1.4
- */
- public static byte[] sha256(final String data) {
- return sha256(StringUtils.getBytesUtf8(data));
- }
-
- /**
- * Calculates the SHA-256 digest and returns the value as a hex string.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-256 digest as a hex string
- * @since 1.4
- */
- public static String sha256Hex(final byte[] data) {
- return Hex.encodeHexString(sha256(data));
- }
-
- /**
- * Calculates the SHA-256 digest and returns the value as a hex string.
- *
- * @param data Data to digest
- * @return SHA-256 digest as a hex string
- * @since 1.11
- */
- public static String sha256Hex(final ByteBuffer data) {
- return Hex.encodeHexString(sha256(data));
- }
-
- /**
- * Calculates the SHA-256 digest and returns the value as a hex string.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-256 digest as a hex string
- * @throws IOException On error reading from the stream
- * @since 1.4
- */
- public static String sha256Hex(final InputStream data) throws IOException {
- return Hex.encodeHexString(sha256(data));
- }
-
- /**
- * Calculates the SHA-256 digest and returns the value as a hex string.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-256 digest as a hex string
- * @since 1.4
- */
- public static String sha256Hex(final String data) {
- return Hex.encodeHexString(sha256(data));
- }
-
- /**
- * Calculates the SHA-384 digest and returns the value as a byte[]
.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-384 digest
- * @since 1.4
- */
- public static byte[] sha384(final byte[] data) {
- return getSha384Digest().digest(data);
- }
-
- /**
- * Calculates the SHA-384 digest and returns the value as a byte[]
.
- *
- * @param data Data to digest
- * @return SHA-384 digest
- * @since 1.11
- */
- public static byte[] sha384(final ByteBuffer data) {
- return digest(getSha384Digest(), data);
- }
-
- /**
- * Calculates the SHA-384 digest and returns the value as a byte[]
.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-384 digest
- * @throws IOException On error reading from the stream
- * @since 1.4
- */
- public static byte[] sha384(final InputStream data) throws IOException {
- return digest(getSha384Digest(), data);
- }
-
- /**
- * Calculates the SHA-384 digest and returns the value as a byte[]
.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
- * @return SHA-384 digest
- * @since 1.4
- */
- public static byte[] sha384(final String data) {
- return sha384(StringUtils.getBytesUtf8(data));
- }
-
- /**
- * Calculates the SHA-384 digest and returns the value as a hex string.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-384 digest as a hex string
- * @since 1.4
- */
- public static String sha384Hex(final byte[] data) {
- return Hex.encodeHexString(sha384(data));
- }
-
- /**
- * Calculates the SHA-384 digest and returns the value as a hex string.
- *
- * @param data Data to digest
- * @return SHA-384 digest as a hex string
- * @since 1.11
- */
- public static String sha384Hex(final ByteBuffer data) {
- return Hex.encodeHexString(sha384(data));
- }
-
- /**
- * Calculates the SHA-384 digest and returns the value as a hex string.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-384 digest as a hex string
- * @throws IOException On error reading from the stream
- * @since 1.4
- */
- public static String sha384Hex(final InputStream data) throws IOException {
- return Hex.encodeHexString(sha384(data));
- }
-
- /**
- * Calculates the SHA-384 digest and returns the value as a hex string.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-384 digest as a hex string
- * @since 1.4
- */
- public static String sha384Hex(final String data) {
- return Hex.encodeHexString(sha384(data));
- }
-
- /**
- * Calculates the SHA-512 digest and returns the value as a byte[]
.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-512 digest
- * @since 1.4
- */
- public static byte[] sha512(final byte[] data) {
- return getSha512Digest().digest(data);
- }
-
- /**
- * Calculates the SHA-512 digest and returns the value as a byte[]
.
- *
- * @param data Data to digest
- * @return SHA-512 digest
- * @since 1.11
- */
- public static byte[] sha512(final ByteBuffer data) {
- return digest(getSha512Digest(), data);
- }
-
- /**
- * Calculates the SHA-512 digest and returns the value as a byte[]
.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-512 digest
- * @throws IOException On error reading from the stream
- * @since 1.4
- */
- public static byte[] sha512(final InputStream data) throws IOException {
- return digest(getSha512Digest(), data);
- }
-
- /**
- * Calculates the SHA-512 digest and returns the value as a byte[]
.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest; converted to bytes using {@link StringUtils#getBytesUtf8(String)}
- * @return SHA-512 digest
- * @since 1.4
- */
- public static byte[] sha512(final String data) {
- return sha512(StringUtils.getBytesUtf8(data));
- }
-
- /**
- * Calculates the SHA-512 digest and returns the value as a hex string.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-512 digest as a hex string
- * @since 1.4
- */
- public static String sha512Hex(final byte[] data) {
- return Hex.encodeHexString(sha512(data));
- }
-
- /**
- * Calculates the SHA-512 digest and returns the value as a hex string.
- *
- * @param data Data to digest
- * @return SHA-512 digest as a hex string
- * @since 1.11
- */
- public static String sha512Hex(final ByteBuffer data) {
- return Hex.encodeHexString(sha512(data));
- }
-
- /**
- * Calculates the SHA-512 digest and returns the value as a hex string.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-512 digest as a hex string
- * @throws IOException On error reading from the stream
- * @since 1.4
- */
- public static String sha512Hex(final InputStream data) throws IOException {
- return Hex.encodeHexString(sha512(data));
- }
-
- /**
- * Calculates the SHA-512 digest and returns the value as a hex string.
- *
- * Throws a RuntimeException
on JRE versions prior to 1.4.0.
- *
- *
- * @param data Data to digest
- * @return SHA-512 digest as a hex string
- * @since 1.4
- */
- public static String sha512Hex(final String data) {
- return Hex.encodeHexString(sha512(data));
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a hex string.
- *
- * @param data Data to digest
- * @return SHA-1 digest as a hex string
- * @deprecated Use {@link #sha1Hex(byte[])}
- */
- @Deprecated
- public static String shaHex(final byte[] data) {
- return sha1Hex(data);
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a hex string.
- *
- * @param data Data to digest
- * @return SHA-1 digest as a hex string
- * @throws IOException On error reading from the stream
- * @since 1.4
- * @deprecated Use {@link #sha1Hex(InputStream)}
- */
- @Deprecated
- public static String shaHex(final InputStream data) throws IOException {
- return sha1Hex(data);
- }
-
- /**
- * Calculates the SHA-1 digest and returns the value as a hex string.
- *
- * @param data Data to digest
- * @return SHA-1 digest as a hex string
- * @deprecated Use {@link #sha1Hex(String)}
- */
- @Deprecated
- public static String shaHex(final String data) {
- return sha1Hex(data);
- }
-
- /**
- * Updates the given {@link MessageDigest}.
- *
- * @param messageDigest the {@link MessageDigest} to update
- * @param valueToDigest the value to update the {@link MessageDigest} with
- * @return the updated {@link MessageDigest}
- * @since 1.7
- */
- public static MessageDigest updateDigest(final MessageDigest messageDigest, final byte[] valueToDigest) {
- messageDigest.update(valueToDigest);
- return messageDigest;
- }
-
- /**
- * Updates the given {@link MessageDigest}.
- *
- * @param messageDigest the {@link MessageDigest} to update
- * @param valueToDigest the value to update the {@link MessageDigest} with
- * @return the updated {@link MessageDigest}
- * @since 1.11
- */
- public static MessageDigest updateDigest(final MessageDigest messageDigest, final ByteBuffer valueToDigest) {
- messageDigest.update(valueToDigest);
- return messageDigest;
- }
-
- /**
- * Reads through an InputStream and updates the digest for the data
- *
- * @param digest The MessageDigest to use (e.g. MD5)
- * @param data Data to digest
- * @return the digest
- * @throws IOException On error reading from the stream
- * @since 1.8
- */
- public static MessageDigest updateDigest(final MessageDigest digest, final InputStream data) throws IOException {
- final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
- int read = data.read(buffer, 0, STREAM_BUFFER_LENGTH);
-
- while (read > -1) {
- digest.update(buffer, 0, read);
- read = data.read(buffer, 0, STREAM_BUFFER_LENGTH);
- }
-
- return digest;
- }
-
- /**
- * Updates the given {@link MessageDigest}.
- *
- * @param messageDigest the {@link MessageDigest} to update
- * @param valueToDigest the value to update the {@link MessageDigest} with;
- * converted to bytes using {@link StringUtils#getBytesUtf8(String)}
- * @return the updated {@link MessageDigest}
- * @since 1.7
- */
- public static MessageDigest updateDigest(final MessageDigest messageDigest, final String valueToDigest) {
- messageDigest.update(StringUtils.getBytesUtf8(valueToDigest));
- return messageDigest;
- }
-}
diff --git a/src/org/apache/commons/codec/digest/HmacAlgorithms.java b/src/org/apache/commons/codec/digest/HmacAlgorithms.java
deleted file mode 100644
index 790ae99b..00000000
--- a/src/org/apache/commons/codec/digest/HmacAlgorithms.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.digest;
-
-/**
- * Standard {@link HmacUtils} algorithm names from the Java Cryptography Architecture Standard Algorithm Name
- * Documentation .
- *
- *
- * Note: Not all JCE implementations supports all algorithms in this enum.
- *
- *
- * @version $Id$
- * @see Java Cryptography
- * Architecture Standard Algorithm Name Documentation
- * @since 1.10
- */
-public enum HmacAlgorithms {
-
- /**
- * The HmacMD5 Message Authentication Code (MAC) algorithm specified in RFC 2104 and RFC 1321.
- *
- * Every implementation of the Java platform is required to support this standard Mac algorithm.
- *
- */
- HMAC_MD5("HmacMD5"),
-
- /**
- * The HmacSHA1 Message Authentication Code (MAC) algorithm specified in RFC 2104 and FIPS PUB 180-2.
- *
- * Every implementation of the Java platform is required to support this standard Mac algorithm.
- *
- */
- HMAC_SHA_1("HmacSHA1"),
-
- /**
- * The HmacSHA256 Message Authentication Code (MAC) algorithm specified in RFC 2104 and FIPS PUB 180-2.
- *
- * Every implementation of the Java platform is required to support this standard Mac algorithm.
- *
- */
- HMAC_SHA_256("HmacSHA256"),
-
- /**
- * The HmacSHA384 Message Authentication Code (MAC) algorithm specified in RFC 2104 and FIPS PUB 180-2.
- *
- * Every implementation of the Java platform is not required to support this Mac algorithm.
- *
- */
- HMAC_SHA_384("HmacSHA384"),
-
- /**
- * The HmacSHA512 Message Authentication Code (MAC) algorithm specified in RFC 2104 and FIPS PUB 180-2.
- *
- * Every implementation of the Java platform is not required to support this Mac algorithm.
- *
- */
- HMAC_SHA_512("HmacSHA512");
-
- private final String algorithm;
-
- private HmacAlgorithms(final String algorithm) {
- this.algorithm = algorithm;
- }
-
- /**
- * The algorithm name
- *
- * @return The algorithm name ("HmacSHA512" for example)
- * @see Java
- * Cryptography Architecture Sun Providers Documentation
- */
- @Override
- public String toString() {
- return algorithm;
- }
-}
diff --git a/src/org/apache/commons/codec/digest/HmacUtils.java b/src/org/apache/commons/codec/digest/HmacUtils.java
deleted file mode 100644
index 5184bbeb..00000000
--- a/src/org/apache/commons/codec/digest/HmacUtils.java
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.digest;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.codec.binary.StringUtils;
-
-/**
- * Simplifies common {@link javax.crypto.Mac} tasks. This class is immutable and thread-safe.
- *
- *
- *
- * Note: Not all JCE implementations supports all algorithms. If not supported, an IllegalArgumentException is
- * thrown.
- *
- *
- * @version $Id$
- * @since 1.10
- */
-public final class HmacUtils {
-
- private static final int STREAM_BUFFER_LENGTH = 1024;
-
- /**
- * Returns an initialized Mac
for the HmacMD5 algorithm.
- *
- * Every implementation of the Java platform is required to support this standard Mac algorithm.
- *
- *
- * @param key They key for the keyed digest (must not be null)
- * @return A Mac instance initialized with the given key.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- * @see Mac#getInstance(String)
- * @see Mac#init(Key)
- */
- public static Mac getHmacMd5(final byte[] key) {
- return getInitializedMac(HmacAlgorithms.HMAC_MD5, key);
- }
-
- /**
- * Returns an initialized Mac
for the HmacSHA1 algorithm.
- *
- * Every implementation of the Java platform is required to support this standard Mac algorithm.
- *
- *
- * @param key They key for the keyed digest (must not be null)
- * @return A Mac instance initialized with the given key.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- * @see Mac#getInstance(String)
- * @see Mac#init(Key)
- */
- public static Mac getHmacSha1(final byte[] key) {
- return getInitializedMac(HmacAlgorithms.HMAC_SHA_1, key);
- }
-
- /**
- * Returns an initialized Mac
for the HmacSHA256 algorithm.
- *
- * Every implementation of the Java platform is required to support this standard Mac algorithm.
- *
- *
- * @param key They key for the keyed digest (must not be null)
- * @return A Mac instance initialized with the given key.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- * @see Mac#getInstance(String)
- * @see Mac#init(Key)
- */
- public static Mac getHmacSha256(final byte[] key) {
- return getInitializedMac(HmacAlgorithms.HMAC_SHA_256, key);
- }
-
- /**
- * Returns an initialized Mac
for the HmacSHA384 algorithm.
- *
- * Every implementation of the Java platform is not required to support this Mac algorithm.
- *
- *
- * @param key They key for the keyed digest (must not be null)
- * @return A Mac instance initialized with the given key.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- * @see Mac#getInstance(String)
- * @see Mac#init(Key)
- */
- public static Mac getHmacSha384(final byte[] key) {
- return getInitializedMac(HmacAlgorithms.HMAC_SHA_384, key);
- }
-
- /**
- * Returns an initialized Mac
for the HmacSHA512 algorithm.
- *
- * Every implementation of the Java platform is not required to support this Mac algorithm.
- *
- *
- * @param key They key for the keyed digest (must not be null)
- * @return A Mac instance initialized with the given key.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- * @see Mac#getInstance(String)
- * @see Mac#init(Key)
- */
- public static Mac getHmacSha512(final byte[] key) {
- return getInitializedMac(HmacAlgorithms.HMAC_SHA_512, key);
- }
-
- /**
- * Returns an initialized Mac
for the given algorithm
.
- *
- * @param algorithm the name of the algorithm requested. See Appendix
- * A in the Java Cryptography Architecture Reference Guide for information about standard algorithm
- * names.
- * @param key They key for the keyed digest (must not be null)
- * @return A Mac instance initialized with the given key.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- * @see Mac#getInstance(String)
- * @see Mac#init(Key)
- */
- public static Mac getInitializedMac(final HmacAlgorithms algorithm, final byte[] key) {
- return getInitializedMac(algorithm.toString(), key);
- }
-
- /**
- * Returns an initialized Mac
for the given algorithm
.
- *
- * @param algorithm the name of the algorithm requested. See Appendix
- * A in the Java Cryptography Architecture Reference Guide for information about standard algorithm
- * names.
- * @param key They key for the keyed digest (must not be null)
- * @return A Mac instance initialized with the given key.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- * @see Mac#getInstance(String)
- * @see Mac#init(Key)
- */
- public static Mac getInitializedMac(final String algorithm, final byte[] key) {
-
- if (key == null) {
- throw new IllegalArgumentException("Null key");
- }
-
- try {
- final SecretKeySpec keySpec = new SecretKeySpec(key, algorithm);
- final Mac mac = Mac.getInstance(algorithm);
- mac.init(keySpec);
- return mac;
- } catch (final NoSuchAlgorithmException e) {
- throw new IllegalArgumentException(e);
- } catch (final InvalidKeyException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- // hmacMd5
-
- /**
- * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacMD5 MAC for the given key and value
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacMd5(final byte[] key, final byte[] valueToDigest) {
- try {
- return getHmacMd5(key).doFinal(valueToDigest);
- } catch (final IllegalStateException e) {
- // cannot happen
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest
- *
- * The InputStream must not be null and will not be closed
- *
- * @return HmacMD5 MAC for the given key and value
- * @throws IOException If an I/O error occurs.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacMd5(final byte[] key, final InputStream valueToDigest) throws IOException {
- return updateHmac(getHmacMd5(key), valueToDigest).doFinal();
- }
-
- /**
- * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacMD5 MAC for the given key and value
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacMd5(final String key, final String valueToDigest) {
- return hmacMd5(StringUtils.getBytesUtf8(key), StringUtils.getBytesUtf8(valueToDigest));
- }
-
- /**
- * Returns a HmacMD5 Message Authentication Code (MAC) as a hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacMD5 MAC for the given key and value as a hex string (lowercase)
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacMd5Hex(final byte[] key, final byte[] valueToDigest) {
- return Hex.encodeHexString(hmacMd5(key, valueToDigest));
- }
-
- /**
- * Returns a HmacMD5 Message Authentication Code (MAC) as a hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest
- *
- * The InputStream must not be null and will not be closed
- *
- * @return HmacMD5 MAC for the given key and value as a hex string (lowercase)
- * @throws IOException If an I/O error occurs.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacMd5Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
- return Hex.encodeHexString(hmacMd5(key, valueToDigest));
- }
-
- /**
- * Returns a HmacMD5 Message Authentication Code (MAC) as a hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacMD5 MAC for the given key and value as a hex string (lowercase)
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacMd5Hex(final String key, final String valueToDigest) {
- return Hex.encodeHexString(hmacMd5(key, valueToDigest));
- }
-
- // hmacSha1
-
- /**
- * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA1 MAC for the given key and value
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha1(final byte[] key, final byte[] valueToDigest) {
- try {
- return getHmacSha1(key).doFinal(valueToDigest);
- } catch (final IllegalStateException e) {
- // cannot happen
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest
- *
- * The InputStream must not be null and will not be closed
- *
- * @return HmacSHA1 MAC for the given key and value
- * @throws IOException If an I/O error occurs.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha1(final byte[] key, final InputStream valueToDigest) throws IOException {
- return updateHmac(getHmacSha1(key), valueToDigest).doFinal();
- }
-
- /**
- * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA1 MAC for the given key and value
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha1(final String key, final String valueToDigest) {
- return hmacSha1(StringUtils.getBytesUtf8(key), StringUtils.getBytesUtf8(valueToDigest));
- }
-
- /**
- * Returns a HmacSHA1 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA1 MAC for the given key and value as hex string (lowercase)
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha1Hex(final byte[] key, final byte[] valueToDigest) {
- return Hex.encodeHexString(hmacSha1(key, valueToDigest));
- }
-
- /**
- * Returns a HmacSHA1 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest
- *
- * The InputStream must not be null and will not be closed
- *
- * @return HmacSHA1 MAC for the given key and value as hex string (lowercase)
- * @throws IOException If an I/O error occurs.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha1Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
- return Hex.encodeHexString(hmacSha1(key, valueToDigest));
- }
-
- /**
- * Returns a HmacSHA1 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA1 MAC for the given key and value as hex string (lowercase)
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha1Hex(final String key, final String valueToDigest) {
- return Hex.encodeHexString(hmacSha1(key, valueToDigest));
- }
-
- // hmacSha256
-
- /**
- * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA256 MAC for the given key and value
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha256(final byte[] key, final byte[] valueToDigest) {
- try {
- return getHmacSha256(key).doFinal(valueToDigest);
- } catch (final IllegalStateException e) {
- // cannot happen
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest
- *
- * The InputStream must not be null and will not be closed
- *
- * @return HmacSHA256 MAC for the given key and value
- * @throws IOException If an I/O error occurs.
- * s * @throws IllegalArgumentException
- * when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha256(final byte[] key, final InputStream valueToDigest) throws IOException {
- return updateHmac(getHmacSha256(key), valueToDigest).doFinal();
- }
-
- /**
- * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA256 MAC for the given key and value
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha256(final String key, final String valueToDigest) {
- return hmacSha256(StringUtils.getBytesUtf8(key), StringUtils.getBytesUtf8(valueToDigest));
- }
-
- /**
- * Returns a HmacSHA256 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA256 MAC for the given key and value as hex string (lowercase)
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha256Hex(final byte[] key, final byte[] valueToDigest) {
- return Hex.encodeHexString(hmacSha256(key, valueToDigest));
- }
-
- /**
- * Returns a HmacSHA256 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest
- *
- * The InputStream must not be null and will not be closed
- *
- * @return HmacSHA256 MAC for the given key and value as hex string (lowercase)
- * @throws IOException If an I/O error occurs.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha256Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
- return Hex.encodeHexString(hmacSha256(key, valueToDigest));
- }
-
- /**
- * Returns a HmacSHA256 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA256 MAC for the given key and value as hex string (lowercase)
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha256Hex(final String key, final String valueToDigest) {
- return Hex.encodeHexString(hmacSha256(key, valueToDigest));
- }
-
- // hmacSha384
-
- /**
- * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA384 MAC for the given key and value
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha384(final byte[] key, final byte[] valueToDigest) {
- try {
- return getHmacSha384(key).doFinal(valueToDigest);
- } catch (final IllegalStateException e) {
- // cannot happen
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest
- *
- * The InputStream must not be null and will not be closed
- *
- * @return HmacSHA384 MAC for the given key and value
- * @throws IOException If an I/O error occurs.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha384(final byte[] key, final InputStream valueToDigest) throws IOException {
- return updateHmac(getHmacSha384(key), valueToDigest).doFinal();
- }
-
- /**
- * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA384 MAC for the given key and value
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha384(final String key, final String valueToDigest) {
- return hmacSha384(StringUtils.getBytesUtf8(key), StringUtils.getBytesUtf8(valueToDigest));
- }
-
- /**
- * Returns a HmacSHA384 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA384 MAC for the given key and value as hex string (lowercase)
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha384Hex(final byte[] key, final byte[] valueToDigest) {
- return Hex.encodeHexString(hmacSha384(key, valueToDigest));
- }
-
- /**
- * Returns a HmacSHA384 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest
- *
- * The InputStream must not be null and will not be closed
- *
- * @return HmacSHA384 MAC for the given key and value as hex string (lowercase)
- * @throws IOException If an I/O error occurs.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha384Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
- return Hex.encodeHexString(hmacSha384(key, valueToDigest));
- }
-
- /**
- * Returns a HmacSHA384 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA384 MAC for the given key and value as hex string (lowercase)
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha384Hex(final String key, final String valueToDigest) {
- return Hex.encodeHexString(hmacSha384(key, valueToDigest));
- }
-
- // hmacSha512
-
- /**
- * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA512 MAC for the given key and value
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha512(final byte[] key, final byte[] valueToDigest) {
- try {
- return getHmacSha512(key).doFinal(valueToDigest);
- } catch (final IllegalStateException e) {
- // cannot happen
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest
- *
- * The InputStream must not be null and will not be closed
- *
- * @return HmacSHA512 MAC for the given key and value
- * @throws IOException If an I/O error occurs.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha512(final byte[] key, final InputStream valueToDigest) throws IOException {
- return updateHmac(getHmacSha512(key), valueToDigest).doFinal();
- }
-
- /**
- * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA512 MAC for the given key and value
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static byte[] hmacSha512(final String key, final String valueToDigest) {
- return hmacSha512(StringUtils.getBytesUtf8(key), StringUtils.getBytesUtf8(valueToDigest));
- }
-
- /**
- * Returns a HmacSHA512 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA512 MAC for the given key and value as hex string (lowercase)
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha512Hex(final byte[] key, final byte[] valueToDigest) {
- return Hex.encodeHexString(hmacSha512(key, valueToDigest));
- }
-
- /**
- * Returns a HmacSHA512 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest
- *
- * The InputStream must not be null and will not be closed
- *
- * @return HmacSHA512 MAC for the given key and value as hex string (lowercase)
- * @throws IOException If an I/O error occurs.
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha512Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
- return Hex.encodeHexString(hmacSha512(key, valueToDigest));
- }
-
- /**
- * Returns a HmacSHA512 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
- *
- * @param key They key for the keyed digest (must not be null)
- * @param valueToDigest The value (data) which should to digest (maybe empty or null)
- * @return HmacSHA512 MAC for the given key and value as hex string (lowercase)
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
- */
- public static String hmacSha512Hex(final String key, final String valueToDigest) {
- return Hex.encodeHexString(hmacSha512(key, valueToDigest));
- }
-
- // update
-
- /**
- * Updates the given {@link Mac}. This generates a digest for valueToDigest and the key the Mac was initialized
- *
- * @param mac the initialized {@link Mac} to update
- * @param valueToDigest the value to update the {@link Mac} with (maybe null or empty)
- * @return the updated {@link Mac}
- * @throws IllegalStateException if the Mac was not initialized
- * @since 1.x
- */
- public static Mac updateHmac(final Mac mac, final byte[] valueToDigest) {
- mac.reset();
- mac.update(valueToDigest);
- return mac;
- }
-
- /**
- * Updates the given {@link Mac}. This generates a digest for valueToDigest and the key the Mac was initialized
- *
- * @param mac the initialized {@link Mac} to update
- * @param valueToDigest the value to update the {@link Mac} with
- *
- * The InputStream must not be null and will not be closed
- *
- * @return the updated {@link Mac}
- * @throws IOException If an I/O error occurs.
- * @throws IllegalStateException If the Mac was not initialized
- * @since 1.x
- */
- public static Mac updateHmac(final Mac mac, final InputStream valueToDigest) throws IOException {
- mac.reset();
- final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
- int read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
-
- while (read > -1) {
- mac.update(buffer, 0, read);
- read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
- }
-
- return mac;
- }
-
- /**
- * Updates the given {@link Mac}. This generates a digest for valueToDigest and the key the Mac was initialized
- *
- * @param mac the initialized {@link Mac} to update
- * @param valueToDigest the value to update the {@link Mac} with (maybe null or empty)
- * @return the updated {@link Mac}
- * @throws IllegalStateException if the Mac was not initialized
- * @since 1.x
- */
- public static Mac updateHmac(final Mac mac, final String valueToDigest) {
- mac.reset();
- mac.update(StringUtils.getBytesUtf8(valueToDigest));
- return mac;
- }
-}
diff --git a/src/org/apache/commons/codec/digest/Md5Crypt.java b/src/org/apache/commons/codec/digest/Md5Crypt.java
deleted file mode 100644
index 1cb17ef1..00000000
--- a/src/org/apache/commons/codec/digest/Md5Crypt.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.codec.digest;
-
-import java.security.MessageDigest;
-import java.util.Arrays;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.commons.codec.Charsets;
-
-/**
- * The libc crypt() "$1$" and Apache "$apr1$" MD5-based hash algorithm.
- *
- * Based on the public domain ("beer-ware") C implementation from Poul-Henning Kamp which was found at:
- * crypt-md5.c @ freebsd.org
- *
- * Source:
- *
- *
- * $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.1 1999/01/21 13:50:09 brandon Exp $
- *
- *
- * Conversion to Kotlin and from there to Java in 2012.
- *
- * The C style comments are from the original C code, the ones with "//" from the port.
- *
- * This class is immutable and thread-safe.
- *
- * @version $Id$
- * @since 1.7
- */
-public class Md5Crypt {
-
- /**
- * The Identifier of the Apache variant.
- */
- static final String APR1_PREFIX = "$apr1$";
-
- /**
- * The number of bytes of the final hash.
- */
- private static final int BLOCKSIZE = 16;
-
- /**
- * The Identifier of this crypt() variant.
- */
- static final String MD5_PREFIX = "$1$";
-
- /**
- * The number of rounds of the big loop.
- */
- private static final int ROUNDS = 1000;
-
- /**
- * See {@link #apr1Crypt(String, String)} for details.
- *
- * @param keyBytes plaintext string to hash.
- * @return the hash value
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught. *
- */
- public static String apr1Crypt(final byte[] keyBytes) {
- return apr1Crypt(keyBytes, APR1_PREFIX + B64.getRandomSalt(8));
- }
-
- /**
- * See {@link #apr1Crypt(String, String)} for details.
- *
- * @param keyBytes plaintext string to hash.
- * @param salt An APR1 salt.
- * @return the hash value
- * @throws IllegalArgumentException if the salt does not match the allowed pattern
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String apr1Crypt(final byte[] keyBytes, String salt) {
- // to make the md5Crypt regex happy
- if (salt != null && !salt.startsWith(APR1_PREFIX)) {
- salt = APR1_PREFIX + salt;
- }
- return Md5Crypt.md5Crypt(keyBytes, salt, APR1_PREFIX);
- }
-
- /**
- * See {@link #apr1Crypt(String, String)} for details.
- *
- * @param keyBytes plaintext string to hash.
- * @return the hash value
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String apr1Crypt(final String keyBytes) {
- return apr1Crypt(keyBytes.getBytes(Charsets.UTF_8));
- }
-
- /**
- * Generates an Apache htpasswd compatible "$apr1$" MD5 based hash value.
- *
- * The algorithm is identical to the crypt(3) "$1$" one but produces different outputs due to the different salt
- * prefix.
- *
- * @param keyBytes plaintext string to hash.
- * @param salt salt string including the prefix and optionally garbage at the end. Will be generated randomly if
- * null.
- * @return the hash value
- * @throws IllegalArgumentException if the salt does not match the allowed pattern
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String apr1Crypt(final String keyBytes, final String salt) {
- return apr1Crypt(keyBytes.getBytes(Charsets.UTF_8), salt);
- }
-
- /**
- * Generates a libc6 crypt() compatible "$1$" hash value.
- *
- * See {@link Crypt#crypt(String, String)} for details.
- *
- * @param keyBytes plaintext string to hash.
- * @return the hash value
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String md5Crypt(final byte[] keyBytes) {
- return md5Crypt(keyBytes, MD5_PREFIX + B64.getRandomSalt(8));
- }
-
- /**
- * Generates a libc crypt() compatible "$1$" MD5 based hash value.
- *
- * See {@link Crypt#crypt(String, String)} for details.
- *
- * @param keyBytes plaintext string to hash.
- * @param salt salt string including the prefix and optionally garbage at the end. Will be generated randomly if
- * null.
- * @return the hash value
- * @throws IllegalArgumentException if the salt does not match the allowed pattern
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String md5Crypt(final byte[] keyBytes, final String salt) {
- return md5Crypt(keyBytes, salt, MD5_PREFIX);
- }
-
- /**
- * Generates a libc6 crypt() "$1$" or Apache htpasswd "$apr1$" hash value.
- *
- * See {@link Crypt#crypt(String, String)} or {@link #apr1Crypt(String, String)} for details.
- *
- * @param keyBytes plaintext string to hash.
- * @param salt May be null.
- * @param prefix salt prefix
- * @return the hash value
- * @throws IllegalArgumentException if the salt does not match the allowed pattern
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String md5Crypt(final byte[] keyBytes, final String salt, final String prefix) {
- final int keyLen = keyBytes.length;
-
- // Extract the real salt from the given string which can be a complete hash string.
- String saltString;
- if (salt == null) {
- saltString = B64.getRandomSalt(8);
- } else {
- final Pattern p = Pattern.compile("^" + prefix.replace("$", "\\$") + "([\\.\\/a-zA-Z0-9]{1,8}).*");
- final Matcher m = p.matcher(salt);
- if (m == null || !m.find()) {
- throw new IllegalArgumentException("Invalid salt value: " + salt);
- }
- saltString = m.group(1);
- }
- final byte[] saltBytes = saltString.getBytes(Charsets.UTF_8);
-
- final MessageDigest ctx = DigestUtils.getMd5Digest();
-
- /*
- * The password first, since that is what is most unknown
- */
- ctx.update(keyBytes);
-
- /*
- * Then our magic string
- */
- ctx.update(prefix.getBytes(Charsets.UTF_8));
-
- /*
- * Then the raw salt
- */
- ctx.update(saltBytes);
-
- /*
- * Then just as many characters of the MD5(pw,salt,pw)
- */
- MessageDigest ctx1 = DigestUtils.getMd5Digest();
- ctx1.update(keyBytes);
- ctx1.update(saltBytes);
- ctx1.update(keyBytes);
- byte[] finalb = ctx1.digest();
- int ii = keyLen;
- while (ii > 0) {
- ctx.update(finalb, 0, ii > 16 ? 16 : ii);
- ii -= 16;
- }
-
- /*
- * Don't leave anything around in vm they could use.
- */
- Arrays.fill(finalb, (byte) 0);
-
- /*
- * Then something really weird...
- */
- ii = keyLen;
- final int j = 0;
- while (ii > 0) {
- if ((ii & 1) == 1) {
- ctx.update(finalb[j]);
- } else {
- ctx.update(keyBytes[j]);
- }
- ii >>= 1;
- }
-
- /*
- * Now make the output string
- */
- final StringBuilder passwd = new StringBuilder(prefix + saltString + "$");
- finalb = ctx.digest();
-
- /*
- * and now, just to make sure things don't run too fast On a 60 Mhz Pentium this takes 34 msec, so you would
- * need 30 seconds to build a 1000 entry dictionary...
- */
- for (int i = 0; i < ROUNDS; i++) {
- ctx1 = DigestUtils.getMd5Digest();
- if ((i & 1) != 0) {
- ctx1.update(keyBytes);
- } else {
- ctx1.update(finalb, 0, BLOCKSIZE);
- }
-
- if (i % 3 != 0) {
- ctx1.update(saltBytes);
- }
-
- if (i % 7 != 0) {
- ctx1.update(keyBytes);
- }
-
- if ((i & 1) != 0) {
- ctx1.update(finalb, 0, BLOCKSIZE);
- } else {
- ctx1.update(keyBytes);
- }
- finalb = ctx1.digest();
- }
-
- // The following was nearly identical to the Sha2Crypt code.
- // Again, the buflen is not really needed.
- // int buflen = MD5_PREFIX.length() - 1 + salt_string.length() + 1 + BLOCKSIZE + 1;
- B64.b64from24bit(finalb[0], finalb[6], finalb[12], 4, passwd);
- B64.b64from24bit(finalb[1], finalb[7], finalb[13], 4, passwd);
- B64.b64from24bit(finalb[2], finalb[8], finalb[14], 4, passwd);
- B64.b64from24bit(finalb[3], finalb[9], finalb[15], 4, passwd);
- B64.b64from24bit(finalb[4], finalb[10], finalb[5], 4, passwd);
- B64.b64from24bit((byte) 0, (byte) 0, finalb[11], 2, passwd);
-
- /*
- * Don't leave anything around in vm they could use.
- */
- // Is there a better way to do this with the JVM?
- ctx.reset();
- ctx1.reset();
- Arrays.fill(keyBytes, (byte) 0);
- Arrays.fill(saltBytes, (byte) 0);
- Arrays.fill(finalb, (byte) 0);
-
- return passwd.toString();
- }
-}
diff --git a/src/org/apache/commons/codec/digest/MessageDigestAlgorithms.java b/src/org/apache/commons/codec/digest/MessageDigestAlgorithms.java
deleted file mode 100644
index 3fcbea42..00000000
--- a/src/org/apache/commons/codec/digest/MessageDigestAlgorithms.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.digest;
-
-import java.security.MessageDigest;
-
-/**
- * Standard {@link MessageDigest} algorithm names from the Java Cryptography Architecture Standard Algorithm Name
- * Documentation .
- *
- * This class is immutable and thread-safe.
- *
- * TODO 2.0 This should be an enum.
- *
- * @version $Id$
- * @see Java Cryptography
- * Architecture Standard Algorithm Name Documentation
- * @since 1.7
- */
-public class MessageDigestAlgorithms {
-
- private MessageDigestAlgorithms() {
- // cannot be instantiated.
- }
-
- /**
- * The MD2 message digest algorithm defined in RFC 1319.
- */
- public static final String MD2 = "MD2";
-
- /**
- * The MD5 message digest algorithm defined in RFC 1321.
- */
- public static final String MD5 = "MD5";
-
- /**
- * The SHA-1 hash algorithm defined in the FIPS PUB 180-2.
- */
- public static final String SHA_1 = "SHA-1";
-
- /**
- * The SHA-224 hash algorithm defined in the FIPS PUB 180-4.
- *
- * Java 8 only.
- *
- *
- * @since 1.11
- */
- public static final String SHA_224 = "SHA-224";
-
- /**
- * The SHA-256 hash algorithm defined in the FIPS PUB 180-2.
- */
- public static final String SHA_256 = "SHA-256";
-
- /**
- * The SHA-384 hash algorithm defined in the FIPS PUB 180-2.
- */
- public static final String SHA_384 = "SHA-384";
-
- /**
- * The SHA-512 hash algorithm defined in the FIPS PUB 180-2.
- */
- public static final String SHA_512 = "SHA-512";
-}
diff --git a/src/org/apache/commons/codec/digest/Sha2Crypt.java b/src/org/apache/commons/codec/digest/Sha2Crypt.java
deleted file mode 100644
index 966fc54e..00000000
--- a/src/org/apache/commons/codec/digest/Sha2Crypt.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.codec.digest;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.commons.codec.Charsets;
-
-/**
- * SHA2-based Unix crypt implementation.
- *
- * Based on the C implementation released into the Public Domain by Ulrich Drepper <drepper@redhat.com>
- * http://www.akkadia.org/drepper/SHA-crypt.txt
- *
- * Conversion to Kotlin and from there to Java in 2012 by Christian Hammers <ch@lathspell.de> and likewise put
- * into the Public Domain.
- *
- * This class is immutable and thread-safe.
- *
- * @version $Id$
- * @since 1.7
- */
-public class Sha2Crypt {
-
- /**
- * Default number of rounds if not explicitly specified.
- */
- private static final int ROUNDS_DEFAULT = 5000;
-
- /**
- * Maximum number of rounds.
- */
- private static final int ROUNDS_MAX = 999999999;
-
- /**
- * Minimum number of rounds.
- */
- private static final int ROUNDS_MIN = 1000;
-
- /**
- * Prefix for optional rounds specification.
- */
- private static final String ROUNDS_PREFIX = "rounds=";
-
- /**
- * The number of bytes the final hash value will have (SHA-256 variant).
- */
- private static final int SHA256_BLOCKSIZE = 32;
-
- /**
- * The prefixes that can be used to identify this crypt() variant (SHA-256).
- */
- static final String SHA256_PREFIX = "$5$";
-
- /**
- * The number of bytes the final hash value will have (SHA-512 variant).
- */
- private static final int SHA512_BLOCKSIZE = 64;
-
- /**
- * The prefixes that can be used to identify this crypt() variant (SHA-512).
- */
- static final String SHA512_PREFIX = "$6$";
-
- /**
- * The pattern to match valid salt values.
- */
- private static final Pattern SALT_PATTERN = Pattern
- .compile("^\\$([56])\\$(rounds=(\\d+)\\$)?([\\.\\/a-zA-Z0-9]{1,16}).*");
-
- /**
- * Generates a libc crypt() compatible "$5$" hash value with random salt.
- *
- * See {@link Crypt#crypt(String, String)} for details.
- *
- * @param keyBytes plaintext to hash
- * @return complete hash value
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String sha256Crypt(final byte[] keyBytes) {
- return sha256Crypt(keyBytes, null);
- }
-
- /**
- * Generates a libc6 crypt() compatible "$5$" hash value.
- *
- * See {@link Crypt#crypt(String, String)} for details.
- *
- * @param keyBytes plaintext to hash
- * @param salt real salt value without prefix or "rounds="
- * @return complete hash value including salt
- * @throws IllegalArgumentException if the salt does not match the allowed pattern
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String sha256Crypt(final byte[] keyBytes, String salt) {
- if (salt == null) {
- salt = SHA256_PREFIX + B64.getRandomSalt(8);
- }
- return sha2Crypt(keyBytes, salt, SHA256_PREFIX, SHA256_BLOCKSIZE, MessageDigestAlgorithms.SHA_256);
- }
-
- /**
- * Generates a libc6 crypt() compatible "$5$" or "$6$" SHA2 based hash value.
- *
- * This is a nearly line by line conversion of the original C function. The numbered comments are from the algorithm
- * description, the short C-style ones from the original C code and the ones with "Remark" from me.
- *
- * See {@link Crypt#crypt(String, String)} for details.
- *
- * @param keyBytes plaintext to hash
- * @param salt real salt value without prefix or "rounds="
- * @param saltPrefix either $5$ or $6$
- * @param blocksize a value that differs between $5$ and $6$
- * @param algorithm {@link MessageDigest} algorithm identifier string
- * @return complete hash value including prefix and salt
- * @throws IllegalArgumentException if the given salt is null
or does not match the allowed pattern
- * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught
- * @see MessageDigestAlgorithms
- */
- private static String sha2Crypt(final byte[] keyBytes, final String salt, final String saltPrefix,
- final int blocksize, final String algorithm) {
-
- final int keyLen = keyBytes.length;
-
- // Extracts effective salt and the number of rounds from the given salt.
- int rounds = ROUNDS_DEFAULT;
- boolean roundsCustom = false;
- if (salt == null) {
- throw new IllegalArgumentException("Salt must not be null");
- }
-
- final Matcher m = SALT_PATTERN.matcher(salt);
- if (m == null || !m.find()) {
- throw new IllegalArgumentException("Invalid salt value: " + salt);
- }
- if (m.group(3) != null) {
- rounds = Integer.parseInt(m.group(3));
- rounds = Math.max(ROUNDS_MIN, Math.min(ROUNDS_MAX, rounds));
- roundsCustom = true;
- }
- final String saltString = m.group(4);
- final byte[] saltBytes = saltString.getBytes(Charsets.UTF_8);
- final int saltLen = saltBytes.length;
-
- // 1. start digest A
- // Prepare for the real work.
- MessageDigest ctx = DigestUtils.getDigest(algorithm);
-
- // 2. the password string is added to digest A
- /*
- * Add the key string.
- */
- ctx.update(keyBytes);
-
- // 3. the salt string is added to digest A. This is just the salt string
- // itself without the enclosing '$', without the magic salt_prefix $5$ and
- // $6$ respectively and without the rounds= specification.
- //
- // NB: the MD5 algorithm did add the $1$ salt_prefix. This is not deemed
- // necessary since it is a constant string and does not add security
- // and /possibly/ allows a plain text attack. Since the rounds=
- // specification should never be added this would also create an
- // inconsistency.
- /*
- * The last part is the salt string. This must be at most 16 characters and it ends at the first `$' character
- * (for compatibility with existing implementations).
- */
- ctx.update(saltBytes);
-
- // 4. start digest B
- /*
- * Compute alternate sha512 sum with input KEY, SALT, and KEY. The final result will be added to the first
- * context.
- */
- MessageDigest altCtx = DigestUtils.getDigest(algorithm);
-
- // 5. add the password to digest B
- /*
- * Add key.
- */
- altCtx.update(keyBytes);
-
- // 6. add the salt string to digest B
- /*
- * Add salt.
- */
- altCtx.update(saltBytes);
-
- // 7. add the password again to digest B
- /*
- * Add key again.
- */
- altCtx.update(keyBytes);
-
- // 8. finish digest B
- /*
- * Now get result of this (32 bytes) and add it to the other context.
- */
- byte[] altResult = altCtx.digest();
-
- // 9. For each block of 32 or 64 bytes in the password string (excluding
- // the terminating NUL in the C representation), add digest B to digest A
- /*
- * Add for any character in the key one byte of the alternate sum.
- */
- /*
- * (Remark: the C code comment seems wrong for key length > 32!)
- */
- int cnt = keyBytes.length;
- while (cnt > blocksize) {
- ctx.update(altResult, 0, blocksize);
- cnt -= blocksize;
- }
-
- // 10. For the remaining N bytes of the password string add the first
- // N bytes of digest B to digest A
- ctx.update(altResult, 0, cnt);
-
- // 11. For each bit of the binary representation of the length of the
- // password string up to and including the highest 1-digit, starting
- // from to lowest bit position (numeric value 1):
- //
- // a) for a 1-digit add digest B to digest A
- //
- // b) for a 0-digit add the password string
- //
- // NB: this step differs significantly from the MD5 algorithm. It
- // adds more randomness.
- /*
- * Take the binary representation of the length of the key and for every 1 add the alternate sum, for every 0
- * the key.
- */
- cnt = keyBytes.length;
- while (cnt > 0) {
- if ((cnt & 1) != 0) {
- ctx.update(altResult, 0, blocksize);
- } else {
- ctx.update(keyBytes);
- }
- cnt >>= 1;
- }
-
- // 12. finish digest A
- /*
- * Create intermediate result.
- */
- altResult = ctx.digest();
-
- // 13. start digest DP
- /*
- * Start computation of P byte sequence.
- */
- altCtx = DigestUtils.getDigest(algorithm);
-
- // 14. for every byte in the password (excluding the terminating NUL byte
- // in the C representation of the string)
- //
- // add the password to digest DP
- /*
- * For every character in the password add the entire password.
- */
- for (int i = 1; i <= keyLen; i++) {
- altCtx.update(keyBytes);
- }
-
- // 15. finish digest DP
- /*
- * Finish the digest.
- */
- byte[] tempResult = altCtx.digest();
-
- // 16. produce byte sequence P of the same length as the password where
- //
- // a) for each block of 32 or 64 bytes of length of the password string
- // the entire digest DP is used
- //
- // b) for the remaining N (up to 31 or 63) bytes use the first N
- // bytes of digest DP
- /*
- * Create byte sequence P.
- */
- final byte[] pBytes = new byte[keyLen];
- int cp = 0;
- while (cp < keyLen - blocksize) {
- System.arraycopy(tempResult, 0, pBytes, cp, blocksize);
- cp += blocksize;
- }
- System.arraycopy(tempResult, 0, pBytes, cp, keyLen - cp);
-
- // 17. start digest DS
- /*
- * Start computation of S byte sequence.
- */
- altCtx = DigestUtils.getDigest(algorithm);
-
- // 18. repeast the following 16+A[0] times, where A[0] represents the first
- // byte in digest A interpreted as an 8-bit unsigned value
- //
- // add the salt to digest DS
- /*
- * For every character in the password add the entire password.
- */
- for (int i = 1; i <= 16 + (altResult[0] & 0xff); i++) {
- altCtx.update(saltBytes);
- }
-
- // 19. finish digest DS
- /*
- * Finish the digest.
- */
- tempResult = altCtx.digest();
-
- // 20. produce byte sequence S of the same length as the salt string where
- //
- // a) for each block of 32 or 64 bytes of length of the salt string
- // the entire digest DS is used
- //
- // b) for the remaining N (up to 31 or 63) bytes use the first N
- // bytes of digest DS
- /*
- * Create byte sequence S.
- */
- // Remark: The salt is limited to 16 chars, how does this make sense?
- final byte[] sBytes = new byte[saltLen];
- cp = 0;
- while (cp < saltLen - blocksize) {
- System.arraycopy(tempResult, 0, sBytes, cp, blocksize);
- cp += blocksize;
- }
- System.arraycopy(tempResult, 0, sBytes, cp, saltLen - cp);
-
- // 21. repeat a loop according to the number specified in the rounds=
- // specification in the salt (or the default value if none is
- // present). Each round is numbered, starting with 0 and up to N-1.
- //
- // The loop uses a digest as input. In the first round it is the
- // digest produced in step 12. In the latter steps it is the digest
- // produced in step 21.h. The following text uses the notation
- // "digest A/C" to describe this behavior.
- /*
- * Repeatedly run the collected hash value through sha512 to burn CPU cycles.
- */
- for (int i = 0; i <= rounds - 1; i++) {
- // a) start digest C
- /*
- * New context.
- */
- ctx = DigestUtils.getDigest(algorithm);
-
- // b) for odd round numbers add the byte sequense P to digest C
- // c) for even round numbers add digest A/C
- /*
- * Add key or last result.
- */
- if ((i & 1) != 0) {
- ctx.update(pBytes, 0, keyLen);
- } else {
- ctx.update(altResult, 0, blocksize);
- }
-
- // d) for all round numbers not divisible by 3 add the byte sequence S
- /*
- * Add salt for numbers not divisible by 3.
- */
- if (i % 3 != 0) {
- ctx.update(sBytes, 0, saltLen);
- }
-
- // e) for all round numbers not divisible by 7 add the byte sequence P
- /*
- * Add key for numbers not divisible by 7.
- */
- if (i % 7 != 0) {
- ctx.update(pBytes, 0, keyLen);
- }
-
- // f) for odd round numbers add digest A/C
- // g) for even round numbers add the byte sequence P
- /*
- * Add key or last result.
- */
- if ((i & 1) != 0) {
- ctx.update(altResult, 0, blocksize);
- } else {
- ctx.update(pBytes, 0, keyLen);
- }
-
- // h) finish digest C.
- /*
- * Create intermediate result.
- */
- altResult = ctx.digest();
- }
-
- // 22. Produce the output string. This is an ASCII string of the maximum
- // size specified above, consisting of multiple pieces:
- //
- // a) the salt salt_prefix, $5$ or $6$ respectively
- //
- // b) the rounds= specification, if one was present in the input
- // salt string. A trailing '$' is added in this case to separate
- // the rounds specification from the following text.
- //
- // c) the salt string truncated to 16 characters
- //
- // d) a '$' character
- /*
- * Now we can construct the result string. It consists of three parts.
- */
- final StringBuilder buffer = new StringBuilder(saltPrefix);
- if (roundsCustom) {
- buffer.append(ROUNDS_PREFIX);
- buffer.append(rounds);
- buffer.append("$");
- }
- buffer.append(saltString);
- buffer.append("$");
-
- // e) the base-64 encoded final C digest. The encoding used is as
- // follows:
- // [...]
- //
- // Each group of three bytes from the digest produces four
- // characters as output:
- //
- // 1. character: the six low bits of the first byte
- // 2. character: the two high bits of the first byte and the
- // four low bytes from the second byte
- // 3. character: the four high bytes from the second byte and
- // the two low bits from the third byte
- // 4. character: the six high bits from the third byte
- //
- // The groups of three bytes are as follows (in this sequence).
- // These are the indices into the byte array containing the
- // digest, starting with index 0. For the last group there are
- // not enough bytes left in the digest and the value zero is used
- // in its place. This group also produces only three or two
- // characters as output for SHA-512 and SHA-512 respectively.
-
- // This was just a safeguard in the C implementation:
- // int buflen = salt_prefix.length() - 1 + ROUNDS_PREFIX.length() + 9 + 1 + salt_string.length() + 1 + 86 + 1;
-
- if (blocksize == 32) {
- B64.b64from24bit(altResult[0], altResult[10], altResult[20], 4, buffer);
- B64.b64from24bit(altResult[21], altResult[1], altResult[11], 4, buffer);
- B64.b64from24bit(altResult[12], altResult[22], altResult[2], 4, buffer);
- B64.b64from24bit(altResult[3], altResult[13], altResult[23], 4, buffer);
- B64.b64from24bit(altResult[24], altResult[4], altResult[14], 4, buffer);
- B64.b64from24bit(altResult[15], altResult[25], altResult[5], 4, buffer);
- B64.b64from24bit(altResult[6], altResult[16], altResult[26], 4, buffer);
- B64.b64from24bit(altResult[27], altResult[7], altResult[17], 4, buffer);
- B64.b64from24bit(altResult[18], altResult[28], altResult[8], 4, buffer);
- B64.b64from24bit(altResult[9], altResult[19], altResult[29], 4, buffer);
- B64.b64from24bit((byte) 0, altResult[31], altResult[30], 3, buffer);
- } else {
- B64.b64from24bit(altResult[0], altResult[21], altResult[42], 4, buffer);
- B64.b64from24bit(altResult[22], altResult[43], altResult[1], 4, buffer);
- B64.b64from24bit(altResult[44], altResult[2], altResult[23], 4, buffer);
- B64.b64from24bit(altResult[3], altResult[24], altResult[45], 4, buffer);
- B64.b64from24bit(altResult[25], altResult[46], altResult[4], 4, buffer);
- B64.b64from24bit(altResult[47], altResult[5], altResult[26], 4, buffer);
- B64.b64from24bit(altResult[6], altResult[27], altResult[48], 4, buffer);
- B64.b64from24bit(altResult[28], altResult[49], altResult[7], 4, buffer);
- B64.b64from24bit(altResult[50], altResult[8], altResult[29], 4, buffer);
- B64.b64from24bit(altResult[9], altResult[30], altResult[51], 4, buffer);
- B64.b64from24bit(altResult[31], altResult[52], altResult[10], 4, buffer);
- B64.b64from24bit(altResult[53], altResult[11], altResult[32], 4, buffer);
- B64.b64from24bit(altResult[12], altResult[33], altResult[54], 4, buffer);
- B64.b64from24bit(altResult[34], altResult[55], altResult[13], 4, buffer);
- B64.b64from24bit(altResult[56], altResult[14], altResult[35], 4, buffer);
- B64.b64from24bit(altResult[15], altResult[36], altResult[57], 4, buffer);
- B64.b64from24bit(altResult[37], altResult[58], altResult[16], 4, buffer);
- B64.b64from24bit(altResult[59], altResult[17], altResult[38], 4, buffer);
- B64.b64from24bit(altResult[18], altResult[39], altResult[60], 4, buffer);
- B64.b64from24bit(altResult[40], altResult[61], altResult[19], 4, buffer);
- B64.b64from24bit(altResult[62], altResult[20], altResult[41], 4, buffer);
- B64.b64from24bit((byte) 0, (byte) 0, altResult[63], 2, buffer);
- }
-
- /*
- * Clear the buffer for the intermediate result so that people attaching to processes or reading core dumps
- * cannot get any information.
- */
- // Is there a better way to do this with the JVM?
- Arrays.fill(tempResult, (byte) 0);
- Arrays.fill(pBytes, (byte) 0);
- Arrays.fill(sBytes, (byte) 0);
- ctx.reset();
- altCtx.reset();
- Arrays.fill(keyBytes, (byte) 0);
- Arrays.fill(saltBytes, (byte) 0);
-
- return buffer.toString();
- }
-
- /**
- * Generates a libc crypt() compatible "$6$" hash value with random salt.
- *
- * See {@link Crypt#crypt(String, String)} for details.
- *
- * @param keyBytes plaintext to hash
- * @return complete hash value
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String sha512Crypt(final byte[] keyBytes) {
- return sha512Crypt(keyBytes, null);
- }
-
- /**
- * Generates a libc6 crypt() compatible "$6$" hash value.
- *
- * See {@link Crypt#crypt(String, String)} for details.
- *
- * @param keyBytes plaintext to hash
- * @param salt real salt value without prefix or "rounds="
- * @return complete hash value including salt
- * @throws IllegalArgumentException if the salt does not match the allowed pattern
- * @throws RuntimeException when a {@link java.security.NoSuchAlgorithmException} is caught.
- */
- public static String sha512Crypt(final byte[] keyBytes, String salt) {
- if (salt == null) {
- salt = SHA512_PREFIX + B64.getRandomSalt(8);
- }
- return sha2Crypt(keyBytes, salt, SHA512_PREFIX, SHA512_BLOCKSIZE, MessageDigestAlgorithms.SHA_512);
- }
-}
diff --git a/src/org/apache/commons/codec/digest/UnixCrypt.java b/src/org/apache/commons/codec/digest/UnixCrypt.java
deleted file mode 100644
index 7b596194..00000000
--- a/src/org/apache/commons/codec/digest/UnixCrypt.java
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.codec.digest;
-
-import java.util.Random;
-
-import org.apache.commons.codec.Charsets;
-
-/**
- * Unix crypt(3) algorithm implementation.
- *
- * This class only implements the traditional 56 bit DES based algorithm. Please use DigestUtils.crypt() for a method
- * that distinguishes between all the algorithms supported in the current glibc's crypt().
- *
- * The Java implementation was taken from the JetSpeed Portal project (see
- * org.apache.jetspeed.services.security.ldap.UnixCrypt).
- *
- * This class is slightly incompatible if the given salt contains characters that are not part of the allowed range
- * [a-zA-Z0-9./].
- *
- * This class is immutable and thread-safe.
- *
- * @version $Id$
- * @since 1.7
- */
-public class UnixCrypt {
-
- private static final int CON_SALT[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0};
-
- private static final int COV2CHAR[] = {46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
- 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102,
- 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122};
-
- private static final char SALT_CHARS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
- .toCharArray();
-
- private static final boolean SHIFT2[] = {false, false, true, true, true, true, true, true, false, true, true,
- true, true, true, true, false};
-
- private static final int SKB[][] = {
- {0, 16, 0x20000000, 0x20000010, 0x10000, 0x10010, 0x20010000, 0x20010010, 2048, 2064, 0x20000800,
- 0x20000810, 0x10800, 0x10810, 0x20010800, 0x20010810, 32, 48, 0x20000020, 0x20000030, 0x10020,
- 0x10030, 0x20010020, 0x20010030, 2080, 2096, 0x20000820, 0x20000830, 0x10820, 0x10830, 0x20010820,
- 0x20010830, 0x80000, 0x80010, 0x20080000, 0x20080010, 0x90000, 0x90010, 0x20090000, 0x20090010,
- 0x80800, 0x80810, 0x20080800, 0x20080810, 0x90800, 0x90810, 0x20090800, 0x20090810, 0x80020,
- 0x80030, 0x20080020, 0x20080030, 0x90020, 0x90030, 0x20090020, 0x20090030, 0x80820, 0x80830,
- 0x20080820, 0x20080830, 0x90820, 0x90830, 0x20090820, 0x20090830},
- {0, 0x2000000, 8192, 0x2002000, 0x200000, 0x2200000, 0x202000, 0x2202000, 4, 0x2000004, 8196, 0x2002004,
- 0x200004, 0x2200004, 0x202004, 0x2202004, 1024, 0x2000400, 9216, 0x2002400, 0x200400, 0x2200400,
- 0x202400, 0x2202400, 1028, 0x2000404, 9220, 0x2002404, 0x200404, 0x2200404, 0x202404, 0x2202404,
- 0x10000000, 0x12000000, 0x10002000, 0x12002000, 0x10200000, 0x12200000, 0x10202000, 0x12202000,
- 0x10000004, 0x12000004, 0x10002004, 0x12002004, 0x10200004, 0x12200004, 0x10202004, 0x12202004,
- 0x10000400, 0x12000400, 0x10002400, 0x12002400, 0x10200400, 0x12200400, 0x10202400, 0x12202400,
- 0x10000404, 0x12000404, 0x10002404, 0x12002404, 0x10200404, 0x12200404, 0x10202404, 0x12202404},
- {0, 1, 0x40000, 0x40001, 0x1000000, 0x1000001, 0x1040000, 0x1040001, 2, 3, 0x40002, 0x40003, 0x1000002,
- 0x1000003, 0x1040002, 0x1040003, 512, 513, 0x40200, 0x40201, 0x1000200, 0x1000201, 0x1040200,
- 0x1040201, 514, 515, 0x40202, 0x40203, 0x1000202, 0x1000203, 0x1040202, 0x1040203, 0x8000000,
- 0x8000001, 0x8040000, 0x8040001, 0x9000000, 0x9000001, 0x9040000, 0x9040001, 0x8000002, 0x8000003,
- 0x8040002, 0x8040003, 0x9000002, 0x9000003, 0x9040002, 0x9040003, 0x8000200, 0x8000201, 0x8040200,
- 0x8040201, 0x9000200, 0x9000201, 0x9040200, 0x9040201, 0x8000202, 0x8000203, 0x8040202, 0x8040203,
- 0x9000202, 0x9000203, 0x9040202, 0x9040203},
- {0, 0x100000, 256, 0x100100, 8, 0x100008, 264, 0x100108, 4096, 0x101000, 4352, 0x101100, 4104, 0x101008,
- 4360, 0x101108, 0x4000000, 0x4100000, 0x4000100, 0x4100100, 0x4000008, 0x4100008, 0x4000108,
- 0x4100108, 0x4001000, 0x4101000, 0x4001100, 0x4101100, 0x4001008, 0x4101008, 0x4001108, 0x4101108,
- 0x20000, 0x120000, 0x20100, 0x120100, 0x20008, 0x120008, 0x20108, 0x120108, 0x21000, 0x121000,
- 0x21100, 0x121100, 0x21008, 0x121008, 0x21108, 0x121108, 0x4020000, 0x4120000, 0x4020100,
- 0x4120100, 0x4020008, 0x4120008, 0x4020108, 0x4120108, 0x4021000, 0x4121000, 0x4021100, 0x4121100,
- 0x4021008, 0x4121008, 0x4021108, 0x4121108},
- {0, 0x10000000, 0x10000, 0x10010000, 4, 0x10000004, 0x10004, 0x10010004, 0x20000000, 0x30000000,
- 0x20010000, 0x30010000, 0x20000004, 0x30000004, 0x20010004, 0x30010004, 0x100000, 0x10100000,
- 0x110000, 0x10110000, 0x100004, 0x10100004, 0x110004, 0x10110004, 0x20100000, 0x30100000,
- 0x20110000, 0x30110000, 0x20100004, 0x30100004, 0x20110004, 0x30110004, 4096, 0x10001000, 0x11000,
- 0x10011000, 4100, 0x10001004, 0x11004, 0x10011004, 0x20001000, 0x30001000, 0x20011000, 0x30011000,
- 0x20001004, 0x30001004, 0x20011004, 0x30011004, 0x101000, 0x10101000, 0x111000, 0x10111000,
- 0x101004, 0x10101004, 0x111004, 0x10111004, 0x20101000, 0x30101000, 0x20111000, 0x30111000,
- 0x20101004, 0x30101004, 0x20111004, 0x30111004},
- {0, 0x8000000, 8, 0x8000008, 1024, 0x8000400, 1032, 0x8000408, 0x20000, 0x8020000, 0x20008, 0x8020008,
- 0x20400, 0x8020400, 0x20408, 0x8020408, 1, 0x8000001, 9, 0x8000009, 1025, 0x8000401, 1033,
- 0x8000409, 0x20001, 0x8020001, 0x20009, 0x8020009, 0x20401, 0x8020401, 0x20409, 0x8020409,
- 0x2000000, 0xa000000, 0x2000008, 0xa000008, 0x2000400, 0xa000400, 0x2000408, 0xa000408, 0x2020000,
- 0xa020000, 0x2020008, 0xa020008, 0x2020400, 0xa020400, 0x2020408, 0xa020408, 0x2000001, 0xa000001,
- 0x2000009, 0xa000009, 0x2000401, 0xa000401, 0x2000409, 0xa000409, 0x2020001, 0xa020001, 0x2020009,
- 0xa020009, 0x2020401, 0xa020401, 0x2020409, 0xa020409},
- {0, 256, 0x80000, 0x80100, 0x1000000, 0x1000100, 0x1080000, 0x1080100, 16, 272, 0x80010, 0x80110,
- 0x1000010, 0x1000110, 0x1080010, 0x1080110, 0x200000, 0x200100, 0x280000, 0x280100, 0x1200000,
- 0x1200100, 0x1280000, 0x1280100, 0x200010, 0x200110, 0x280010, 0x280110, 0x1200010, 0x1200110,
- 0x1280010, 0x1280110, 512, 768, 0x80200, 0x80300, 0x1000200, 0x1000300, 0x1080200, 0x1080300, 528,
- 784, 0x80210, 0x80310, 0x1000210, 0x1000310, 0x1080210, 0x1080310, 0x200200, 0x200300, 0x280200,
- 0x280300, 0x1200200, 0x1200300, 0x1280200, 0x1280300, 0x200210, 0x200310, 0x280210, 0x280310,
- 0x1200210, 0x1200310, 0x1280210, 0x1280310},
- {0, 0x4000000, 0x40000, 0x4040000, 2, 0x4000002, 0x40002, 0x4040002, 8192, 0x4002000, 0x42000, 0x4042000,
- 8194, 0x4002002, 0x42002, 0x4042002, 32, 0x4000020, 0x40020, 0x4040020, 34, 0x4000022, 0x40022,
- 0x4040022, 8224, 0x4002020, 0x42020, 0x4042020, 8226, 0x4002022, 0x42022, 0x4042022, 2048,
- 0x4000800, 0x40800, 0x4040800, 2050, 0x4000802, 0x40802, 0x4040802, 10240, 0x4002800, 0x42800,
- 0x4042800, 10242, 0x4002802, 0x42802, 0x4042802, 2080, 0x4000820, 0x40820, 0x4040820, 2082,
- 0x4000822, 0x40822, 0x4040822, 10272, 0x4002820, 0x42820, 0x4042820, 10274, 0x4002822, 0x42822,
- 0x4042822}};
-
- private static final int SPTRANS[][] = {
- {0x820200, 0x20000, 0x80800000, 0x80820200, 0x800000, 0x80020200, 0x80020000, 0x80800000, 0x80020200,
- 0x820200, 0x820000, 0x80000200, 0x80800200, 0x800000, 0, 0x80020000, 0x20000, 0x80000000,
- 0x800200, 0x20200, 0x80820200, 0x820000, 0x80000200, 0x800200, 0x80000000, 512, 0x20200,
- 0x80820000, 512, 0x80800200, 0x80820000, 0, 0, 0x80820200, 0x800200, 0x80020000, 0x820200,
- 0x20000, 0x80000200, 0x800200, 0x80820000, 512, 0x20200, 0x80800000, 0x80020200, 0x80000000,
- 0x80800000, 0x820000, 0x80820200, 0x20200, 0x820000, 0x80800200, 0x800000, 0x80000200, 0x80020000,
- 0, 0x20000, 0x800000, 0x80800200, 0x820200, 0x80000000, 0x80820000, 512, 0x80020200},
- {0x10042004, 0, 0x42000, 0x10040000, 0x10000004, 8196, 0x10002000, 0x42000, 8192, 0x10040004, 4,
- 0x10002000, 0x40004, 0x10042000, 0x10040000, 4, 0x40000, 0x10002004, 0x10040004, 8192, 0x42004,
- 0x10000000, 0, 0x40004, 0x10002004, 0x42004, 0x10042000, 0x10000004, 0x10000000, 0x40000, 8196,
- 0x10042004, 0x40004, 0x10042000, 0x10002000, 0x42004, 0x10042004, 0x40004, 0x10000004, 0,
- 0x10000000, 8196, 0x40000, 0x10040004, 8192, 0x10000000, 0x42004, 0x10002004, 0x10042000, 8192, 0,
- 0x10000004, 4, 0x10042004, 0x42000, 0x10040000, 0x10040004, 0x40000, 8196, 0x10002000, 0x10002004,
- 4, 0x10040000, 0x42000},
- {0x41000000, 0x1010040, 64, 0x41000040, 0x40010000, 0x1000000, 0x41000040, 0x10040, 0x1000040, 0x10000,
- 0x1010000, 0x40000000, 0x41010040, 0x40000040, 0x40000000, 0x41010000, 0, 0x40010000, 0x1010040,
- 64, 0x40000040, 0x41010040, 0x10000, 0x41000000, 0x41010000, 0x1000040, 0x40010040, 0x1010000,
- 0x10040, 0, 0x1000000, 0x40010040, 0x1010040, 64, 0x40000000, 0x10000, 0x40000040, 0x40010000,
- 0x1010000, 0x41000040, 0, 0x1010040, 0x10040, 0x41010000, 0x40010000, 0x1000000, 0x41010040,
- 0x40000000, 0x40010040, 0x41000000, 0x1000000, 0x41010040, 0x10000, 0x1000040, 0x41000040,
- 0x10040, 0x1000040, 0, 0x41010000, 0x40000040, 0x41000000, 0x40010040, 64, 0x1010000},
- {0x100402, 0x4000400, 2, 0x4100402, 0, 0x4100000, 0x4000402, 0x100002, 0x4100400, 0x4000002, 0x4000000,
- 1026, 0x4000002, 0x100402, 0x100000, 0x4000000, 0x4100002, 0x100400, 1024, 2, 0x100400, 0x4000402,
- 0x4100000, 1024, 1026, 0, 0x100002, 0x4100400, 0x4000400, 0x4100002, 0x4100402, 0x100000,
- 0x4100002, 1026, 0x100000, 0x4000002, 0x100400, 0x4000400, 2, 0x4100000, 0x4000402, 0, 1024,
- 0x100002, 0, 0x4100002, 0x4100400, 1024, 0x4000000, 0x4100402, 0x100402, 0x100000, 0x4100402, 2,
- 0x4000400, 0x100402, 0x100002, 0x100400, 0x4100000, 0x4000402, 1026, 0x4000000, 0x4000002,
- 0x4100400},
- {0x2000000, 16384, 256, 0x2004108, 0x2004008, 0x2000100, 16648, 0x2004000, 16384, 8, 0x2000008, 16640,
- 0x2000108, 0x2004008, 0x2004100, 0, 16640, 0x2000000, 16392, 264, 0x2000100, 16648, 0, 0x2000008,
- 8, 0x2000108, 0x2004108, 16392, 0x2004000, 256, 264, 0x2004100, 0x2004100, 0x2000108, 16392,
- 0x2004000, 16384, 8, 0x2000008, 0x2000100, 0x2000000, 16640, 0x2004108, 0, 16648, 0x2000000, 256,
- 16392, 0x2000108, 256, 0, 0x2004108, 0x2004008, 0x2004100, 264, 16384, 16640, 0x2004008,
- 0x2000100, 264, 8, 16648, 0x2004000, 0x2000008},
- {0x20000010, 0x80010, 0, 0x20080800, 0x80010, 2048, 0x20000810, 0x80000, 2064, 0x20080810, 0x80800,
- 0x20000000, 0x20000800, 0x20000010, 0x20080000, 0x80810, 0x80000, 0x20000810, 0x20080010, 0, 2048,
- 16, 0x20080800, 0x20080010, 0x20080810, 0x20080000, 0x20000000, 2064, 16, 0x80800, 0x80810,
- 0x20000800, 2064, 0x20000000, 0x20000800, 0x80810, 0x20080800, 0x80010, 0, 0x20000800, 0x20000000,
- 2048, 0x20080010, 0x80000, 0x80010, 0x20080810, 0x80800, 16, 0x20080810, 0x80800, 0x80000,
- 0x20000810, 0x20000010, 0x20080000, 0x80810, 0, 2048, 0x20000010, 0x20000810, 0x20080800,
- 0x20080000, 2064, 16, 0x20080010},
- {4096, 128, 0x400080, 0x400001, 0x401081, 4097, 4224, 0, 0x400000, 0x400081, 129, 0x401000, 1, 0x401080,
- 0x401000, 129, 0x400081, 4096, 4097, 0x401081, 0, 0x400080, 0x400001, 4224, 0x401001, 4225,
- 0x401080, 1, 4225, 0x401001, 128, 0x400000, 4225, 0x401000, 0x401001, 129, 4096, 128, 0x400000,
- 0x401001, 0x400081, 4225, 4224, 0, 128, 0x400001, 1, 0x400080, 0, 0x400081, 0x400080, 4224, 129,
- 4096, 0x401081, 0x400000, 0x401080, 1, 4097, 0x401081, 0x400001, 0x401080, 0x401000, 4097},
- {0x8200020, 0x8208000, 32800, 0, 0x8008000, 0x200020, 0x8200000, 0x8208020, 32, 0x8000000, 0x208000,
- 32800, 0x208020, 0x8008020, 0x8000020, 0x8200000, 32768, 0x208020, 0x200020, 0x8008000, 0x8208020,
- 0x8000020, 0, 0x208000, 0x8000000, 0x200000, 0x8008020, 0x8200020, 0x200000, 32768, 0x8208000, 32,
- 0x200000, 32768, 0x8000020, 0x8208020, 32800, 0x8000000, 0, 0x208000, 0x8200020, 0x8008020,
- 0x8008000, 0x200020, 0x8208000, 32, 0x200020, 0x8008000, 0x8208020, 0x200000, 0x8200000,
- 0x8000020, 0x208000, 32800, 0x8008020, 0x8200000, 32, 0x8208000, 0x208020, 0, 0x8000000,
- 0x8200020, 32768, 0x208020}};
-
- /**
- * Generates a crypt(3) compatible hash using the DES algorithm.
- *
- * As no salt is given, a random one will be used.
- *
- * @param original plaintext password
- * @return a 13 character string starting with the salt string
- */
- public static String crypt(final byte[] original) {
- return crypt(original, null);
- }
-
- /**
- * Generates a crypt(3) compatible hash using the DES algorithm.
- *
- * Using unspecified characters as salt results incompatible hash values.
- *
- * @param original plaintext password
- * @param salt a two character string drawn from [a-zA-Z0-9./] or null for a random one
- * @return a 13 character string starting with the salt string
- * @throws IllegalArgumentException if the salt does not match the allowed pattern
- */
- public static String crypt(final byte[] original, String salt) {
- if (salt == null) {
- final Random randomGenerator = new Random();
- final int numSaltChars = SALT_CHARS.length;
- salt = "" + SALT_CHARS[randomGenerator.nextInt(numSaltChars)] +
- SALT_CHARS[randomGenerator.nextInt(numSaltChars)];
- } else if (!salt.matches("^[" + B64.B64T + "]{2,}$")) {
- throw new IllegalArgumentException("Invalid salt value: " + salt);
- }
-
- final StringBuilder buffer = new StringBuilder(" ");
- final char charZero = salt.charAt(0);
- final char charOne = salt.charAt(1);
- buffer.setCharAt(0, charZero);
- buffer.setCharAt(1, charOne);
- final int eSwap0 = CON_SALT[charZero];
- final int eSwap1 = CON_SALT[charOne] << 4;
- final byte key[] = new byte[8];
- for (int i = 0; i < key.length; i++) {
- key[i] = 0;
- }
-
- for (int i = 0; i < key.length && i < original.length; i++) {
- final int iChar = original[i];
- key[i] = (byte) (iChar << 1);
- }
-
- final int schedule[] = desSetKey(key);
- final int out[] = body(schedule, eSwap0, eSwap1);
- final byte b[] = new byte[9];
- intToFourBytes(out[0], b, 0);
- intToFourBytes(out[1], b, 4);
- b[8] = 0;
- int i = 2;
- int y = 0;
- int u = 128;
- for (; i < 13; i++) {
- int j = 0;
- int c = 0;
- for (; j < 6; j++) {
- c <<= 1;
- if ((b[y] & u) != 0) {
- c |= 0x1;
- }
- u >>>= 1;
- if (u == 0) {
- y++;
- u = 128;
- }
- buffer.setCharAt(i, (char) COV2CHAR[c]);
- }
- }
- return buffer.toString();
- }
-
- /**
- * Generates a crypt(3) compatible hash using the DES algorithm.
- *
- * As no salt is given, a random one is used.
- *
- * @param original plaintext password
- * @return a 13 character string starting with the salt string
- */
- public static String crypt(final String original) {
- return crypt(original.getBytes(Charsets.UTF_8));
- }
-
- /**
- * Generates a crypt(3) compatible hash using the DES algorithm.
- *
- * @param original plaintext password
- * @param salt a two character string drawn from [a-zA-Z0-9./] or null for a random one
- * @return a 13 character string starting with the salt string
- * @throws IllegalArgumentException if the salt does not match the allowed pattern
- */
- public static String crypt(final String original, final String salt) {
- return crypt(original.getBytes(Charsets.UTF_8), salt);
- }
-
- private static int[] body(final int schedule[], final int eSwap0, final int eSwap1) {
- int left = 0;
- int right = 0;
- int t = 0;
- for (int j = 0; j < 25; j++) {
- for (int i = 0; i < 32; i += 4) {
- left = dEncrypt(left, right, i, eSwap0, eSwap1, schedule);
- right = dEncrypt(right, left, i + 2, eSwap0, eSwap1, schedule);
- }
- t = left;
- left = right;
- right = t;
- }
-
- t = right;
- right = left >>> 1 | left << 31;
- left = t >>> 1 | t << 31;
- final int results[] = new int[2];
- permOp(right, left, 1, 0x55555555, results);
- right = results[0];
- left = results[1];
- permOp(left, right, 8, 0xff00ff, results);
- left = results[0];
- right = results[1];
- permOp(right, left, 2, 0x33333333, results);
- right = results[0];
- left = results[1];
- permOp(left, right, 16, 65535, results);
- left = results[0];
- right = results[1];
- permOp(right, left, 4, 0xf0f0f0f, results);
- right = results[0];
- left = results[1];
- final int out[] = new int[2];
- out[0] = left;
- out[1] = right;
- return out;
- }
-
- private static int byteToUnsigned(final byte b) {
- final int value = b;
- return value < 0 ? value + 256 : value;
- }
-
- private static int dEncrypt(int el, final int r, final int s, final int e0, final int e1, final int sArr[]) {
- int v = r ^ r >>> 16;
- int u = v & e0;
- v &= e1;
- u = u ^ u << 16 ^ r ^ sArr[s];
- int t = v ^ v << 16 ^ r ^ sArr[s + 1];
- t = t >>> 4 | t << 28;
- el ^= SPTRANS[1][t & 0x3f] | SPTRANS[3][t >>> 8 & 0x3f] | SPTRANS[5][t >>> 16 & 0x3f] |
- SPTRANS[7][t >>> 24 & 0x3f] | SPTRANS[0][u & 0x3f] | SPTRANS[2][u >>> 8 & 0x3f] |
- SPTRANS[4][u >>> 16 & 0x3f] | SPTRANS[6][u >>> 24 & 0x3f];
- return el;
- }
-
- private static int[] desSetKey(final byte key[]) {
- final int schedule[] = new int[32];
- int c = fourBytesToInt(key, 0);
- int d = fourBytesToInt(key, 4);
- final int results[] = new int[2];
- permOp(d, c, 4, 0xf0f0f0f, results);
- d = results[0];
- c = results[1];
- c = hPermOp(c, -2, 0xcccc0000);
- d = hPermOp(d, -2, 0xcccc0000);
- permOp(d, c, 1, 0x55555555, results);
- d = results[0];
- c = results[1];
- permOp(c, d, 8, 0xff00ff, results);
- c = results[0];
- d = results[1];
- permOp(d, c, 1, 0x55555555, results);
- d = results[0];
- c = results[1];
- d = (d & 0xff) << 16 | d & 0xff00 | (d & 0xff0000) >>> 16 | (c & 0xf0000000) >>> 4;
- c &= 0xfffffff;
- int j = 0;
- for (int i = 0; i < 16; i++) {
- if (SHIFT2[i]) {
- c = c >>> 2 | c << 26;
- d = d >>> 2 | d << 26;
- } else {
- c = c >>> 1 | c << 27;
- d = d >>> 1 | d << 27;
- }
- c &= 0xfffffff;
- d &= 0xfffffff;
- int s = SKB[0][c & 0x3f] | SKB[1][c >>> 6 & 0x3 | c >>> 7 & 0x3c] |
- SKB[2][c >>> 13 & 0xf | c >>> 14 & 0x30] |
- SKB[3][c >>> 20 & 0x1 | c >>> 21 & 0x6 | c >>> 22 & 0x38];
- final int t = SKB[4][d & 0x3f] | SKB[5][d >>> 7 & 0x3 | d >>> 8 & 0x3c] | SKB[6][d >>> 15 & 0x3f] |
- SKB[7][d >>> 21 & 0xf | d >>> 22 & 0x30];
- schedule[j++] = (t << 16 | s & 0xffff);
- s = s >>> 16 | t & 0xffff0000;
- s = s << 4 | s >>> 28;
- schedule[j++] = s;
- }
-
- return schedule;
- }
-
- private static int fourBytesToInt(final byte b[], int offset) {
- int value = byteToUnsigned(b[offset++]);
- value |= byteToUnsigned(b[offset++]) << 8;
- value |= byteToUnsigned(b[offset++]) << 16;
- value |= byteToUnsigned(b[offset++]) << 24;
- return value;
- }
-
- private static int hPermOp(int a, final int n, final int m) {
- final int t = (a << 16 - n ^ a) & m;
- a = a ^ t ^ t >>> 16 - n;
- return a;
- }
-
- private static void intToFourBytes(final int iValue, final byte b[], int offset) {
- b[offset++] = (byte) (iValue & 0xff);
- b[offset++] = (byte) (iValue >>> 8 & 0xff);
- b[offset++] = (byte) (iValue >>> 16 & 0xff);
- b[offset++] = (byte) (iValue >>> 24 & 0xff);
- }
-
- private static void permOp(int a, int b, final int n, final int m, final int results[]) {
- final int t = (a >>> n ^ b) & m;
- a ^= t << n;
- b ^= t;
- results[0] = a;
- results[1] = b;
- }
-}
diff --git a/src/org/apache/commons/codec/digest/package.html b/src/org/apache/commons/codec/digest/package.html
deleted file mode 100644
index ccfbe300..00000000
--- a/src/org/apache/commons/codec/digest/package.html
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-Simplifies common {@link java.security.MessageDigest} tasks and
-includes a libc crypt(3) compatible crypt method that supports DES,
-MD5, SHA-256 and SHA-512 based algorithms as well as the Apache
-specific "$apr1$" variant.
-
-
diff --git a/src/org/apache/commons/codec/language/AbstractCaverphone.java b/src/org/apache/commons/codec/language/AbstractCaverphone.java
deleted file mode 100644
index 0ffd7b4f..00000000
--- a/src/org/apache/commons/codec/language/AbstractCaverphone.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Encodes a string into a Caverphone value.
- *
- * This is an algorithm created by the Caversham Project at the University of Otago. It implements the Caverphone 2.0
- * algorithm:
- *
- *
This class is immutable and thread-safe.
- *
- * @version $Id: Caverphone.java 1075947 2011-03-01 17:56:14Z ggregory $
- * @see Wikipedia - Caverphone
- * @since 1.5
- */
-public abstract class AbstractCaverphone implements StringEncoder {
-
- /**
- * Creates an instance of the Caverphone encoder
- */
- public AbstractCaverphone() {
- super();
- }
-
- /**
- * Encodes an Object using the caverphone algorithm. This method is provided in order to satisfy the requirements of
- * the Encoder interface, and will throw an EncoderException if the supplied object is not of type java.lang.String.
- *
- * @param source Object to encode
- * @return An object (or type java.lang.String) containing the caverphone code which corresponds to the String
- * supplied.
- * @throws EncoderException if the parameter supplied is not of type java.lang.String
- */
- @Override
- public Object encode(final Object source) throws EncoderException {
- if (!(source instanceof String)) {
- throw new EncoderException("Parameter supplied to Caverphone encode is not of type java.lang.String");
- }
- return this.encode((String) source);
- }
-
- /**
- * Tests if the encodings of two strings are equal.
- *
- * This method might be promoted to a new AbstractStringEncoder superclass.
- *
- * @param str1 First of two strings to compare
- * @param str2 Second of two strings to compare
- * @return true
if the encodings of these strings are identical, false
otherwise.
- * @throws EncoderException thrown if there is an error condition during the encoding process.
- */
- public boolean isEncodeEqual(final String str1, final String str2) throws EncoderException {
- return this.encode(str1).equals(this.encode(str2));
- }
-}
diff --git a/src/org/apache/commons/codec/language/Caverphone.java b/src/org/apache/commons/codec/language/Caverphone.java
deleted file mode 100644
index 05e38961..00000000
--- a/src/org/apache/commons/codec/language/Caverphone.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Encodes a string into a Caverphone 2.0 value. Delegate to a {@link Caverphone2} instance.
- *
- * This is an algorithm created by the Caversham Project at the University of Otago. It implements the Caverphone 2.0
- * algorithm:
- *
- * @version $Id: Caverphone.java 1079535 2011-03-08 20:54:37Z ggregory $
- * @see Wikipedia - Caverphone
- * @see Caverphone 2.0 specification
- * @since 1.4
- * @deprecated 1.5 Replaced by {@link Caverphone2}, will be removed in 2.0.
- */
-@Deprecated
-public class Caverphone implements StringEncoder {
-
- /**
- * Delegate to a {@link Caverphone2} instance to avoid code duplication.
- */
- final private Caverphone2 encoder = new Caverphone2();
-
- /**
- * Creates an instance of the Caverphone encoder
- */
- public Caverphone() {
- super();
- }
-
- /**
- * Encodes the given String into a Caverphone value.
- *
- * @param source String the source string
- * @return A caverphone code for the given String
- */
- public String caverphone(final String source) {
- return this.encoder.encode(source);
- }
-
- /**
- * Encodes an Object using the caverphone algorithm. This method is provided in order to satisfy the requirements of
- * the Encoder interface, and will throw an EncoderException if the supplied object is not of type java.lang.String.
- *
- * @param obj Object to encode
- * @return An object (or type java.lang.String) containing the caverphone code which corresponds to the String
- * supplied.
- * @throws EncoderException if the parameter supplied is not of type java.lang.String
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (!(obj instanceof String)) {
- throw new EncoderException("Parameter supplied to Caverphone encode is not of type java.lang.String");
- }
- return this.caverphone((String) obj);
- }
-
- /**
- * Encodes a String using the Caverphone algorithm.
- *
- * @param str String object to encode
- * @return The caverphone code corresponding to the String supplied
- */
- @Override
- public String encode(final String str) {
- return this.caverphone(str);
- }
-
- /**
- * Tests if the caverphones of two strings are identical.
- *
- * @param str1 First of two strings to compare
- * @param str2 Second of two strings to compare
- * @return true
if the caverphones of these strings are identical, false
otherwise.
- */
- public boolean isCaverphoneEqual(final String str1, final String str2) {
- return this.caverphone(str1).equals(this.caverphone(str2));
- }
-}
diff --git a/src/org/apache/commons/codec/language/Caverphone1.java b/src/org/apache/commons/codec/language/Caverphone1.java
deleted file mode 100644
index 25fe749f..00000000
--- a/src/org/apache/commons/codec/language/Caverphone1.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language;
-
-/**
- * Encodes a string into a Caverphone 1.0 value.
- *
- * This is an algorithm created by the Caversham Project at the University of Otago. It implements the Caverphone 1.0
- * algorithm:
- *
- * @version $Id: Caverphone.java 1075947 2011-03-01 17:56:14Z ggregory $
- * @see Wikipedia - Caverphone
- * @see Caverphone 1.0 specification
- * @since 1.5
- *
- *
This class is immutable and thread-safe.
- */
-public class Caverphone1 extends AbstractCaverphone {
-
- private static final String SIX_1 = "111111";
-
- /**
- * Encodes the given String into a Caverphone value.
- *
- * @param source String the source string
- * @return A caverphone code for the given String
- */
- @Override
- public String encode(final String source) {
- String txt = source;
- if (txt == null || txt.length() == 0) {
- return SIX_1;
- }
-
- // 1. Convert to lowercase
- txt = txt.toLowerCase(java.util.Locale.ENGLISH);
-
- // 2. Remove anything not A-Z
- txt = txt.replaceAll("[^a-z]", "");
-
- // 3. Handle various start options
- // 2 is a temporary placeholder to indicate a consonant which we are no longer interested in.
- txt = txt.replaceAll("^cough", "cou2f");
- txt = txt.replaceAll("^rough", "rou2f");
- txt = txt.replaceAll("^tough", "tou2f");
- txt = txt.replaceAll("^enough", "enou2f");
- txt = txt.replaceAll("^gn", "2n");
-
- // End
- txt = txt.replaceAll("mb$", "m2");
-
- // 4. Handle replacements
- txt = txt.replaceAll("cq", "2q");
- txt = txt.replaceAll("ci", "si");
- txt = txt.replaceAll("ce", "se");
- txt = txt.replaceAll("cy", "sy");
- txt = txt.replaceAll("tch", "2ch");
- txt = txt.replaceAll("c", "k");
- txt = txt.replaceAll("q", "k");
- txt = txt.replaceAll("x", "k");
- txt = txt.replaceAll("v", "f");
- txt = txt.replaceAll("dg", "2g");
- txt = txt.replaceAll("tio", "sio");
- txt = txt.replaceAll("tia", "sia");
- txt = txt.replaceAll("d", "t");
- txt = txt.replaceAll("ph", "fh");
- txt = txt.replaceAll("b", "p");
- txt = txt.replaceAll("sh", "s2");
- txt = txt.replaceAll("z", "s");
- txt = txt.replaceAll("^[aeiou]", "A");
- // 3 is a temporary placeholder marking a vowel
- txt = txt.replaceAll("[aeiou]", "3");
- txt = txt.replaceAll("3gh3", "3kh3");
- txt = txt.replaceAll("gh", "22");
- txt = txt.replaceAll("g", "k");
- txt = txt.replaceAll("s+", "S");
- txt = txt.replaceAll("t+", "T");
- txt = txt.replaceAll("p+", "P");
- txt = txt.replaceAll("k+", "K");
- txt = txt.replaceAll("f+", "F");
- txt = txt.replaceAll("m+", "M");
- txt = txt.replaceAll("n+", "N");
- txt = txt.replaceAll("w3", "W3");
- txt = txt.replaceAll("wy", "Wy"); // 1.0 only
- txt = txt.replaceAll("wh3", "Wh3");
- txt = txt.replaceAll("why", "Why"); // 1.0 only
- txt = txt.replaceAll("w", "2");
- txt = txt.replaceAll("^h", "A");
- txt = txt.replaceAll("h", "2");
- txt = txt.replaceAll("r3", "R3");
- txt = txt.replaceAll("ry", "Ry"); // 1.0 only
- txt = txt.replaceAll("r", "2");
- txt = txt.replaceAll("l3", "L3");
- txt = txt.replaceAll("ly", "Ly"); // 1.0 only
- txt = txt.replaceAll("l", "2");
- txt = txt.replaceAll("j", "y"); // 1.0 only
- txt = txt.replaceAll("y3", "Y3"); // 1.0 only
- txt = txt.replaceAll("y", "2"); // 1.0 only
-
- // 5. Handle removals
- txt = txt.replaceAll("2", "");
- txt = txt.replaceAll("3", "");
-
- // 6. put ten 1s on the end
- txt = txt + SIX_1;
-
- // 7. take the first six characters as the code
- return txt.substring(0, SIX_1.length());
- }
-}
diff --git a/src/org/apache/commons/codec/language/Caverphone2.java b/src/org/apache/commons/codec/language/Caverphone2.java
deleted file mode 100644
index 5f8e31d8..00000000
--- a/src/org/apache/commons/codec/language/Caverphone2.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language;
-
-/**
- * Encodes a string into a Caverphone 2.0 value.
- *
- * This is an algorithm created by the Caversham Project at the University of Otago. It implements the Caverphone 2.0
- * algorithm:
- *
- * @version $Id: Caverphone.java 1075947 2011-03-01 17:56:14Z ggregory $
- * @see Wikipedia - Caverphone
- * @see Caverphone 2.0 specification
- * @since 1.5
- *
- *
This class is immutable and thread-safe.
- */
-public class Caverphone2 extends AbstractCaverphone {
-
- private static final String TEN_1 = "1111111111";
-
- /**
- * Encodes the given String into a Caverphone 2.0 value.
- *
- * @param source String the source string
- * @return A caverphone code for the given String
- */
- @Override
- public String encode(final String source) {
- String txt = source;
- if (txt == null || txt.length() == 0) {
- return TEN_1;
- }
-
- // 1. Convert to lowercase
- txt = txt.toLowerCase(java.util.Locale.ENGLISH);
-
- // 2. Remove anything not A-Z
- txt = txt.replaceAll("[^a-z]", "");
-
- // 2.5. Remove final e
- txt = txt.replaceAll("e$", ""); // 2.0 only
-
- // 3. Handle various start options
- txt = txt.replaceAll("^cough", "cou2f");
- txt = txt.replaceAll("^rough", "rou2f");
- txt = txt.replaceAll("^tough", "tou2f");
- txt = txt.replaceAll("^enough", "enou2f"); // 2.0 only
- txt = txt.replaceAll("^trough", "trou2f"); // 2.0 only
- // note the spec says ^enough here again, c+p error I assume
- txt = txt.replaceAll("^gn", "2n");
-
- // End
- txt = txt.replaceAll("mb$", "m2");
-
- // 4. Handle replacements
- txt = txt.replaceAll("cq", "2q");
- txt = txt.replaceAll("ci", "si");
- txt = txt.replaceAll("ce", "se");
- txt = txt.replaceAll("cy", "sy");
- txt = txt.replaceAll("tch", "2ch");
- txt = txt.replaceAll("c", "k");
- txt = txt.replaceAll("q", "k");
- txt = txt.replaceAll("x", "k");
- txt = txt.replaceAll("v", "f");
- txt = txt.replaceAll("dg", "2g");
- txt = txt.replaceAll("tio", "sio");
- txt = txt.replaceAll("tia", "sia");
- txt = txt.replaceAll("d", "t");
- txt = txt.replaceAll("ph", "fh");
- txt = txt.replaceAll("b", "p");
- txt = txt.replaceAll("sh", "s2");
- txt = txt.replaceAll("z", "s");
- txt = txt.replaceAll("^[aeiou]", "A");
- txt = txt.replaceAll("[aeiou]", "3");
- txt = txt.replaceAll("j", "y"); // 2.0 only
- txt = txt.replaceAll("^y3", "Y3"); // 2.0 only
- txt = txt.replaceAll("^y", "A"); // 2.0 only
- txt = txt.replaceAll("y", "3"); // 2.0 only
- txt = txt.replaceAll("3gh3", "3kh3");
- txt = txt.replaceAll("gh", "22");
- txt = txt.replaceAll("g", "k");
- txt = txt.replaceAll("s+", "S");
- txt = txt.replaceAll("t+", "T");
- txt = txt.replaceAll("p+", "P");
- txt = txt.replaceAll("k+", "K");
- txt = txt.replaceAll("f+", "F");
- txt = txt.replaceAll("m+", "M");
- txt = txt.replaceAll("n+", "N");
- txt = txt.replaceAll("w3", "W3");
- txt = txt.replaceAll("wh3", "Wh3");
- txt = txt.replaceAll("w$", "3"); // 2.0 only
- txt = txt.replaceAll("w", "2");
- txt = txt.replaceAll("^h", "A");
- txt = txt.replaceAll("h", "2");
- txt = txt.replaceAll("r3", "R3");
- txt = txt.replaceAll("r$", "3"); // 2.0 only
- txt = txt.replaceAll("r", "2");
- txt = txt.replaceAll("l3", "L3");
- txt = txt.replaceAll("l$", "3"); // 2.0 only
- txt = txt.replaceAll("l", "2");
-
- // 5. Handle removals
- txt = txt.replaceAll("2", "");
- txt = txt.replaceAll("3$", "A"); // 2.0 only
- txt = txt.replaceAll("3", "");
-
- // 6. put ten 1s on the end
- txt = txt + TEN_1;
-
- // 7. take the first ten characters as the code
- return txt.substring(0, TEN_1.length());
- }
-}
diff --git a/src/org/apache/commons/codec/language/ColognePhonetic.java b/src/org/apache/commons/codec/language/ColognePhonetic.java
deleted file mode 100644
index d04428d1..00000000
--- a/src/org/apache/commons/codec/language/ColognePhonetic.java
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language;
-
-import java.util.Locale;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Encodes a string into a Cologne Phonetic value.
- *
- * Implements the Kölner Phonetik (Cologne
- * Phonetic) algorithm issued by Hans Joachim Postel in 1969.
- *
- *
- * The Kölner Phonetik is a phonetic algorithm which is optimized for the German language. It is related to
- * the well-known soundex algorithm.
- *
- *
- *
Algorithm
- *
- *
- *
- *
- * This class is thread-safe.
- *
- *
- * @see Wikipedia (de): Kölner Phonetik (in German)
- * @since 1.5
- */
-public class ColognePhonetic implements StringEncoder {
-
- // Predefined char arrays for better performance and less GC load
- private static final char[] AEIJOUY = new char[]{'A', 'E', 'I', 'J', 'O', 'U', 'Y'};
- private static final char[] SCZ = new char[]{'S', 'C', 'Z'};
- private static final char[] WFPV = new char[]{'W', 'F', 'P', 'V'};
- private static final char[] GKQ = new char[]{'G', 'K', 'Q'};
- private static final char[] CKQ = new char[]{'C', 'K', 'Q'};
- private static final char[] AHKLOQRUX = new char[]{'A', 'H', 'K', 'L', 'O', 'Q', 'R', 'U', 'X'};
- private static final char[] SZ = new char[]{'S', 'Z'};
- private static final char[] AHOUKQX = new char[]{'A', 'H', 'O', 'U', 'K', 'Q', 'X'};
- private static final char[] TDX = new char[]{'T', 'D', 'X'};
-
- /**
- * This class is not thread-safe; the field {@link #length} is mutable.
- * However, it is not shared between threads, as it is constructed on demand
- * by the method {@link ColognePhonetic#colognePhonetic(String)}
- */
- private abstract class CologneBuffer {
-
- protected final char[] data;
-
- protected int length = 0;
-
- public CologneBuffer(final char[] data) {
- this.data = data;
- this.length = data.length;
- }
-
- public CologneBuffer(final int buffSize) {
- this.data = new char[buffSize];
- this.length = 0;
- }
-
- protected abstract char[] copyData(int start, final int length);
-
- public int length() {
- return length;
- }
-
- @Override
- public String toString() {
- return new String(copyData(0, length));
- }
- }
-
- private class CologneOutputBuffer extends CologneBuffer {
-
- public CologneOutputBuffer(final int buffSize) {
- super(buffSize);
- }
-
- public void addRight(final char chr) {
- data[length] = chr;
- length++;
- }
-
- @Override
- protected char[] copyData(final int start, final int length) {
- final char[] newData = new char[length];
- System.arraycopy(data, start, newData, 0, length);
- return newData;
- }
- }
-
- private class CologneInputBuffer extends CologneBuffer {
-
- public CologneInputBuffer(final char[] data) {
- super(data);
- }
-
- public void addLeft(final char ch) {
- length++;
- data[getNextPos()] = ch;
- }
-
- @Override
- protected char[] copyData(final int start, final int length) {
- final char[] newData = new char[length];
- System.arraycopy(data, data.length - this.length + start, newData, 0, length);
- return newData;
- }
-
- public char getNextChar() {
- return data[getNextPos()];
- }
-
- protected int getNextPos() {
- return data.length - length;
- }
-
- public char removeNext() {
- final char ch = getNextChar();
- length--;
- return ch;
- }
- }
-
- /**
- * Maps some Germanic characters to plain for internal processing. The following characters are mapped:
- *
- * capital a, umlaut mark
- * capital u, umlaut mark
- * capital o, umlaut mark
- * small sharp s, German
- *
- */
- private static final char[][] PREPROCESS_MAP = new char[][]{
- {'\u00C4', 'A'}, // capital a, umlaut mark
- {'\u00DC', 'U'}, // capital u, umlaut mark
- {'\u00D6', 'O'}, // capital o, umlaut mark
- {'\u00DF', 'S'} // small sharp s, German
- };
-
- /*
- * Returns whether the array contains the key, or not.
- */
- private static boolean arrayContains(final char[] arr, final char key) {
- for (final char element : arr) {
- if (element == key) {
- return true;
- }
- }
- return false;
- }
-
- /**
- *
- * Implements the Kölner Phonetik algorithm.
- *
- *
- * In contrast to the initial description of the algorithm, this implementation does the encoding in one pass.
- *
- *
- * @param text The source text to encode
- * @return the corresponding encoding according to the Kölner Phonetik algorithm
- */
- public String colognePhonetic(String text) {
- if (text == null) {
- return null;
- }
-
- text = preprocess(text);
-
- final CologneOutputBuffer output = new CologneOutputBuffer(text.length() * 2);
- final CologneInputBuffer input = new CologneInputBuffer(text.toCharArray());
-
- char nextChar;
-
- char lastChar = '-';
- char lastCode = '/';
- char code;
- char chr;
-
- int rightLength = input.length();
-
- while (rightLength > 0) {
- chr = input.removeNext();
-
- if ((rightLength = input.length()) > 0) {
- nextChar = input.getNextChar();
- } else {
- nextChar = '-';
- }
-
- if (arrayContains(AEIJOUY, chr)) {
- code = '0';
- } else if (chr == 'H' || chr < 'A' || chr > 'Z') {
- if (lastCode == '/') {
- continue;
- }
- code = '-';
- } else if (chr == 'B' || (chr == 'P' && nextChar != 'H')) {
- code = '1';
- } else if ((chr == 'D' || chr == 'T') && !arrayContains(SCZ, nextChar)) {
- code = '2';
- } else if (arrayContains(WFPV, chr)) {
- code = '3';
- } else if (arrayContains(GKQ, chr)) {
- code = '4';
- } else if (chr == 'X' && !arrayContains(CKQ, lastChar)) {
- code = '4';
- input.addLeft('S');
- rightLength++;
- } else if (chr == 'S' || chr == 'Z') {
- code = '8';
- } else if (chr == 'C') {
- if (lastCode == '/') {
- if (arrayContains(AHKLOQRUX, nextChar)) {
- code = '4';
- } else {
- code = '8';
- }
- } else {
- if (arrayContains(SZ, lastChar) || !arrayContains(AHOUKQX, nextChar)) {
- code = '8';
- } else {
- code = '4';
- }
- }
- } else if (arrayContains(TDX, chr)) {
- code = '8';
- } else if (chr == 'R') {
- code = '7';
- } else if (chr == 'L') {
- code = '5';
- } else if (chr == 'M' || chr == 'N') {
- code = '6';
- } else {
- code = chr;
- }
-
- if (code != '-' && (lastCode != code && (code != '0' || lastCode == '/') || code < '0' || code > '8')) {
- output.addRight(code);
- }
-
- lastChar = chr;
- lastCode = code;
- }
- return output.toString();
- }
-
- @Override
- public Object encode(final Object object) throws EncoderException {
- if (!(object instanceof String)) {
- throw new EncoderException("This method's parameter was expected to be of the type " +
- String.class.getName() +
- ". But actually it was of the type " +
- object.getClass().getName() +
- ".");
- }
- return encode((String) object);
- }
-
- @Override
- public String encode(final String text) {
- return colognePhonetic(text);
- }
-
- public boolean isEncodeEqual(final String text1, final String text2) {
- return colognePhonetic(text1).equals(colognePhonetic(text2));
- }
-
- /**
- * Converts the string to upper case and replaces germanic characters as defined in {@link #PREPROCESS_MAP}.
- */
- private String preprocess(String text) {
- text = text.toUpperCase(Locale.GERMAN);
-
- final char[] chrs = text.toCharArray();
-
- for (int index = 0; index < chrs.length; index++) {
- if (chrs[index] > 'Z') {
- for (final char[] element : PREPROCESS_MAP) {
- if (chrs[index] == element[0]) {
- chrs[index] = element[1];
- break;
- }
- }
- }
- }
- return new String(chrs);
- }
-}
diff --git a/src/org/apache/commons/codec/language/DaitchMokotoffSoundex.java b/src/org/apache/commons/codec/language/DaitchMokotoffSoundex.java
deleted file mode 100644
index 5d41e694..00000000
--- a/src/org/apache/commons/codec/language/DaitchMokotoffSoundex.java
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.codec.language;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Scanner;
-import java.util.Set;
-
-import org.apache.commons.codec.CharEncoding;
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Encodes a string into a Daitch-Mokotoff Soundex value.
- *
- * The Daitch-Mokotoff Soundex algorithm is a refinement of the Russel and American Soundex algorithms, yielding greater
- * accuracy in matching especially Slavish and Yiddish surnames with similar pronunciation but differences in spelling.
- *
- *
- * The main differences compared to the other soundex variants are:
- *
- *
- * coded names are 6 digits long
- * the initial character of the name is coded
- * rules to encoded multi-character n-grams
- * multiple possible encodings for the same name (branching)
- *
- *
- * This implementation supports branching, depending on the used method:
- *
- * {@link #encode(String)} - branching disabled, only the first code will be returned
- * {@link #soundex(String)} - branching enabled, all codes will be returned, separated by '|'
- *
- *
- * Note: this implementation has additional branching rules compared to the original description of the algorithm. The
- * rules can be customized by overriding the default rules contained in the resource file
- * {@code org/apache/commons/codec/language/dmrules.txt}.
- *
- *
- * This class is thread-safe.
- *
- *
- * @version $Id$
- * @see Soundex
- * @see Wikipedia - Daitch-Mokotoff Soundex
- * @see Avotaynu - Soundexing and Genealogy
- * @since 1.10
- */
-public class DaitchMokotoffSoundex implements StringEncoder {
-
- /**
- * Inner class representing a branch during DM soundex encoding.
- */
- private static final class Branch {
- private final StringBuilder builder;
- private String cachedString;
- private String lastReplacement;
-
- private Branch() {
- builder = new StringBuilder();
- lastReplacement = null;
- cachedString = null;
- }
-
- /**
- * Creates a new branch, identical to this branch.
- *
- * @return a new, identical branch
- */
- public Branch createBranch() {
- final Branch branch = new Branch();
- branch.builder.append(toString());
- branch.lastReplacement = this.lastReplacement;
- return branch;
- }
-
- @Override
- public boolean equals(final Object other) {
- if (this == other) {
- return true;
- }
- if (!(other instanceof Branch)) {
- return false;
- }
-
- return toString().equals(((Branch) other).toString());
- }
-
- /**
- * Finish this branch by appending '0's until the maximum code length has been reached.
- */
- public void finish() {
- while (builder.length() < MAX_LENGTH) {
- builder.append('0');
- cachedString = null;
- }
- }
-
- @Override
- public int hashCode() {
- return toString().hashCode();
- }
-
- /**
- * Process the next replacement to be added to this branch.
- *
- * @param replacement the next replacement to append
- * @param forceAppend indicates if the default processing shall be overridden
- */
- public void processNextReplacement(final String replacement, final boolean forceAppend) {
- final boolean append = lastReplacement == null || !lastReplacement.endsWith(replacement) || forceAppend;
-
- if (append && builder.length() < MAX_LENGTH) {
- builder.append(replacement);
- // remove all characters after the maximum length
- if (builder.length() > MAX_LENGTH) {
- builder.delete(MAX_LENGTH, builder.length());
- }
- cachedString = null;
- }
-
- lastReplacement = replacement;
- }
-
- @Override
- public String toString() {
- if (cachedString == null) {
- cachedString = builder.toString();
- }
- return cachedString;
- }
- }
-
- /**
- * Inner class for storing rules.
- */
- private static final class Rule {
- private final String pattern;
- private final String[] replacementAtStart;
- private final String[] replacementBeforeVowel;
- private final String[] replacementDefault;
-
- protected Rule(final String pattern, final String replacementAtStart, final String replacementBeforeVowel,
- final String replacementDefault) {
- this.pattern = pattern;
- this.replacementAtStart = replacementAtStart.split("\\|");
- this.replacementBeforeVowel = replacementBeforeVowel.split("\\|");
- this.replacementDefault = replacementDefault.split("\\|");
- }
-
- public int getPatternLength() {
- return pattern.length();
- }
-
- public String[] getReplacements(final String context, final boolean atStart) {
- if (atStart) {
- return replacementAtStart;
- }
-
- final int nextIndex = getPatternLength();
- final boolean nextCharIsVowel = nextIndex < context.length() ? isVowel(context.charAt(nextIndex)) : false;
- if (nextCharIsVowel) {
- return replacementBeforeVowel;
- }
-
- return replacementDefault;
- }
-
- private boolean isVowel(final char ch) {
- return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
- }
-
- public boolean matches(final String context) {
- return context.startsWith(pattern);
- }
-
- @Override
- public String toString() {
- return String.format("%s=(%s,%s,%s)", pattern, Arrays.asList(replacementAtStart),
- Arrays.asList(replacementBeforeVowel), Arrays.asList(replacementDefault));
- }
- }
-
- private static final String COMMENT = "//";
- private static final String DOUBLE_QUOTE = "\"";
-
- private static final String MULTILINE_COMMENT_END = "*/";
-
- private static final String MULTILINE_COMMENT_START = "/*";
-
- /**
- * The resource file containing the replacement and folding rules
- */
- private static final String RESOURCE_FILE = "org/apache/commons/codec/language/dmrules.txt";
-
- /**
- * The code length of a DM soundex value.
- */
- private static final int MAX_LENGTH = 6;
-
- /**
- * Transformation rules indexed by the first character of their pattern.
- */
- private static final Map> RULES = new HashMap>();
-
- /**
- * Folding rules.
- */
- private static final Map FOLDINGS = new HashMap();
-
- static {
- final InputStream rulesIS = DaitchMokotoffSoundex.class.getClassLoader().getResourceAsStream(RESOURCE_FILE);
- if (rulesIS == null) {
- throw new IllegalArgumentException("Unable to load resource: " + RESOURCE_FILE);
- }
-
- final Scanner scanner = new Scanner(rulesIS, CharEncoding.UTF_8);
- parseRules(scanner, RESOURCE_FILE, RULES, FOLDINGS);
- scanner.close();
-
- // sort RULES by pattern length in descending order
- for (final Map.Entry> rule : RULES.entrySet()) {
- final List ruleList = rule.getValue();
- Collections.sort(ruleList, new Comparator() {
- @Override
- public int compare(final Rule rule1, final Rule rule2) {
- return rule2.getPatternLength() - rule1.getPatternLength();
- }
- });
- }
- }
-
- private static void parseRules(final Scanner scanner, final String location,
- final Map> ruleMapping, final Map asciiFoldings) {
- int currentLine = 0;
- boolean inMultilineComment = false;
-
- while (scanner.hasNextLine()) {
- currentLine++;
- final String rawLine = scanner.nextLine();
- String line = rawLine;
-
- if (inMultilineComment) {
- if (line.endsWith(MULTILINE_COMMENT_END)) {
- inMultilineComment = false;
- }
- continue;
- }
-
- if (line.startsWith(MULTILINE_COMMENT_START)) {
- inMultilineComment = true;
- } else {
- // discard comments
- final int cmtI = line.indexOf(COMMENT);
- if (cmtI >= 0) {
- line = line.substring(0, cmtI);
- }
-
- // trim leading-trailing whitespace
- line = line.trim();
-
- if (line.length() == 0) {
- continue; // empty lines can be safely skipped
- }
-
- if (line.contains("=")) {
- // folding
- final String[] parts = line.split("=");
- if (parts.length != 2) {
- throw new IllegalArgumentException("Malformed folding statement split into " + parts.length +
- " parts: " + rawLine + " in " + location);
- } else {
- final String leftCharacter = parts[0];
- final String rightCharacter = parts[1];
-
- if (leftCharacter.length() != 1 || rightCharacter.length() != 1) {
- throw new IllegalArgumentException("Malformed folding statement - " +
- "patterns are not single characters: " + rawLine + " in " + location);
- }
-
- asciiFoldings.put(leftCharacter.charAt(0), rightCharacter.charAt(0));
- }
- } else {
- // rule
- final String[] parts = line.split("\\s+");
- if (parts.length != 4) {
- throw new IllegalArgumentException("Malformed rule statement split into " + parts.length +
- " parts: " + rawLine + " in " + location);
- } else {
- try {
- final String pattern = stripQuotes(parts[0]);
- final String replacement1 = stripQuotes(parts[1]);
- final String replacement2 = stripQuotes(parts[2]);
- final String replacement3 = stripQuotes(parts[3]);
-
- final Rule r = new Rule(pattern, replacement1, replacement2, replacement3);
- final char patternKey = r.pattern.charAt(0);
- List rules = ruleMapping.get(patternKey);
- if (rules == null) {
- rules = new ArrayList();
- ruleMapping.put(patternKey, rules);
- }
- rules.add(r);
- } catch (final IllegalArgumentException e) {
- throw new IllegalStateException(
- "Problem parsing line '" + currentLine + "' in " + location, e);
- }
- }
- }
- }
- }
- }
-
- private static String stripQuotes(String str) {
- if (str.startsWith(DOUBLE_QUOTE)) {
- str = str.substring(1);
- }
-
- if (str.endsWith(DOUBLE_QUOTE)) {
- str = str.substring(0, str.length() - 1);
- }
-
- return str;
- }
-
- /**
- * Whether to use ASCII folding prior to encoding.
- */
- private final boolean folding;
-
- /**
- * Creates a new instance with ASCII-folding enabled.
- */
- public DaitchMokotoffSoundex() {
- this(true);
- }
-
- /**
- * Creates a new instance.
- *
- * With ASCII-folding enabled, certain accented characters will be transformed to equivalent ASCII characters, e.g.
- * è -> e.
- *
- *
- * @param folding if ASCII-folding shall be performed before encoding
- */
- public DaitchMokotoffSoundex(final boolean folding) {
- this.folding = folding;
- }
-
- /**
- * Performs a cleanup of the input string before the actual soundex transformation.
- *
- * Removes all whitespace characters and performs ASCII folding if enabled.
- *
- *
- * @param input the input string to cleanup
- * @return a cleaned up string
- */
- private String cleanup(final String input) {
- final StringBuilder sb = new StringBuilder();
- for (char ch : input.toCharArray()) {
- if (Character.isWhitespace(ch)) {
- continue;
- }
-
- ch = Character.toLowerCase(ch);
- if (folding && FOLDINGS.containsKey(ch)) {
- ch = FOLDINGS.get(ch);
- }
- sb.append(ch);
- }
- return sb.toString();
- }
-
- /**
- * Encodes an Object using the Daitch-Mokotoff soundex algorithm without branching.
- *
- * This method is provided in order to satisfy the requirements of the Encoder interface, and will throw an
- * EncoderException if the supplied object is not of type java.lang.String.
- *
- *
- * @param obj Object to encode
- * @return An object (of type java.lang.String) containing the DM soundex code, which corresponds to the String
- * supplied.
- * @throws EncoderException if the parameter supplied is not of type java.lang.String
- * @throws IllegalArgumentException if a character is not mapped
- * @see #soundex(String)
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (!(obj instanceof String)) {
- throw new EncoderException(
- "Parameter supplied to DaitchMokotoffSoundex encode is not of type java.lang.String");
- }
- return encode((String) obj);
- }
-
- /**
- * Encodes a String using the Daitch-Mokotoff soundex algorithm without branching.
- *
- * @param source A String object to encode
- * @return A DM Soundex code corresponding to the String supplied
- * @throws IllegalArgumentException if a character is not mapped
- * @see #soundex(String)
- */
- @Override
- public String encode(final String source) {
- if (source == null) {
- return null;
- }
- return soundex(source, false)[0];
- }
-
- /**
- * Encodes a String using the Daitch-Mokotoff soundex algorithm with branching.
- *
- * In case a string is encoded into multiple codes (see branching rules), the result will contain all codes,
- * separated by '|'.
- *
- *
- * Example: the name "AUERBACH" is encoded as both
- *
- *
- * 097400
- * 097500
- *
- *
- * Thus the result will be "097400|097500".
- *
- *
- * @param source A String object to encode
- * @return A string containing a set of DM Soundex codes corresponding to the String supplied
- * @throws IllegalArgumentException if a character is not mapped
- */
- public String soundex(final String source) {
- final String[] branches = soundex(source, true);
- final StringBuilder sb = new StringBuilder();
- int index = 0;
- for (final String branch : branches) {
- sb.append(branch);
- if (++index < branches.length) {
- sb.append('|');
- }
- }
- return sb.toString();
- }
-
- /**
- * Perform the actual DM Soundex algorithm on the input string.
- *
- * @param source A String object to encode
- * @param branching If branching shall be performed
- * @return A string array containing all DM Soundex codes corresponding to the String supplied depending on the
- * selected branching mode
- */
- private String[] soundex(final String source, final boolean branching) {
- if (source == null) {
- return null;
- }
-
- final String input = cleanup(source);
-
- final Set currentBranches = new LinkedHashSet();
- currentBranches.add(new Branch());
-
- char lastChar = '\0';
- for (int index = 0; index < input.length(); index++) {
- final char ch = input.charAt(index);
-
- // ignore whitespace inside a name
- if (Character.isWhitespace(ch)) {
- continue;
- }
-
- final String inputContext = input.substring(index);
- final List rules = RULES.get(ch);
- if (rules == null) {
- continue;
- }
-
- // use an EMPTY_LIST to avoid false positive warnings wrt potential null pointer access
- @SuppressWarnings("unchecked") final List nextBranches = branching ? new ArrayList() : Collections.EMPTY_LIST;
-
- for (final Rule rule : rules) {
- if (rule.matches(inputContext)) {
- if (branching) {
- nextBranches.clear();
- }
- final String[] replacements = rule.getReplacements(inputContext, lastChar == '\0');
- final boolean branchingRequired = replacements.length > 1 && branching;
-
- for (final Branch branch : currentBranches) {
- for (final String nextReplacement : replacements) {
- // if we have multiple replacements, always create a new branch
- final Branch nextBranch = branchingRequired ? branch.createBranch() : branch;
-
- // special rule: occurrences of mn or nm are treated differently
- final boolean force = (lastChar == 'm' && ch == 'n') || (lastChar == 'n' && ch == 'm');
-
- nextBranch.processNextReplacement(nextReplacement, force);
-
- if (branching) {
- nextBranches.add(nextBranch);
- } else {
- break;
- }
- }
- }
-
- if (branching) {
- currentBranches.clear();
- currentBranches.addAll(nextBranches);
- }
- index += rule.getPatternLength() - 1;
- break;
- }
- }
-
- lastChar = ch;
- }
-
- final String[] result = new String[currentBranches.size()];
- int index = 0;
- for (final Branch branch : currentBranches) {
- branch.finish();
- result[index++] = branch.toString();
- }
-
- return result;
- }
-}
diff --git a/src/org/apache/commons/codec/language/DoubleMetaphone.java b/src/org/apache/commons/codec/language/DoubleMetaphone.java
deleted file mode 100644
index 899fc89b..00000000
--- a/src/org/apache/commons/codec/language/DoubleMetaphone.java
+++ /dev/null
@@ -1,1010 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-import org.apache.commons.codec.binary.StringUtils;
-
-/**
- * Encodes a string into a double metaphone value. This Implementation is based on the algorithm by Lawrence
- * Philips .
- *
- * This class is conditionally thread-safe. The instance field {@link #maxCodeLen} is mutable
- * {@link #setMaxCodeLen(int)} but is not volatile, and accesses are not synchronized. If an instance of the class is
- * shared between threads, the caller needs to ensure that suitable synchronization is used to ensure safe publication
- * of the value between threads, and must not invoke {@link #setMaxCodeLen(int)} after initial setup.
- *
- * @version $Id$
- * @see Original Article
- * @see http://en.wikipedia.org/wiki/Metaphone
- */
-public class DoubleMetaphone implements StringEncoder {
-
- /**
- * "Vowels" to test for
- */
- private static final String VOWELS = "AEIOUY";
-
- /**
- * Prefixes when present which are not pronounced
- */
- private static final String[] SILENT_START =
- {"GN", "KN", "PN", "WR", "PS"};
- private static final String[] L_R_N_M_B_H_F_V_W_SPACE =
- {"L", "R", "N", "M", "B", "H", "F", "V", "W", " "};
- private static final String[] ES_EP_EB_EL_EY_IB_IL_IN_IE_EI_ER =
- {"ES", "EP", "EB", "EL", "EY", "IB", "IL", "IN", "IE", "EI", "ER"};
- private static final String[] L_T_K_S_N_M_B_Z =
- {"L", "T", "K", "S", "N", "M", "B", "Z"};
-
- /**
- * Maximum length of an encoding, default is 4
- */
- private int maxCodeLen = 4;
-
- /**
- * Creates an instance of this DoubleMetaphone encoder
- */
- public DoubleMetaphone() {
- super();
- }
-
- /**
- * Encode a value with Double Metaphone.
- *
- * @param value String to encode
- * @return an encoded string
- */
- public String doubleMetaphone(final String value) {
- return doubleMetaphone(value, false);
- }
-
- /**
- * Encode a value with Double Metaphone, optionally using the alternate encoding.
- *
- * @param value String to encode
- * @param alternate use alternate encode
- * @return an encoded string
- */
- public String doubleMetaphone(String value, final boolean alternate) {
- value = cleanInput(value);
- if (value == null) {
- return null;
- }
-
- final boolean slavoGermanic = isSlavoGermanic(value);
- int index = isSilentStart(value) ? 1 : 0;
-
- final DoubleMetaphoneResult result = new DoubleMetaphoneResult(this.getMaxCodeLen());
-
- while (!result.isComplete() && index <= value.length() - 1) {
- switch (value.charAt(index)) {
- case 'A':
- case 'E':
- case 'I':
- case 'O':
- case 'U':
- case 'Y':
- index = handleAEIOUY(result, index);
- break;
- case 'B':
- result.append('P');
- index = charAt(value, index + 1) == 'B' ? index + 2 : index + 1;
- break;
- case '\u00C7':
- // A C with a Cedilla
- result.append('S');
- index++;
- break;
- case 'C':
- index = handleC(value, result, index);
- break;
- case 'D':
- index = handleD(value, result, index);
- break;
- case 'F':
- result.append('F');
- index = charAt(value, index + 1) == 'F' ? index + 2 : index + 1;
- break;
- case 'G':
- index = handleG(value, result, index, slavoGermanic);
- break;
- case 'H':
- index = handleH(value, result, index);
- break;
- case 'J':
- index = handleJ(value, result, index, slavoGermanic);
- break;
- case 'K':
- result.append('K');
- index = charAt(value, index + 1) == 'K' ? index + 2 : index + 1;
- break;
- case 'L':
- index = handleL(value, result, index);
- break;
- case 'M':
- result.append('M');
- index = conditionM0(value, index) ? index + 2 : index + 1;
- break;
- case 'N':
- result.append('N');
- index = charAt(value, index + 1) == 'N' ? index + 2 : index + 1;
- break;
- case '\u00D1':
- // N with a tilde (spanish ene)
- result.append('N');
- index++;
- break;
- case 'P':
- index = handleP(value, result, index);
- break;
- case 'Q':
- result.append('K');
- index = charAt(value, index + 1) == 'Q' ? index + 2 : index + 1;
- break;
- case 'R':
- index = handleR(value, result, index, slavoGermanic);
- break;
- case 'S':
- index = handleS(value, result, index, slavoGermanic);
- break;
- case 'T':
- index = handleT(value, result, index);
- break;
- case 'V':
- result.append('F');
- index = charAt(value, index + 1) == 'V' ? index + 2 : index + 1;
- break;
- case 'W':
- index = handleW(value, result, index);
- break;
- case 'X':
- index = handleX(value, result, index);
- break;
- case 'Z':
- index = handleZ(value, result, index, slavoGermanic);
- break;
- default:
- index++;
- break;
- }
- }
-
- return alternate ? result.getAlternate() : result.getPrimary();
- }
-
- /**
- * Encode the value using DoubleMetaphone. It will only work if
- * obj
is a String
(like Metaphone
).
- *
- * @param obj Object to encode (should be of type String)
- * @return An encoded Object (will be of type String)
- * @throws EncoderException encode parameter is not of type String
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (!(obj instanceof String)) {
- throw new EncoderException("DoubleMetaphone encode parameter is not of type String");
- }
- return doubleMetaphone((String) obj);
- }
-
- /**
- * Encode the value using DoubleMetaphone.
- *
- * @param value String to encode
- * @return An encoded String
- */
- @Override
- public String encode(final String value) {
- return doubleMetaphone(value);
- }
-
- /**
- * Check if the Double Metaphone values of two String
values
- * are equal.
- *
- * @param value1 The left-hand side of the encoded {@link String#equals(Object)}.
- * @param value2 The right-hand side of the encoded {@link String#equals(Object)}.
- * @return true
if the encoded String
s are equal;
- * false
otherwise.
- * @see #isDoubleMetaphoneEqual(String, String, boolean)
- */
- public boolean isDoubleMetaphoneEqual(final String value1, final String value2) {
- return isDoubleMetaphoneEqual(value1, value2, false);
- }
-
- /**
- * Check if the Double Metaphone values of two String
values
- * are equal, optionally using the alternate value.
- *
- * @param value1 The left-hand side of the encoded {@link String#equals(Object)}.
- * @param value2 The right-hand side of the encoded {@link String#equals(Object)}.
- * @param alternate use the alternate value if true
.
- * @return true
if the encoded String
s are equal;
- * false
otherwise.
- */
- public boolean isDoubleMetaphoneEqual(final String value1, final String value2, final boolean alternate) {
- return StringUtils.equals(doubleMetaphone(value1, alternate), doubleMetaphone(value2, alternate));
- }
-
- /**
- * Returns the maxCodeLen.
- *
- * @return int
- */
- public int getMaxCodeLen() {
- return this.maxCodeLen;
- }
-
- /**
- * Sets the maxCodeLen.
- *
- * @param maxCodeLen The maxCodeLen to set
- */
- public void setMaxCodeLen(final int maxCodeLen) {
- this.maxCodeLen = maxCodeLen;
- }
-
- //-- BEGIN HANDLERS --//
-
- /**
- * Handles 'A', 'E', 'I', 'O', 'U', and 'Y' cases.
- */
- private int handleAEIOUY(final DoubleMetaphoneResult result, final int index) {
- if (index == 0) {
- result.append('A');
- }
- return index + 1;
- }
-
- /**
- * Handles 'C' cases.
- */
- private int handleC(final String value, final DoubleMetaphoneResult result, int index) {
- if (conditionC0(value, index)) { // very confusing, moved out
- result.append('K');
- index += 2;
- } else if (index == 0 && contains(value, index, 6, "CAESAR")) {
- result.append('S');
- index += 2;
- } else if (contains(value, index, 2, "CH")) {
- index = handleCH(value, result, index);
- } else if (contains(value, index, 2, "CZ") &&
- !contains(value, index - 2, 4, "WICZ")) {
- //-- "Czerny" --//
- result.append('S', 'X');
- index += 2;
- } else if (contains(value, index + 1, 3, "CIA")) {
- //-- "focaccia" --//
- result.append('X');
- index += 3;
- } else if (contains(value, index, 2, "CC") &&
- !(index == 1 && charAt(value, 0) == 'M')) {
- //-- double "cc" but not "McClelland" --//
- return handleCC(value, result, index);
- } else if (contains(value, index, 2, "CK", "CG", "CQ")) {
- result.append('K');
- index += 2;
- } else if (contains(value, index, 2, "CI", "CE", "CY")) {
- //-- Italian vs. English --//
- if (contains(value, index, 3, "CIO", "CIE", "CIA")) {
- result.append('S', 'X');
- } else {
- result.append('S');
- }
- index += 2;
- } else {
- result.append('K');
- if (contains(value, index + 1, 2, " C", " Q", " G")) {
- //-- Mac Caffrey, Mac Gregor --//
- index += 3;
- } else if (contains(value, index + 1, 1, "C", "K", "Q") &&
- !contains(value, index + 1, 2, "CE", "CI")) {
- index += 2;
- } else {
- index++;
- }
- }
-
- return index;
- }
-
- /**
- * Handles 'CC' cases.
- */
- private int handleCC(final String value, final DoubleMetaphoneResult result, int index) {
- if (contains(value, index + 2, 1, "I", "E", "H") &&
- !contains(value, index + 2, 2, "HU")) {
- //-- "bellocchio" but not "bacchus" --//
- if ((index == 1 && charAt(value, index - 1) == 'A') ||
- contains(value, index - 1, 5, "UCCEE", "UCCES")) {
- //-- "accident", "accede", "succeed" --//
- result.append("KS");
- } else {
- //-- "bacci", "bertucci", other Italian --//
- result.append('X');
- }
- index += 3;
- } else { // Pierce's rule
- result.append('K');
- index += 2;
- }
-
- return index;
- }
-
- /**
- * Handles 'CH' cases.
- */
- private int handleCH(final String value, final DoubleMetaphoneResult result, final int index) {
- if (index > 0 && contains(value, index, 4, "CHAE")) { // Michael
- result.append('K', 'X');
- return index + 2;
- } else if (conditionCH0(value, index)) {
- //-- Greek roots ("chemistry", "chorus", etc.) --//
- result.append('K');
- return index + 2;
- } else if (conditionCH1(value, index)) {
- //-- Germanic, Greek, or otherwise 'ch' for 'kh' sound --//
- result.append('K');
- return index + 2;
- } else {
- if (index > 0) {
- if (contains(value, 0, 2, "MC")) {
- result.append('K');
- } else {
- result.append('X', 'K');
- }
- } else {
- result.append('X');
- }
- return index + 2;
- }
- }
-
- /**
- * Handles 'D' cases.
- */
- private int handleD(final String value, final DoubleMetaphoneResult result, int index) {
- if (contains(value, index, 2, "DG")) {
- //-- "Edge" --//
- if (contains(value, index + 2, 1, "I", "E", "Y")) {
- result.append('J');
- index += 3;
- //-- "Edgar" --//
- } else {
- result.append("TK");
- index += 2;
- }
- } else if (contains(value, index, 2, "DT", "DD")) {
- result.append('T');
- index += 2;
- } else {
- result.append('T');
- index++;
- }
- return index;
- }
-
- /**
- * Handles 'G' cases.
- */
- private int handleG(final String value, final DoubleMetaphoneResult result, int index,
- final boolean slavoGermanic) {
- if (charAt(value, index + 1) == 'H') {
- index = handleGH(value, result, index);
- } else if (charAt(value, index + 1) == 'N') {
- if (index == 1 && isVowel(charAt(value, 0)) && !slavoGermanic) {
- result.append("KN", "N");
- } else if (!contains(value, index + 2, 2, "EY") &&
- charAt(value, index + 1) != 'Y' && !slavoGermanic) {
- result.append("N", "KN");
- } else {
- result.append("KN");
- }
- index = index + 2;
- } else if (contains(value, index + 1, 2, "LI") && !slavoGermanic) {
- result.append("KL", "L");
- index += 2;
- } else if (index == 0 &&
- (charAt(value, index + 1) == 'Y' ||
- contains(value, index + 1, 2, ES_EP_EB_EL_EY_IB_IL_IN_IE_EI_ER))) {
- //-- -ges-, -gep-, -gel-, -gie- at beginning --//
- result.append('K', 'J');
- index += 2;
- } else if ((contains(value, index + 1, 2, "ER") ||
- charAt(value, index + 1) == 'Y') &&
- !contains(value, 0, 6, "DANGER", "RANGER", "MANGER") &&
- !contains(value, index - 1, 1, "E", "I") &&
- !contains(value, index - 1, 3, "RGY", "OGY")) {
- //-- -ger-, -gy- --//
- result.append('K', 'J');
- index += 2;
- } else if (contains(value, index + 1, 1, "E", "I", "Y") ||
- contains(value, index - 1, 4, "AGGI", "OGGI")) {
- //-- Italian "biaggi" --//
- if (contains(value, 0, 4, "VAN ", "VON ") ||
- contains(value, 0, 3, "SCH") ||
- contains(value, index + 1, 2, "ET")) {
- //-- obvious germanic --//
- result.append('K');
- } else if (contains(value, index + 1, 3, "IER")) {
- result.append('J');
- } else {
- result.append('J', 'K');
- }
- index += 2;
- } else if (charAt(value, index + 1) == 'G') {
- index += 2;
- result.append('K');
- } else {
- index++;
- result.append('K');
- }
- return index;
- }
-
- /**
- * Handles 'GH' cases.
- */
- private int handleGH(final String value, final DoubleMetaphoneResult result, int index) {
- if (index > 0 && !isVowel(charAt(value, index - 1))) {
- result.append('K');
- index += 2;
- } else if (index == 0) {
- if (charAt(value, index + 2) == 'I') {
- result.append('J');
- } else {
- result.append('K');
- }
- index += 2;
- } else if ((index > 1 && contains(value, index - 2, 1, "B", "H", "D")) ||
- (index > 2 && contains(value, index - 3, 1, "B", "H", "D")) ||
- (index > 3 && contains(value, index - 4, 1, "B", "H"))) {
- //-- Parker's rule (with some further refinements) - "hugh"
- index += 2;
- } else {
- if (index > 2 && charAt(value, index - 1) == 'U' &&
- contains(value, index - 3, 1, "C", "G", "L", "R", "T")) {
- //-- "laugh", "McLaughlin", "cough", "gough", "rough", "tough"
- result.append('F');
- } else if (index > 0 && charAt(value, index - 1) != 'I') {
- result.append('K');
- }
- index += 2;
- }
- return index;
- }
-
- /**
- * Handles 'H' cases.
- */
- private int handleH(final String value, final DoubleMetaphoneResult result, int index) {
- //-- only keep if first & before vowel or between 2 vowels --//
- if ((index == 0 || isVowel(charAt(value, index - 1))) &&
- isVowel(charAt(value, index + 1))) {
- result.append('H');
- index += 2;
- //-- also takes car of "HH" --//
- } else {
- index++;
- }
- return index;
- }
-
- /**
- * Handles 'J' cases.
- */
- private int handleJ(final String value, final DoubleMetaphoneResult result, int index,
- final boolean slavoGermanic) {
- if (contains(value, index, 4, "JOSE") || contains(value, 0, 4, "SAN ")) {
- //-- obvious Spanish, "Jose", "San Jacinto" --//
- if ((index == 0 && (charAt(value, index + 4) == ' ') ||
- value.length() == 4) || contains(value, 0, 4, "SAN ")) {
- result.append('H');
- } else {
- result.append('J', 'H');
- }
- index++;
- } else {
- if (index == 0 && !contains(value, index, 4, "JOSE")) {
- result.append('J', 'A');
- } else if (isVowel(charAt(value, index - 1)) && !slavoGermanic &&
- (charAt(value, index + 1) == 'A' || charAt(value, index + 1) == 'O')) {
- result.append('J', 'H');
- } else if (index == value.length() - 1) {
- result.append('J', ' ');
- } else if (!contains(value, index + 1, 1, L_T_K_S_N_M_B_Z) &&
- !contains(value, index - 1, 1, "S", "K", "L")) {
- result.append('J');
- }
-
- if (charAt(value, index + 1) == 'J') {
- index += 2;
- } else {
- index++;
- }
- }
- return index;
- }
-
- /**
- * Handles 'L' cases.
- */
- private int handleL(final String value, final DoubleMetaphoneResult result, int index) {
- if (charAt(value, index + 1) == 'L') {
- if (conditionL0(value, index)) {
- result.appendPrimary('L');
- } else {
- result.append('L');
- }
- index += 2;
- } else {
- index++;
- result.append('L');
- }
- return index;
- }
-
- /**
- * Handles 'P' cases.
- */
- private int handleP(final String value, final DoubleMetaphoneResult result, int index) {
- if (charAt(value, index + 1) == 'H') {
- result.append('F');
- index += 2;
- } else {
- result.append('P');
- index = contains(value, index + 1, 1, "P", "B") ? index + 2 : index + 1;
- }
- return index;
- }
-
- /**
- * Handles 'R' cases.
- */
- private int handleR(final String value, final DoubleMetaphoneResult result, final int index,
- final boolean slavoGermanic) {
- if (index == value.length() - 1 && !slavoGermanic &&
- contains(value, index - 2, 2, "IE") &&
- !contains(value, index - 4, 2, "ME", "MA")) {
- result.appendAlternate('R');
- } else {
- result.append('R');
- }
- return charAt(value, index + 1) == 'R' ? index + 2 : index + 1;
- }
-
- /**
- * Handles 'S' cases.
- */
- private int handleS(final String value, final DoubleMetaphoneResult result, int index,
- final boolean slavoGermanic) {
- if (contains(value, index - 1, 3, "ISL", "YSL")) {
- //-- special cases "island", "isle", "carlisle", "carlysle" --//
- index++;
- } else if (index == 0 && contains(value, index, 5, "SUGAR")) {
- //-- special case "sugar-" --//
- result.append('X', 'S');
- index++;
- } else if (contains(value, index, 2, "SH")) {
- if (contains(value, index + 1, 4, "HEIM", "HOEK", "HOLM", "HOLZ")) {
- //-- germanic --//
- result.append('S');
- } else {
- result.append('X');
- }
- index += 2;
- } else if (contains(value, index, 3, "SIO", "SIA") || contains(value, index, 4, "SIAN")) {
- //-- Italian and Armenian --//
- if (slavoGermanic) {
- result.append('S');
- } else {
- result.append('S', 'X');
- }
- index += 3;
- } else if ((index == 0 && contains(value, index + 1, 1, "M", "N", "L", "W")) ||
- contains(value, index + 1, 1, "Z")) {
- //-- german & anglicisations, e.g. "smith" match "schmidt" //
- // "snider" match "schneider" --//
- //-- also, -sz- in slavic language although in hungarian it //
- // is pronounced "s" --//
- result.append('S', 'X');
- index = contains(value, index + 1, 1, "Z") ? index + 2 : index + 1;
- } else if (contains(value, index, 2, "SC")) {
- index = handleSC(value, result, index);
- } else {
- if (index == value.length() - 1 && contains(value, index - 2, 2, "AI", "OI")) {
- //-- french e.g. "resnais", "artois" --//
- result.appendAlternate('S');
- } else {
- result.append('S');
- }
- index = contains(value, index + 1, 1, "S", "Z") ? index + 2 : index + 1;
- }
- return index;
- }
-
- /**
- * Handles 'SC' cases.
- */
- private int handleSC(final String value, final DoubleMetaphoneResult result, final int index) {
- if (charAt(value, index + 2) == 'H') {
- //-- Schlesinger's rule --//
- if (contains(value, index + 3, 2, "OO", "ER", "EN", "UY", "ED", "EM")) {
- //-- Dutch origin, e.g. "school", "schooner" --//
- if (contains(value, index + 3, 2, "ER", "EN")) {
- //-- "schermerhorn", "schenker" --//
- result.append("X", "SK");
- } else {
- result.append("SK");
- }
- } else {
- if (index == 0 && !isVowel(charAt(value, 3)) && charAt(value, 3) != 'W') {
- result.append('X', 'S');
- } else {
- result.append('X');
- }
- }
- } else if (contains(value, index + 2, 1, "I", "E", "Y")) {
- result.append('S');
- } else {
- result.append("SK");
- }
- return index + 3;
- }
-
- /**
- * Handles 'T' cases.
- */
- private int handleT(final String value, final DoubleMetaphoneResult result, int index) {
- if (contains(value, index, 4, "TION")) {
- result.append('X');
- index += 3;
- } else if (contains(value, index, 3, "TIA", "TCH")) {
- result.append('X');
- index += 3;
- } else if (contains(value, index, 2, "TH") || contains(value, index, 3, "TTH")) {
- if (contains(value, index + 2, 2, "OM", "AM") ||
- //-- special case "thomas", "thames" or germanic --//
- contains(value, 0, 4, "VAN ", "VON ") ||
- contains(value, 0, 3, "SCH")) {
- result.append('T');
- } else {
- result.append('0', 'T');
- }
- index += 2;
- } else {
- result.append('T');
- index = contains(value, index + 1, 1, "T", "D") ? index + 2 : index + 1;
- }
- return index;
- }
-
- /**
- * Handles 'W' cases.
- */
- private int handleW(final String value, final DoubleMetaphoneResult result, int index) {
- if (contains(value, index, 2, "WR")) {
- //-- can also be in middle of word --//
- result.append('R');
- index += 2;
- } else {
- if (index == 0 && (isVowel(charAt(value, index + 1)) ||
- contains(value, index, 2, "WH"))) {
- if (isVowel(charAt(value, index + 1))) {
- //-- Wasserman should match Vasserman --//
- result.append('A', 'F');
- } else {
- //-- need Uomo to match Womo --//
- result.append('A');
- }
- index++;
- } else if ((index == value.length() - 1 && isVowel(charAt(value, index - 1))) ||
- contains(value, index - 1, 5, "EWSKI", "EWSKY", "OWSKI", "OWSKY") ||
- contains(value, 0, 3, "SCH")) {
- //-- Arnow should match Arnoff --//
- result.appendAlternate('F');
- index++;
- } else if (contains(value, index, 4, "WICZ", "WITZ")) {
- //-- Polish e.g. "filipowicz" --//
- result.append("TS", "FX");
- index += 4;
- } else {
- index++;
- }
- }
- return index;
- }
-
- /**
- * Handles 'X' cases.
- */
- private int handleX(final String value, final DoubleMetaphoneResult result, int index) {
- if (index == 0) {
- result.append('S');
- index++;
- } else {
- if (!((index == value.length() - 1) &&
- (contains(value, index - 3, 3, "IAU", "EAU") ||
- contains(value, index - 2, 2, "AU", "OU")))) {
- //-- French e.g. breaux --//
- result.append("KS");
- }
- index = contains(value, index + 1, 1, "C", "X") ? index + 2 : index + 1;
- }
- return index;
- }
-
- /**
- * Handles 'Z' cases.
- */
- private int handleZ(final String value, final DoubleMetaphoneResult result, int index,
- final boolean slavoGermanic) {
- if (charAt(value, index + 1) == 'H') {
- //-- Chinese pinyin e.g. "zhao" or Angelina "Zhang" --//
- result.append('J');
- index += 2;
- } else {
- if (contains(value, index + 1, 2, "ZO", "ZI", "ZA") ||
- (slavoGermanic && (index > 0 && charAt(value, index - 1) != 'T'))) {
- result.append("S", "TS");
- } else {
- result.append('S');
- }
- index = charAt(value, index + 1) == 'Z' ? index + 2 : index + 1;
- }
- return index;
- }
-
- //-- BEGIN CONDITIONS --//
-
- /**
- * Complex condition 0 for 'C'.
- */
- private boolean conditionC0(final String value, final int index) {
- if (contains(value, index, 4, "CHIA")) {
- return true;
- } else if (index <= 1) {
- return false;
- } else if (isVowel(charAt(value, index - 2))) {
- return false;
- } else if (!contains(value, index - 1, 3, "ACH")) {
- return false;
- } else {
- final char c = charAt(value, index + 2);
- return (c != 'I' && c != 'E') ||
- contains(value, index - 2, 6, "BACHER", "MACHER");
- }
- }
-
- /**
- * Complex condition 0 for 'CH'.
- */
- private boolean conditionCH0(final String value, final int index) {
- if (index != 0) {
- return false;
- } else if (!contains(value, index + 1, 5, "HARAC", "HARIS") &&
- !contains(value, index + 1, 3, "HOR", "HYM", "HIA", "HEM")) {
- return false;
- } else if (contains(value, 0, 5, "CHORE")) {
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * Complex condition 1 for 'CH'.
- */
- private boolean conditionCH1(final String value, final int index) {
- return ((contains(value, 0, 4, "VAN ", "VON ") || contains(value, 0, 3, "SCH")) ||
- contains(value, index - 2, 6, "ORCHES", "ARCHIT", "ORCHID") ||
- contains(value, index + 2, 1, "T", "S") ||
- ((contains(value, index - 1, 1, "A", "O", "U", "E") || index == 0) &&
- (contains(value, index + 2, 1, L_R_N_M_B_H_F_V_W_SPACE) || index + 1 == value.length() - 1)));
- }
-
- /**
- * Complex condition 0 for 'L'.
- */
- private boolean conditionL0(final String value, final int index) {
- if (index == value.length() - 3 &&
- contains(value, index - 1, 4, "ILLO", "ILLA", "ALLE")) {
- return true;
- } else if ((contains(value, value.length() - 2, 2, "AS", "OS") ||
- contains(value, value.length() - 1, 1, "A", "O")) &&
- contains(value, index - 1, 4, "ALLE")) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Complex condition 0 for 'M'.
- */
- private boolean conditionM0(final String value, final int index) {
- if (charAt(value, index + 1) == 'M') {
- return true;
- }
- return contains(value, index - 1, 3, "UMB") &&
- ((index + 1) == value.length() - 1 || contains(value, index + 2, 2, "ER"));
- }
-
- //-- BEGIN HELPER FUNCTIONS --//
-
- /**
- * Determines whether or not a value is of slavo-germanic origin. A value is
- * of slavo-germanic origin if it contians any of 'W', 'K', 'CZ', or 'WITZ'.
- */
- private boolean isSlavoGermanic(final String value) {
- return value.indexOf('W') > -1 || value.indexOf('K') > -1 ||
- value.indexOf("CZ") > -1 || value.indexOf("WITZ") > -1;
- }
-
- /**
- * Determines whether or not a character is a vowel or not
- */
- private boolean isVowel(final char ch) {
- return VOWELS.indexOf(ch) != -1;
- }
-
- /**
- * Determines whether or not the value starts with a silent letter. It will
- * return true
if the value starts with any of 'GN', 'KN',
- * 'PN', 'WR' or 'PS'.
- */
- private boolean isSilentStart(final String value) {
- boolean result = false;
- for (final String element : SILENT_START) {
- if (value.startsWith(element)) {
- result = true;
- break;
- }
- }
- return result;
- }
-
- /**
- * Cleans the input.
- */
- private String cleanInput(String input) {
- if (input == null) {
- return null;
- }
- input = input.trim();
- if (input.length() == 0) {
- return null;
- }
- return input.toUpperCase(java.util.Locale.ENGLISH);
- }
-
- /*
- * Gets the character at index index
if available, otherwise
- * it returns Character.MIN_VALUE
so that there is some sort
- * of a default.
- */
- protected char charAt(final String value, final int index) {
- if (index < 0 || index >= value.length()) {
- return Character.MIN_VALUE;
- }
- return value.charAt(index);
- }
-
- /*
- * Determines whether value
contains any of the criteria starting at index start
and
- * matching up to length length
.
- */
- protected static boolean contains(final String value, final int start, final int length,
- final String... criteria) {
- boolean result = false;
- if (start >= 0 && start + length <= value.length()) {
- final String target = value.substring(start, start + length);
-
- for (final String element : criteria) {
- if (target.equals(element)) {
- result = true;
- break;
- }
- }
- }
- return result;
- }
-
- //-- BEGIN INNER CLASSES --//
-
- /**
- * Inner class for storing results, since there is the optional alternate encoding.
- */
- public class DoubleMetaphoneResult {
-
- private final StringBuilder primary = new StringBuilder(getMaxCodeLen());
- private final StringBuilder alternate = new StringBuilder(getMaxCodeLen());
- private final int maxLength;
-
- public DoubleMetaphoneResult(final int maxLength) {
- this.maxLength = maxLength;
- }
-
- public void append(final char value) {
- appendPrimary(value);
- appendAlternate(value);
- }
-
- public void append(final char primary, final char alternate) {
- appendPrimary(primary);
- appendAlternate(alternate);
- }
-
- public void appendPrimary(final char value) {
- if (this.primary.length() < this.maxLength) {
- this.primary.append(value);
- }
- }
-
- public void appendAlternate(final char value) {
- if (this.alternate.length() < this.maxLength) {
- this.alternate.append(value);
- }
- }
-
- public void append(final String value) {
- appendPrimary(value);
- appendAlternate(value);
- }
-
- public void append(final String primary, final String alternate) {
- appendPrimary(primary);
- appendAlternate(alternate);
- }
-
- public void appendPrimary(final String value) {
- final int addChars = this.maxLength - this.primary.length();
- if (value.length() <= addChars) {
- this.primary.append(value);
- } else {
- this.primary.append(value.substring(0, addChars));
- }
- }
-
- public void appendAlternate(final String value) {
- final int addChars = this.maxLength - this.alternate.length();
- if (value.length() <= addChars) {
- this.alternate.append(value);
- } else {
- this.alternate.append(value.substring(0, addChars));
- }
- }
-
- public String getPrimary() {
- return this.primary.toString();
- }
-
- public String getAlternate() {
- return this.alternate.toString();
- }
-
- public boolean isComplete() {
- return this.primary.length() >= this.maxLength &&
- this.alternate.length() >= this.maxLength;
- }
- }
-}
diff --git a/src/org/apache/commons/codec/language/MatchRatingApproachEncoder.java b/src/org/apache/commons/codec/language/MatchRatingApproachEncoder.java
deleted file mode 100644
index 0ae4c323..00000000
--- a/src/org/apache/commons/codec/language/MatchRatingApproachEncoder.java
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.codec.language;
-
-import java.util.Locale;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Match Rating Approach Phonetic Algorithm Developed by Western Airlines in 1977.
- *
- * This class is immutable and thread-safe.
- *
- * @see Wikipedia - Match Rating Approach
- * @since 1.8
- */
-public class MatchRatingApproachEncoder implements StringEncoder {
-
- private static final String SPACE = " ";
-
- private static final String EMPTY = "";
-
- /**
- * Constants used mainly for the min rating value.
- */
- private static final int ONE = 1, TWO = 2, THREE = 3, FOUR = 4, FIVE = 5, SIX = 6, SEVEN = 7, EIGHT = 8,
- ELEVEN = 11, TWELVE = 12;
-
- /**
- * The plain letter equivalent of the accented letters.
- */
- private static final String PLAIN_ASCII = "AaEeIiOoUu" + // grave
- "AaEeIiOoUuYy" + // acute
- "AaEeIiOoUuYy" + // circumflex
- "AaOoNn" + // tilde
- "AaEeIiOoUuYy" + // umlaut
- "Aa" + // ring
- "Cc" + // cedilla
- "OoUu"; // double acute
-
- /**
- * Unicode characters corresponding to various accented letters. For example: \u00DA is U acute etc...
- */
- private static final String UNICODE = "\u00C0\u00E0\u00C8\u00E8\u00CC\u00EC\u00D2\u00F2\u00D9\u00F9" +
- "\u00C1\u00E1\u00C9\u00E9\u00CD\u00ED\u00D3\u00F3\u00DA\u00FA\u00DD\u00FD" +
- "\u00C2\u00E2\u00CA\u00EA\u00CE\u00EE\u00D4\u00F4\u00DB\u00FB\u0176\u0177" +
- "\u00C3\u00E3\u00D5\u00F5\u00D1\u00F1" +
- "\u00C4\u00E4\u00CB\u00EB\u00CF\u00EF\u00D6\u00F6\u00DC\u00FC\u0178\u00FF" +
- "\u00C5\u00E5" + "\u00C7\u00E7" + "\u0150\u0151\u0170\u0171";
-
- private static final String[] DOUBLE_CONSONANT =
- new String[]{"BB", "CC", "DD", "FF", "GG", "HH", "JJ", "KK", "LL", "MM", "NN", "PP", "QQ", "RR", "SS",
- "TT", "VV", "WW", "XX", "YY", "ZZ"};
-
- /**
- * Cleans up a name: 1. Upper-cases everything 2. Removes some common punctuation 3. Removes accents 4. Removes any
- * spaces.
- *
- *
API Usage
- *
- * Consider this method private, it is package protected for unit testing only.
- *
- *
- * @param name The name to be cleaned
- * @return The cleaned name
- */
- String cleanName(final String name) {
- String upperName = name.toUpperCase(Locale.ENGLISH);
-
- final String[] charsToTrim = {"\\-", "[&]", "\\'", "\\.", "[\\,]"};
- for (final String str : charsToTrim) {
- upperName = upperName.replaceAll(str, EMPTY);
- }
-
- upperName = removeAccents(upperName);
- upperName = upperName.replaceAll("\\s+", EMPTY);
-
- return upperName;
- }
-
- /**
- * Encodes an Object using the Match Rating Approach algorithm. Method is here to satisfy the requirements of the
- * Encoder interface Throws an EncoderException if input object is not of type java.lang.String.
- *
- * @param pObject Object to encode
- * @return An object (or type java.lang.String) containing the Match Rating Approach code which corresponds to the
- * String supplied.
- * @throws EncoderException if the parameter supplied is not of type java.lang.String
- */
- @Override
- public final Object encode(final Object pObject) throws EncoderException {
- if (!(pObject instanceof String)) {
- throw new EncoderException(
- "Parameter supplied to Match Rating Approach encoder is not of type java.lang.String");
- }
- return encode((String) pObject);
- }
-
- /**
- * Encodes a String using the Match Rating Approach (MRA) algorithm.
- *
- * @param name String object to encode
- * @return The MRA code corresponding to the String supplied
- */
- @Override
- public final String encode(String name) {
- // Bulletproof for trivial input - NINO
- if (name == null || EMPTY.equalsIgnoreCase(name) || SPACE.equalsIgnoreCase(name) || name.length() == 1) {
- return EMPTY;
- }
-
- // Preprocessing
- name = cleanName(name);
-
- // BEGIN: Actual encoding part of the algorithm...
- // 1. Delete all vowels unless the vowel begins the word
- name = removeVowels(name);
-
- // 2. Remove second consonant from any double consonant
- name = removeDoubleConsonants(name);
-
- // 3. Reduce codex to 6 letters by joining the first 3 and last 3 letters
- name = getFirst3Last3(name);
-
- return name;
- }
-
- /**
- * Gets the first and last 3 letters of a name (if > 6 characters) Else just returns the name.
- *
- *
API Usage
- *
- * Consider this method private, it is package protected for unit testing only.
- *
- *
- * @param name The string to get the substrings from
- * @return Annexed first and last 3 letters of input word.
- */
- String getFirst3Last3(final String name) {
- final int nameLength = name.length();
-
- if (nameLength > SIX) {
- final String firstThree = name.substring(0, THREE);
- final String lastThree = name.substring(nameLength - THREE, nameLength);
- return firstThree + lastThree;
- } else {
- return name;
- }
- }
-
- /**
- * Obtains the min rating of the length sum of the 2 names. In essence the larger the sum length the smaller the
- * min rating. Values strictly from documentation.
- *
- *
API Usage
- *
- * Consider this method private, it is package protected for unit testing only.
- *
- *
- * @param sumLength The length of 2 strings sent down
- * @return The min rating value
- */
- int getMinRating(final int sumLength) {
- int minRating = 0;
-
- if (sumLength <= FOUR) {
- minRating = FIVE;
- } else if (sumLength >= FIVE && sumLength <= SEVEN) {
- minRating = FOUR;
- } else if (sumLength >= EIGHT && sumLength <= ELEVEN) {
- minRating = THREE;
- } else if (sumLength == TWELVE) {
- minRating = TWO;
- } else {
- minRating = ONE; // docs said little here.
- }
-
- return minRating;
- }
-
- /**
- * Determines if two names are homophonous via Match Rating Approach (MRA) algorithm. It should be noted that the
- * strings are cleaned in the same way as {@link #encode(String)}.
- *
- * @param name1 First of the 2 strings (names) to compare
- * @param name2 Second of the 2 names to compare
- * @return true
if the encodings are identical false
otherwise.
- */
- public boolean isEncodeEquals(String name1, String name2) {
- // Bulletproof for trivial input - NINO
- if (name1 == null || EMPTY.equalsIgnoreCase(name1) || SPACE.equalsIgnoreCase(name1)) {
- return false;
- } else if (name2 == null || EMPTY.equalsIgnoreCase(name2) || SPACE.equalsIgnoreCase(name2)) {
- return false;
- } else if (name1.length() == 1 || name2.length() == 1) {
- return false;
- } else if (name1.equalsIgnoreCase(name2)) {
- return true;
- }
-
- // Preprocessing
- name1 = cleanName(name1);
- name2 = cleanName(name2);
-
- // Actual MRA Algorithm
-
- // 1. Remove vowels
- name1 = removeVowels(name1);
- name2 = removeVowels(name2);
-
- // 2. Remove double consonants
- name1 = removeDoubleConsonants(name1);
- name2 = removeDoubleConsonants(name2);
-
- // 3. Reduce down to 3 letters
- name1 = getFirst3Last3(name1);
- name2 = getFirst3Last3(name2);
-
- // 4. Check for length difference - if 3 or greater then no similarity
- // comparison is done
- if (Math.abs(name1.length() - name2.length()) >= THREE) {
- return false;
- }
-
- // 5. Obtain the minimum rating value by calculating the length sum of the
- // encoded Strings and sending it down.
- final int sumLength = Math.abs(name1.length() + name2.length());
- int minRating = 0;
- minRating = getMinRating(sumLength);
-
- // 6. Process the encoded Strings from left to right and remove any
- // identical characters found from both Strings respectively.
- final int count = leftToRightThenRightToLeftProcessing(name1, name2);
-
- // 7. Each PNI item that has a similarity rating equal to or greater than
- // the min is considered to be a good candidate match
- return count >= minRating;
-
- }
-
- /**
- * Determines if a letter is a vowel.
- *
- *
API Usage
- *
- * Consider this method private, it is package protected for unit testing only.
- *
- *
- * @param letter The letter under investiagtion
- * @return True if a vowel, else false
- */
- boolean isVowel(final String letter) {
- return letter.equalsIgnoreCase("E") || letter.equalsIgnoreCase("A") || letter.equalsIgnoreCase("O") ||
- letter.equalsIgnoreCase("I") || letter.equalsIgnoreCase("U");
- }
-
- /**
- * Processes the names from left to right (first) then right to left removing identical letters in same positions.
- * Then subtracts the longer string that remains from 6 and returns this.
- *
- *
API Usage
- *
- * Consider this method private, it is package protected for unit testing only.
- *
- *
- * @param name1 name2
- * @return
- */
- int leftToRightThenRightToLeftProcessing(final String name1, final String name2) {
- final char[] name1Char = name1.toCharArray();
- final char[] name2Char = name2.toCharArray();
-
- final int name1Size = name1.length() - 1;
- final int name2Size = name2.length() - 1;
-
- String name1LtRStart = EMPTY;
- String name1LtREnd = EMPTY;
-
- String name2RtLStart = EMPTY;
- String name2RtLEnd = EMPTY;
-
- for (int i = 0; i < name1Char.length; i++) {
- if (i > name2Size) {
- break;
- }
-
- name1LtRStart = name1.substring(i, i + 1);
- name1LtREnd = name1.substring(name1Size - i, name1Size - i + 1);
-
- name2RtLStart = name2.substring(i, i + 1);
- name2RtLEnd = name2.substring(name2Size - i, name2Size - i + 1);
-
- // Left to right...
- if (name1LtRStart.equals(name2RtLStart)) {
- name1Char[i] = ' ';
- name2Char[i] = ' ';
- }
-
- // Right to left...
- if (name1LtREnd.equals(name2RtLEnd)) {
- name1Char[name1Size - i] = ' ';
- name2Char[name2Size - i] = ' ';
- }
- }
-
- // Char arrays -> string & remove extraneous space
- final String strA = new String(name1Char).replaceAll("\\s+", EMPTY);
- final String strB = new String(name2Char).replaceAll("\\s+", EMPTY);
-
- // Final bit - subtract longest string from 6 and return this int value
- if (strA.length() > strB.length()) {
- return Math.abs(SIX - strA.length());
- } else {
- return Math.abs(SIX - strB.length());
- }
- }
-
- /**
- * Removes accented letters and replaces with non-accented ascii equivalent Case is preserved.
- * http://www.codecodex.com/wiki/Remove_accent_from_letters_%28ex_.%C3%A9_to_e%29
- *
- * @param accentedWord The word that may have accents in it.
- * @return De-accented word
- */
- String removeAccents(final String accentedWord) {
- if (accentedWord == null) {
- return null;
- }
-
- final StringBuilder sb = new StringBuilder();
- final int n = accentedWord.length();
-
- for (int i = 0; i < n; i++) {
- final char c = accentedWord.charAt(i);
- final int pos = UNICODE.indexOf(c);
- if (pos > -1) {
- sb.append(PLAIN_ASCII.charAt(pos));
- } else {
- sb.append(c);
- }
- }
-
- return sb.toString();
- }
-
- /**
- * Replaces any double consonant pair with the single letter equivalent.
- *
- *
API Usage
- *
- * Consider this method private, it is package protected for unit testing only.
- *
- *
- * @param name String to have double consonants removed
- * @return Single consonant word
- */
- String removeDoubleConsonants(final String name) {
- String replacedName = name.toUpperCase();
- for (final String dc : DOUBLE_CONSONANT) {
- if (replacedName.contains(dc)) {
- final String singleLetter = dc.substring(0, 1);
- replacedName = replacedName.replace(dc, singleLetter);
- }
- }
- return replacedName;
- }
-
- /**
- * Deletes all vowels unless the vowel begins the word.
- *
- *
API Usage
- *
- * Consider this method private, it is package protected for unit testing only.
- *
- *
- * @param name The name to have vowels removed
- * @return De-voweled word
- */
- String removeVowels(String name) {
- // Extract first letter
- final String firstLetter = name.substring(0, 1);
-
- name = name.replaceAll("A", EMPTY);
- name = name.replaceAll("E", EMPTY);
- name = name.replaceAll("I", EMPTY);
- name = name.replaceAll("O", EMPTY);
- name = name.replaceAll("U", EMPTY);
-
- name = name.replaceAll("\\s{2,}\\b", SPACE);
-
- // return isVowel(firstLetter) ? (firstLetter + name) : name;
- if (isVowel(firstLetter)) {
- return firstLetter + name;
- } else {
- return name;
- }
- }
-}
diff --git a/src/org/apache/commons/codec/language/Metaphone.java b/src/org/apache/commons/codec/language/Metaphone.java
deleted file mode 100644
index 0b48602f..00000000
--- a/src/org/apache/commons/codec/language/Metaphone.java
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Encodes a string into a Metaphone value.
- *
- * Initial Java implementation by William B. Brogden. December, 1997 .
- * Permission given by wbrogden for code to be used anywhere.
- *
- * Hanging on the Metaphone by Lawrence Philips in Computer Language of Dec. 1990,
- * p 39.
- *
- * Note, that this does not match the algorithm that ships with PHP, or the algorithm found in the Perl implementations:
- *
- *
- *
- * They have had undocumented changes from the originally published algorithm.
- * For more information, see CODEC-57 .
- *
- * This class is conditionally thread-safe.
- * The instance field {@link #maxCodeLen} is mutable {@link #setMaxCodeLen(int)}
- * but is not volatile, and accesses are not synchronized.
- * If an instance of the class is shared between threads, the caller needs to ensure that suitable synchronization
- * is used to ensure safe publication of the value between threads, and must not invoke {@link #setMaxCodeLen(int)}
- * after initial setup.
- *
- * @version $Id$
- */
-public class Metaphone implements StringEncoder {
-
- /**
- * Five values in the English language
- */
- private static final String VOWELS = "AEIOU";
-
- /**
- * Variable used in Metaphone algorithm
- */
- private static final String FRONTV = "EIY";
-
- /**
- * Variable used in Metaphone algorithm
- */
- private static final String VARSON = "CSPTG";
-
- /**
- * The max code length for metaphone is 4
- */
- private int maxCodeLen = 4;
-
- /**
- * Creates an instance of the Metaphone encoder
- */
- public Metaphone() {
- super();
- }
-
- /**
- * Find the metaphone value of a String. This is similar to the
- * soundex algorithm, but better at finding similar sounding words.
- * All input is converted to upper case.
- * Limitations: Input format is expected to be a single ASCII word
- * with only characters in the A - Z range, no punctuation or numbers.
- *
- * @param txt String to find the metaphone code for
- * @return A metaphone code corresponding to the String supplied
- */
- public String metaphone(final String txt) {
- boolean hard = false;
- int txtLength;
- if (txt == null || (txtLength = txt.length()) == 0) {
- return "";
- }
- // single character is itself
- if (txtLength == 1) {
- return txt.toUpperCase(java.util.Locale.ENGLISH);
- }
-
- final char[] inwd = txt.toUpperCase(java.util.Locale.ENGLISH).toCharArray();
-
- final StringBuilder local = new StringBuilder(40); // manipulate
- final StringBuilder code = new StringBuilder(10); // output
- // handle initial 2 characters exceptions
- switch (inwd[0]) {
- case 'K':
- case 'G':
- case 'P': /* looking for KN, etc*/
- if (inwd[1] == 'N') {
- local.append(inwd, 1, inwd.length - 1);
- } else {
- local.append(inwd);
- }
- break;
- case 'A': /* looking for AE */
- if (inwd[1] == 'E') {
- local.append(inwd, 1, inwd.length - 1);
- } else {
- local.append(inwd);
- }
- break;
- case 'W': /* looking for WR or WH */
- if (inwd[1] == 'R') { // WR -> R
- local.append(inwd, 1, inwd.length - 1);
- break;
- }
- if (inwd[1] == 'H') {
- local.append(inwd, 1, inwd.length - 1);
- local.setCharAt(0, 'W'); // WH -> W
- } else {
- local.append(inwd);
- }
- break;
- case 'X': /* initial X becomes S */
- inwd[0] = 'S';
- local.append(inwd);
- break;
- default:
- local.append(inwd);
- } // now local has working string with initials fixed
-
- final int wdsz = local.length();
- int n = 0;
-
- while (code.length() < this.getMaxCodeLen() &&
- n < wdsz) { // max code size of 4 works well
- final char symb = local.charAt(n);
- // remove duplicate letters except C
- if (symb != 'C' && isPreviousChar(local, n, symb)) {
- n++;
- } else { // not dup
- switch (symb) {
- case 'A':
- case 'E':
- case 'I':
- case 'O':
- case 'U':
- if (n == 0) {
- code.append(symb);
- }
- break; // only use vowel if leading char
- case 'B':
- if (isPreviousChar(local, n, 'M') &&
- isLastChar(wdsz, n)) { // B is silent if word ends in MB
- break;
- }
- code.append(symb);
- break;
- case 'C': // lots of C special cases
- /* discard if SCI, SCE or SCY */
- if (isPreviousChar(local, n, 'S') &&
- !isLastChar(wdsz, n) &&
- FRONTV.indexOf(local.charAt(n + 1)) >= 0) {
- break;
- }
- if (regionMatch(local, n, "CIA")) { // "CIA" -> X
- code.append('X');
- break;
- }
- if (!isLastChar(wdsz, n) &&
- FRONTV.indexOf(local.charAt(n + 1)) >= 0) {
- code.append('S');
- break; // CI,CE,CY -> S
- }
- if (isPreviousChar(local, n, 'S') &&
- isNextChar(local, n, 'H')) { // SCH->sk
- code.append('K');
- break;
- }
- if (isNextChar(local, n, 'H')) { // detect CH
- if (n == 0 &&
- wdsz >= 3 &&
- isVowel(local, 2)) { // CH consonant -> K consonant
- code.append('K');
- } else {
- code.append('X'); // CHvowel -> X
- }
- } else {
- code.append('K');
- }
- break;
- case 'D':
- if (!isLastChar(wdsz, n + 1) &&
- isNextChar(local, n, 'G') &&
- FRONTV.indexOf(local.charAt(n + 2)) >= 0) { // DGE DGI DGY -> J
- code.append('J');
- n += 2;
- } else {
- code.append('T');
- }
- break;
- case 'G': // GH silent at end or before consonant
- if (isLastChar(wdsz, n + 1) &&
- isNextChar(local, n, 'H')) {
- break;
- }
- if (!isLastChar(wdsz, n + 1) &&
- isNextChar(local, n, 'H') &&
- !isVowel(local, n + 2)) {
- break;
- }
- if (n > 0 &&
- (regionMatch(local, n, "GN") ||
- regionMatch(local, n, "GNED"))) {
- break; // silent G
- }
- if (isPreviousChar(local, n, 'G')) {
- // NOTE: Given that duplicated chars are removed, I don't see how this can ever be true
- hard = true;
- } else {
- hard = false;
- }
- if (!isLastChar(wdsz, n) &&
- FRONTV.indexOf(local.charAt(n + 1)) >= 0 &&
- !hard) {
- code.append('J');
- } else {
- code.append('K');
- }
- break;
- case 'H':
- if (isLastChar(wdsz, n)) {
- break; // terminal H
- }
- if (n > 0 &&
- VARSON.indexOf(local.charAt(n - 1)) >= 0) {
- break;
- }
- if (isVowel(local, n + 1)) {
- code.append('H'); // Hvowel
- }
- break;
- case 'F':
- case 'J':
- case 'L':
- case 'M':
- case 'N':
- case 'R':
- code.append(symb);
- break;
- case 'K':
- if (n > 0) { // not initial
- if (!isPreviousChar(local, n, 'C')) {
- code.append(symb);
- }
- } else {
- code.append(symb); // initial K
- }
- break;
- case 'P':
- if (isNextChar(local, n, 'H')) {
- // PH -> F
- code.append('F');
- } else {
- code.append(symb);
- }
- break;
- case 'Q':
- code.append('K');
- break;
- case 'S':
- if (regionMatch(local, n, "SH") ||
- regionMatch(local, n, "SIO") ||
- regionMatch(local, n, "SIA")) {
- code.append('X');
- } else {
- code.append('S');
- }
- break;
- case 'T':
- if (regionMatch(local, n, "TIA") ||
- regionMatch(local, n, "TIO")) {
- code.append('X');
- break;
- }
- if (regionMatch(local, n, "TCH")) {
- // Silent if in "TCH"
- break;
- }
- // substitute numeral 0 for TH (resembles theta after all)
- if (regionMatch(local, n, "TH")) {
- code.append('0');
- } else {
- code.append('T');
- }
- break;
- case 'V':
- code.append('F');
- break;
- case 'W':
- case 'Y': // silent if not followed by vowel
- if (!isLastChar(wdsz, n) &&
- isVowel(local, n + 1)) {
- code.append(symb);
- }
- break;
- case 'X':
- code.append('K');
- code.append('S');
- break;
- case 'Z':
- code.append('S');
- break;
- default:
- // do nothing
- break;
- } // end switch
- n++;
- } // end else from symb != 'C'
- if (code.length() > this.getMaxCodeLen()) {
- code.setLength(this.getMaxCodeLen());
- }
- }
- return code.toString();
- }
-
- private boolean isVowel(final StringBuilder string, final int index) {
- return VOWELS.indexOf(string.charAt(index)) >= 0;
- }
-
- private boolean isPreviousChar(final StringBuilder string, final int index, final char c) {
- boolean matches = false;
- if (index > 0 &&
- index < string.length()) {
- matches = string.charAt(index - 1) == c;
- }
- return matches;
- }
-
- private boolean isNextChar(final StringBuilder string, final int index, final char c) {
- boolean matches = false;
- if (index >= 0 &&
- index < string.length() - 1) {
- matches = string.charAt(index + 1) == c;
- }
- return matches;
- }
-
- private boolean regionMatch(final StringBuilder string, final int index, final String test) {
- boolean matches = false;
- if (index >= 0 &&
- index + test.length() - 1 < string.length()) {
- final String substring = string.substring(index, index + test.length());
- matches = substring.equals(test);
- }
- return matches;
- }
-
- private boolean isLastChar(final int wdsz, final int n) {
- return n + 1 == wdsz;
- }
-
-
- /**
- * Encodes an Object using the metaphone algorithm. This method
- * is provided in order to satisfy the requirements of the
- * Encoder interface, and will throw an EncoderException if the
- * supplied object is not of type java.lang.String.
- *
- * @param obj Object to encode
- * @return An object (or type java.lang.String) containing the
- * metaphone code which corresponds to the String supplied.
- * @throws EncoderException if the parameter supplied is not
- * of type java.lang.String
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (!(obj instanceof String)) {
- throw new EncoderException("Parameter supplied to Metaphone encode is not of type java.lang.String");
- }
- return metaphone((String) obj);
- }
-
- /**
- * Encodes a String using the Metaphone algorithm.
- *
- * @param str String object to encode
- * @return The metaphone code corresponding to the String supplied
- */
- @Override
- public String encode(final String str) {
- return metaphone(str);
- }
-
- /**
- * Tests is the metaphones of two strings are identical.
- *
- * @param str1 First of two strings to compare
- * @param str2 Second of two strings to compare
- * @return true
if the metaphones of these strings are identical,
- * false
otherwise.
- */
- public boolean isMetaphoneEqual(final String str1, final String str2) {
- return metaphone(str1).equals(metaphone(str2));
- }
-
- /**
- * Returns the maxCodeLen.
- *
- * @return int
- */
- public int getMaxCodeLen() {
- return this.maxCodeLen;
- }
-
- /**
- * Sets the maxCodeLen.
- *
- * @param maxCodeLen The maxCodeLen to set
- */
- public void setMaxCodeLen(final int maxCodeLen) {
- this.maxCodeLen = maxCodeLen;
- }
-}
diff --git a/src/org/apache/commons/codec/language/Nysiis.java b/src/org/apache/commons/codec/language/Nysiis.java
deleted file mode 100644
index 9a4e47bc..00000000
--- a/src/org/apache/commons/codec/language/Nysiis.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language;
-
-import java.util.regex.Pattern;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Encodes a string into a NYSIIS value. NYSIIS is an encoding used to relate similar names, but can also be used as a
- * general purpose scheme to find word with similar phonemes.
- *
- * NYSIIS features an accuracy increase of 2.7% over the traditional Soundex algorithm.
- *
- * Algorithm description:
- *
- * 1. Transcode first characters of name
- * 1a. MAC -> MCC
- * 1b. KN -> NN
- * 1c. K -> C
- * 1d. PH -> FF
- * 1e. PF -> FF
- * 1f. SCH -> SSS
- * 2. Transcode last characters of name
- * 2a. EE, IE -> Y
- * 2b. DT,RT,RD,NT,ND -> D
- * 3. First character of key = first character of name
- * 4. Transcode remaining characters by following these rules, incrementing by one character each time
- * 4a. EV -> AF else A,E,I,O,U -> A
- * 4b. Q -> G
- * 4c. Z -> S
- * 4d. M -> N
- * 4e. KN -> N else K -> C
- * 4f. SCH -> SSS
- * 4g. PH -> FF
- * 4h. H -> If previous or next is nonvowel, previous
- * 4i. W -> If previous is vowel, previous
- * 4j. Add current to key if current != last key character
- * 5. If last character is S, remove it
- * 6. If last characters are AY, replace with Y
- * 7. If last character is A, remove it
- * 8. Collapse all strings of repeated characters
- * 9. Add original first character of name as first character of key
- *
- *
- * This class is immutable and thread-safe.
- *
- * @version $Id$
- * @see NYSIIS on Wikipedia
- * @see NYSIIS on dropby.com
- * @see Soundex
- * @since 1.7
- */
-public class Nysiis implements StringEncoder {
-
- private static final char[] CHARS_A = new char[]{'A'};
- private static final char[] CHARS_AF = new char[]{'A', 'F'};
- private static final char[] CHARS_C = new char[]{'C'};
- private static final char[] CHARS_FF = new char[]{'F', 'F'};
- private static final char[] CHARS_G = new char[]{'G'};
- private static final char[] CHARS_N = new char[]{'N'};
- private static final char[] CHARS_NN = new char[]{'N', 'N'};
- private static final char[] CHARS_S = new char[]{'S'};
- private static final char[] CHARS_SSS = new char[]{'S', 'S', 'S'};
-
- private static final Pattern PAT_MAC = Pattern.compile("^MAC");
- private static final Pattern PAT_KN = Pattern.compile("^KN");
- private static final Pattern PAT_K = Pattern.compile("^K");
- private static final Pattern PAT_PH_PF = Pattern.compile("^(PH|PF)");
- private static final Pattern PAT_SCH = Pattern.compile("^SCH");
- private static final Pattern PAT_EE_IE = Pattern.compile("(EE|IE)$");
- private static final Pattern PAT_DT_ETC = Pattern.compile("(DT|RT|RD|NT|ND)$");
-
- private static final char SPACE = ' ';
- private static final int TRUE_LENGTH = 6;
-
- /**
- * Tests if the given character is a vowel.
- *
- * @param c the character to test
- * @return true
if the character is a vowel, false
otherwise
- */
- private static boolean isVowel(final char c) {
- return c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U';
- }
-
- /**
- * Transcodes the remaining parts of the String. The method operates on a sliding window, looking at 4 characters at
- * a time: [i-1, i, i+1, i+2].
- *
- * @param prev the previous character
- * @param curr the current character
- * @param next the next character
- * @param aNext the after next character
- * @return a transcoded array of characters, starting from the current position
- */
- private static char[] transcodeRemaining(final char prev, final char curr, final char next, final char aNext) {
- // 1. EV -> AF
- if (curr == 'E' && next == 'V') {
- return CHARS_AF;
- }
-
- // A, E, I, O, U -> A
- if (isVowel(curr)) {
- return CHARS_A;
- }
-
- // 2. Q -> G, Z -> S, M -> N
- if (curr == 'Q') {
- return CHARS_G;
- } else if (curr == 'Z') {
- return CHARS_S;
- } else if (curr == 'M') {
- return CHARS_N;
- }
-
- // 3. KN -> NN else K -> C
- if (curr == 'K') {
- if (next == 'N') {
- return CHARS_NN;
- } else {
- return CHARS_C;
- }
- }
-
- // 4. SCH -> SSS
- if (curr == 'S' && next == 'C' && aNext == 'H') {
- return CHARS_SSS;
- }
-
- // PH -> FF
- if (curr == 'P' && next == 'H') {
- return CHARS_FF;
- }
-
- // 5. H -> If previous or next is a non vowel, previous.
- if (curr == 'H' && (!isVowel(prev) || !isVowel(next))) {
- return new char[]{prev};
- }
-
- // 6. W -> If previous is vowel, previous.
- if (curr == 'W' && isVowel(prev)) {
- return new char[]{prev};
- }
-
- return new char[]{curr};
- }
-
- /**
- * Indicates the strict mode.
- */
- private final boolean strict;
-
- /**
- * Creates an instance of the {@link Nysiis} encoder with strict mode (original form),
- * i.e. encoded strings have a maximum length of 6.
- */
- public Nysiis() {
- this(true);
- }
-
- /**
- * Create an instance of the {@link Nysiis} encoder with the specified strict mode:
- *
- *
- * true
: encoded strings have a maximum length of 6
- * false
: encoded strings may have arbitrary length
- *
- *
- * @param strict the strict mode
- */
- public Nysiis(final boolean strict) {
- this.strict = strict;
- }
-
- /**
- * Encodes an Object using the NYSIIS algorithm. This method is provided in order to satisfy the requirements of the
- * Encoder interface, and will throw an {@link EncoderException} if the supplied object is not of type
- * {@link String}.
- *
- * @param obj Object to encode
- * @return An object (or a {@link String}) containing the NYSIIS code which corresponds to the given String.
- * @throws EncoderException if the parameter supplied is not of a {@link String}
- * @throws IllegalArgumentException if a character is not mapped
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (!(obj instanceof String)) {
- throw new EncoderException("Parameter supplied to Nysiis encode is not of type java.lang.String");
- }
- return this.nysiis((String) obj);
- }
-
- /**
- * Encodes a String using the NYSIIS algorithm.
- *
- * @param str A String object to encode
- * @return A Nysiis code corresponding to the String supplied
- * @throws IllegalArgumentException if a character is not mapped
- */
- @Override
- public String encode(final String str) {
- return this.nysiis(str);
- }
-
- /**
- * Indicates the strict mode for this {@link Nysiis} encoder.
- *
- * @return true
if the encoder is configured for strict mode, false
otherwise
- */
- public boolean isStrict() {
- return this.strict;
- }
-
- /**
- * Retrieves the NYSIIS code for a given String object.
- *
- * @param str String to encode using the NYSIIS algorithm
- * @return A NYSIIS code for the String supplied
- */
- public String nysiis(String str) {
- if (str == null) {
- return null;
- }
-
- // Use the same clean rules as Soundex
- str = SoundexUtils.clean(str);
-
- if (str.length() == 0) {
- return str;
- }
-
- // Translate first characters of name:
- // MAC -> MCC, KN -> NN, K -> C, PH | PF -> FF, SCH -> SSS
- str = PAT_MAC.matcher(str).replaceFirst("MCC");
- str = PAT_KN.matcher(str).replaceFirst("NN");
- str = PAT_K.matcher(str).replaceFirst("C");
- str = PAT_PH_PF.matcher(str).replaceFirst("FF");
- str = PAT_SCH.matcher(str).replaceFirst("SSS");
-
- // Translate last characters of name:
- // EE -> Y, IE -> Y, DT | RT | RD | NT | ND -> D
- str = PAT_EE_IE.matcher(str).replaceFirst("Y");
- str = PAT_DT_ETC.matcher(str).replaceFirst("D");
-
- // First character of key = first character of name.
- final StringBuilder key = new StringBuilder(str.length());
- key.append(str.charAt(0));
-
- // Transcode remaining characters, incrementing by one character each time
- final char[] chars = str.toCharArray();
- final int len = chars.length;
-
- for (int i = 1; i < len; i++) {
- final char next = i < len - 1 ? chars[i + 1] : SPACE;
- final char aNext = i < len - 2 ? chars[i + 2] : SPACE;
- final char[] transcoded = transcodeRemaining(chars[i - 1], chars[i], next, aNext);
- System.arraycopy(transcoded, 0, chars, i, transcoded.length);
-
- // only append the current char to the key if it is different from the last one
- if (chars[i] != chars[i - 1]) {
- key.append(chars[i]);
- }
- }
-
- if (key.length() > 1) {
- char lastChar = key.charAt(key.length() - 1);
-
- // If last character is S, remove it.
- if (lastChar == 'S') {
- key.deleteCharAt(key.length() - 1);
- lastChar = key.charAt(key.length() - 1);
- }
-
- if (key.length() > 2) {
- final char last2Char = key.charAt(key.length() - 2);
- // If last characters are AY, replace with Y.
- if (last2Char == 'A' && lastChar == 'Y') {
- key.deleteCharAt(key.length() - 2);
- }
- }
-
- // If last character is A, remove it.
- if (lastChar == 'A') {
- key.deleteCharAt(key.length() - 1);
- }
- }
-
- final String string = key.toString();
- return this.isStrict() ? string.substring(0, Math.min(TRUE_LENGTH, string.length())) : string;
- }
-}
diff --git a/src/org/apache/commons/codec/language/RefinedSoundex.java b/src/org/apache/commons/codec/language/RefinedSoundex.java
deleted file mode 100644
index e0157879..00000000
--- a/src/org/apache/commons/codec/language/RefinedSoundex.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Encodes a string into a Refined Soundex value. A refined soundex code is
- * optimized for spell checking words. Soundex method originally developed by
- * Margaret Odell and Robert Russell .
- *
- *
This class is immutable and thread-safe.
- *
- * @version $Id$
- */
-public class RefinedSoundex implements StringEncoder {
-
- /**
- * @since 1.4
- */
- public static final String US_ENGLISH_MAPPING_STRING = "01360240043788015936020505";
-
- /**
- * RefinedSoundex is *refined* for a number of reasons one being that the
- * mappings have been altered. This implementation contains default
- * mappings for US English.
- */
- private static final char[] US_ENGLISH_MAPPING = US_ENGLISH_MAPPING_STRING.toCharArray();
-
- /**
- * Every letter of the alphabet is "mapped" to a numerical value. This char
- * array holds the values to which each letter is mapped. This
- * implementation contains a default map for US_ENGLISH
- */
- private final char[] soundexMapping;
-
- /**
- * This static variable contains an instance of the RefinedSoundex using
- * the US_ENGLISH mapping.
- */
- public static final RefinedSoundex US_ENGLISH = new RefinedSoundex();
-
- /**
- * Creates an instance of the RefinedSoundex object using the default US
- * English mapping.
- */
- public RefinedSoundex() {
- this.soundexMapping = US_ENGLISH_MAPPING;
- }
-
- /**
- * Creates a refined soundex instance using a custom mapping. This
- * constructor can be used to customize the mapping, and/or possibly
- * provide an internationalized mapping for a non-Western character set.
- *
- * @param mapping Mapping array to use when finding the corresponding code for
- * a given character
- */
- public RefinedSoundex(final char[] mapping) {
- this.soundexMapping = new char[mapping.length];
- System.arraycopy(mapping, 0, this.soundexMapping, 0, mapping.length);
- }
-
- /**
- * Creates a refined Soundex instance using a custom mapping. This constructor can be used to customize the mapping,
- * and/or possibly provide an internationalized mapping for a non-Western character set.
- *
- * @param mapping Mapping string to use when finding the corresponding code for a given character
- * @since 1.4
- */
- public RefinedSoundex(final String mapping) {
- this.soundexMapping = mapping.toCharArray();
- }
-
- /**
- * Returns the number of characters in the two encoded Strings that are the
- * same. This return value ranges from 0 to the length of the shortest
- * encoded String: 0 indicates little or no similarity, and 4 out of 4 (for
- * example) indicates strong similarity or identical values. For refined
- * Soundex, the return value can be greater than 4.
- *
- * @param s1 A String that will be encoded and compared.
- * @param s2 A String that will be encoded and compared.
- * @return The number of characters in the two encoded Strings that are the
- * same from 0 to to the length of the shortest encoded String.
- * @throws EncoderException if an error occurs encoding one of the strings
- * @see SoundexUtils#difference(StringEncoder, String, String)
- * @see
- * MS T-SQL DIFFERENCE
- * @since 1.3
- */
- public int difference(final String s1, final String s2) throws EncoderException {
- return SoundexUtils.difference(this, s1, s2);
- }
-
- /**
- * Encodes an Object using the refined soundex algorithm. This method is
- * provided in order to satisfy the requirements of the Encoder interface,
- * and will throw an EncoderException if the supplied object is not of type
- * java.lang.String.
- *
- * @param obj Object to encode
- * @return An object (or type java.lang.String) containing the refined
- * soundex code which corresponds to the String supplied.
- * @throws EncoderException if the parameter supplied is not of type java.lang.String
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (!(obj instanceof String)) {
- throw new EncoderException("Parameter supplied to RefinedSoundex encode is not of type java.lang.String");
- }
- return soundex((String) obj);
- }
-
- /**
- * Encodes a String using the refined soundex algorithm.
- *
- * @param str A String object to encode
- * @return A Soundex code corresponding to the String supplied
- */
- @Override
- public String encode(final String str) {
- return soundex(str);
- }
-
- /**
- * Returns the mapping code for a given character. The mapping codes are
- * maintained in an internal char array named soundexMapping, and the
- * default values of these mappings are US English.
- *
- * @param c char to get mapping for
- * @return A character (really a numeral) to return for the given char
- */
- char getMappingCode(final char c) {
- if (!Character.isLetter(c)) {
- return 0;
- }
- return this.soundexMapping[Character.toUpperCase(c) - 'A'];
- }
-
- /**
- * Retrieves the Refined Soundex code for a given String object.
- *
- * @param str String to encode using the Refined Soundex algorithm
- * @return A soundex code for the String supplied
- */
- public String soundex(String str) {
- if (str == null) {
- return null;
- }
- str = SoundexUtils.clean(str);
- if (str.length() == 0) {
- return str;
- }
-
- final StringBuilder sBuf = new StringBuilder();
- sBuf.append(str.charAt(0));
-
- char last, current;
- last = '*';
-
- for (int i = 0; i < str.length(); i++) {
-
- current = getMappingCode(str.charAt(i));
- if (current == last) {
- continue;
- } else if (current != 0) {
- sBuf.append(current);
- }
-
- last = current;
-
- }
-
- return sBuf.toString();
- }
-}
diff --git a/src/org/apache/commons/codec/language/Soundex.java b/src/org/apache/commons/codec/language/Soundex.java
deleted file mode 100644
index d99d6c23..00000000
--- a/src/org/apache/commons/codec/language/Soundex.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Encodes a string into a Soundex value. Soundex is an encoding used to relate similar names, but can also be used as a
- * general purpose scheme to find word with similar phonemes.
- *
- * This class is thread-safe.
- * Although not strictly immutable, the {@link #maxLength} field is not actually used.
- *
- * @version $Id$
- */
-public class Soundex implements StringEncoder {
-
- /**
- * This is a default mapping of the 26 letters used in US English. A value of 0
for a letter position
- * means do not encode.
- *
- * (This constant is provided as both an implementation convenience and to allow Javadoc to pick
- * up the value for the constant values page.)
- *
- *
- * @see #US_ENGLISH_MAPPING
- */
- public static final String US_ENGLISH_MAPPING_STRING = "0123012#02245501262301#202";
-
- /**
- * This is a default mapping of the 26 letters used in US English. A value of 0
for a letter position
- * means do not encode.
- *
- * @see Soundex#Soundex(char[])
- */
- private static final char[] US_ENGLISH_MAPPING = US_ENGLISH_MAPPING_STRING.toCharArray();
-
- /**
- * An instance of Soundex using the US_ENGLISH_MAPPING mapping.
- *
- * @see #US_ENGLISH_MAPPING
- */
- public static final Soundex US_ENGLISH = new Soundex();
-
- /**
- * The maximum length of a Soundex code - Soundex codes are only four characters by definition.
- *
- * @deprecated This feature is not needed since the encoding size must be constant. Will be removed in 2.0.
- */
- @Deprecated
- private int maxLength = 4;
-
- /**
- * Every letter of the alphabet is "mapped" to a numerical value. This char array holds the values to which each
- * letter is mapped. This implementation contains a default map for US_ENGLISH
- */
- private final char[] soundexMapping;
-
- /**
- * Creates an instance using US_ENGLISH_MAPPING
- *
- * @see Soundex#Soundex(char[])
- * @see Soundex#US_ENGLISH_MAPPING
- */
- public Soundex() {
- this.soundexMapping = US_ENGLISH_MAPPING;
- }
-
- /**
- * Creates a soundex instance using the given mapping. This constructor can be used to provide an internationalized
- * mapping for a non-Western character set.
- *
- * Every letter of the alphabet is "mapped" to a numerical value. This char array holds the values to which each
- * letter is mapped. This implementation contains a default map for US_ENGLISH
- *
- * @param mapping Mapping array to use when finding the corresponding code for a given character
- */
- public Soundex(final char[] mapping) {
- this.soundexMapping = new char[mapping.length];
- System.arraycopy(mapping, 0, this.soundexMapping, 0, mapping.length);
- }
-
- /**
- * Creates a refined soundex instance using a custom mapping. This constructor can be used to customize the mapping,
- * and/or possibly provide an internationalized mapping for a non-Western character set.
- *
- * @param mapping Mapping string to use when finding the corresponding code for a given character
- * @since 1.4
- */
- public Soundex(final String mapping) {
- this.soundexMapping = mapping.toCharArray();
- }
-
- /**
- * Encodes the Strings and returns the number of characters in the two encoded Strings that are the same. This
- * return value ranges from 0 through 4: 0 indicates little or no similarity, and 4 indicates strong similarity or
- * identical values.
- *
- * @param s1 A String that will be encoded and compared.
- * @param s2 A String that will be encoded and compared.
- * @return The number of characters in the two encoded Strings that are the same from 0 to 4.
- * @throws EncoderException if an error occurs encoding one of the strings
- * @see SoundexUtils#difference(StringEncoder, String, String)
- * @see MS
- * T-SQL DIFFERENCE
- * @since 1.3
- */
- public int difference(final String s1, final String s2) throws EncoderException {
- return SoundexUtils.difference(this, s1, s2);
- }
-
- /**
- * Encodes an Object using the soundex algorithm. This method is provided in order to satisfy the requirements of
- * the Encoder interface, and will throw an EncoderException if the supplied object is not of type java.lang.String.
- *
- * @param obj Object to encode
- * @return An object (or type java.lang.String) containing the soundex code which corresponds to the String
- * supplied.
- * @throws EncoderException if the parameter supplied is not of type java.lang.String
- * @throws IllegalArgumentException if a character is not mapped
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (!(obj instanceof String)) {
- throw new EncoderException("Parameter supplied to Soundex encode is not of type java.lang.String");
- }
- return soundex((String) obj);
- }
-
- /**
- * Encodes a String using the soundex algorithm.
- *
- * @param str A String object to encode
- * @return A Soundex code corresponding to the String supplied
- * @throws IllegalArgumentException if a character is not mapped
- */
- @Override
- public String encode(final String str) {
- return soundex(str);
- }
-
- /**
- * Returns the maxLength. Standard Soundex
- *
- * @return int
- * @deprecated This feature is not needed since the encoding size must be constant. Will be removed in 2.0.
- */
- @Deprecated
- public int getMaxLength() {
- return this.maxLength;
- }
-
- /**
- * Returns the soundex mapping.
- *
- * @return soundexMapping.
- */
- private char[] getSoundexMapping() {
- return this.soundexMapping;
- }
-
- /**
- * Maps the given upper-case character to its Soundex code.
- *
- * @param ch An upper-case character.
- * @return A Soundex code.
- * @throws IllegalArgumentException Thrown if ch
is not mapped.
- */
- private char map(final char ch) {
- final int index = ch - 'A';
- if (index < 0 || index >= this.getSoundexMapping().length) {
- throw new IllegalArgumentException("The character is not mapped: " + ch);
- }
- return this.getSoundexMapping()[index];
- }
-
- /**
- * Sets the maxLength.
- *
- * @param maxLength The maxLength to set
- * @deprecated This feature is not needed since the encoding size must be constant. Will be removed in 2.0.
- */
- @Deprecated
- public void setMaxLength(final int maxLength) {
- this.maxLength = maxLength;
- }
-
- /**
- * Retrieves the Soundex code for a given String object.
- *
- * @param str String to encode using the Soundex algorithm
- * @return A soundex code for the String supplied
- * @throws IllegalArgumentException if a character is not mapped
- */
- public String soundex(String str) {
- if (str == null) {
- return null;
- }
- str = SoundexUtils.clean(str);
- if (str.length() == 0) {
- return str;
- }
- final char out[] = {'0', '0', '0', '0'};
- char last, mapped;
- int incount = 1, count = 1;
- out[0] = str.charAt(0);
- // map() throws IllegalArgumentException
- last = this.map(str.charAt(0));
- while (incount < str.length() && count < out.length) {
- mapped = this.map(str.charAt(incount++));
- if (mapped == '0') {
- last = mapped;
- } else if (mapped != '#' && mapped != last) {
- out[count++] = mapped;
- last = mapped;
- }
- }
- return new String(out);
- }
-}
diff --git a/src/org/apache/commons/codec/language/SoundexUtils.java b/src/org/apache/commons/codec/language/SoundexUtils.java
deleted file mode 100644
index 9487efe7..00000000
--- a/src/org/apache/commons/codec/language/SoundexUtils.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Utility methods for {@link Soundex} and {@link RefinedSoundex} classes.
- *
- *
This class is immutable and thread-safe.
- *
- * @version $Id$
- * @since 1.3
- */
-final class SoundexUtils {
-
- /**
- * Cleans up the input string before Soundex processing by only returning
- * upper case letters.
- *
- * @param str The String to clean.
- * @return A clean String.
- */
- static String clean(final String str) {
- if (str == null || str.length() == 0) {
- return str;
- }
- final int len = str.length();
- final char[] chars = new char[len];
- int count = 0;
- for (int i = 0; i < len; i++) {
- if (Character.isLetter(str.charAt(i))) {
- chars[count++] = str.charAt(i);
- }
- }
- if (count == len) {
- return str.toUpperCase(java.util.Locale.ENGLISH);
- }
- return new String(chars, 0, count).toUpperCase(java.util.Locale.ENGLISH);
- }
-
- /**
- * Encodes the Strings and returns the number of characters in the two
- * encoded Strings that are the same.
- *
- * For Soundex, this return value ranges from 0 through 4: 0 indicates
- * little or no similarity, and 4 indicates strong similarity or identical
- * values.
- * For refined Soundex, the return value can be greater than 4.
- *
- *
- * @param encoder The encoder to use to encode the Strings.
- * @param s1 A String that will be encoded and compared.
- * @param s2 A String that will be encoded and compared.
- * @return The number of characters in the two Soundex encoded Strings that
- * are the same.
- * @throws EncoderException if an error occurs encoding one of the strings
- * @see #differenceEncoded(String, String)
- * @see
- * MS T-SQL DIFFERENCE
- */
- static int difference(final StringEncoder encoder, final String s1, final String s2) throws EncoderException {
- return differenceEncoded(encoder.encode(s1), encoder.encode(s2));
- }
-
- /**
- * Returns the number of characters in the two Soundex encoded Strings that
- * are the same.
- *
- * For Soundex, this return value ranges from 0 through 4: 0 indicates
- * little or no similarity, and 4 indicates strong similarity or identical
- * values.
- * For refined Soundex, the return value can be greater than 4.
- *
- *
- * @param es1 An encoded String.
- * @param es2 An encoded String.
- * @return The number of characters in the two Soundex encoded Strings that
- * are the same.
- * @see
- * MS T-SQL DIFFERENCE
- */
- static int differenceEncoded(final String es1, final String es2) {
-
- if (es1 == null || es2 == null) {
- return 0;
- }
- final int lengthToMatch = Math.min(es1.length(), es2.length());
- int diff = 0;
- for (int i = 0; i < lengthToMatch; i++) {
- if (es1.charAt(i) == es2.charAt(i)) {
- diff++;
- }
- }
- return diff;
- }
-}
diff --git a/src/org/apache/commons/codec/language/bm/BeiderMorseEncoder.java b/src/org/apache/commons/codec/language/bm/BeiderMorseEncoder.java
deleted file mode 100644
index 19418484..00000000
--- a/src/org/apache/commons/codec/language/bm/BeiderMorseEncoder.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language.bm;
-
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Encodes strings into their Beider-Morse phonetic encoding.
- *
- * Beider-Morse phonetic encodings are optimised for family names. However, they may be useful for a wide range of
- * words.
- *
- * This encoder is intentionally mutable to allow dynamic configuration through bean properties. As such, it is mutable,
- * and may not be thread-safe. If you require a guaranteed thread-safe encoding then use {@link PhoneticEngine}
- * directly.
- *
- * Encoding overview
- *
- * Beider-Morse phonetic encodings is a multi-step process. Firstly, a table of rules is consulted to guess what
- * language the word comes from. For example, if it ends in "ault
" then it infers that the word is French.
- * Next, the word is translated into a phonetic representation using a language-specific phonetics table. Some runs of
- * letters can be pronounced in multiple ways, and a single run of letters may be potentially broken up into phonemes at
- * different places, so this stage results in a set of possible language-specific phonetic representations. Lastly, this
- * language-specific phonetic representation is processed by a table of rules that re-writes it phonetically taking into
- * account systematic pronunciation differences between languages, to move it towards a pan-indo-european phonetic
- * representation. Again, sometimes there are multiple ways this could be done and sometimes things that can be
- * pronounced in several ways in the source language have only one way to represent them in this average phonetic
- * language, so the result is again a set of phonetic spellings.
- *
- * Some names are treated as having multiple parts. This can be due to two things. Firstly, they may be hyphenated. In
- * this case, each individual hyphenated word is encoded, and then these are combined end-to-end for the final encoding.
- * Secondly, some names have standard prefixes, for example, "Mac/Mc
" in Scottish (English) names. As
- * sometimes it is ambiguous whether the prefix is intended or is an accident of the spelling, the word is encoded once
- * with the prefix and once without it. The resulting encoding contains one and then the other result.
- *
- * Encoding format
- *
- * Individual phonetic spellings of an input word are represented in upper- and lower-case roman characters. Where there
- * are multiple possible phonetic representations, these are joined with a pipe (|
) character. If multiple
- * hyphenated words where found, or if the word may contain a name prefix, each encoded word is placed in elipses and
- * these blocks are then joined with hyphens. For example, "d'ortley
" has a possible prefix. The form
- * without prefix encodes to "ortlaj|ortlej
", while the form with prefix encodes to "
- * dortlaj|dortlej
". Thus, the full, combined encoding is "(ortlaj|ortlej)-(dortlaj|dortlej)
".
- *
- * The encoded forms are often quite a bit longer than the input strings. This is because a single input may have many
- * potential phonetic interpretations. For example, "Renault
" encodes to "
- * rYnDlt|rYnalt|rYnult|rinDlt|rinalt|rinult
". The APPROX
rules will tend to produce larger
- * encodings as they consider a wider range of possible, approximate phonetic interpretations of the original word.
- * Down-stream applications may wish to further process the encoding for indexing or lookup purposes, for example, by
- * splitting on pipe (|
) and indexing under each of these alternatives.
- *
- * Note : this version of the Beider-Morse encoding is equivalent with v3.4 of the reference implementation.
- *
- * @version $Id$
- * @see Beider-Morse Phonetic Matching
- * @see Reference implementation
- * @since 1.6
- */
-public class BeiderMorseEncoder implements StringEncoder {
- // Implementation note: This class is a spring-friendly facade to PhoneticEngine. It allows read/write configuration
- // of an immutable PhoneticEngine instance that will be delegated to for the actual encoding.
-
- // a cached object
- private PhoneticEngine engine = new PhoneticEngine(NameType.GENERIC, RuleType.APPROX, true);
-
- @Override
- public Object encode(final Object source) throws EncoderException {
- if (!(source instanceof String)) {
- throw new EncoderException("BeiderMorseEncoder encode parameter is not of type String");
- }
- return encode((String) source);
- }
-
- @Override
- public String encode(final String source) throws EncoderException {
- if (source == null) {
- return null;
- }
- return this.engine.encode(source);
- }
-
- /**
- * Gets the name type currently in operation.
- *
- * @return the NameType currently being used
- */
- public NameType getNameType() {
- return this.engine.getNameType();
- }
-
- /**
- * Gets the rule type currently in operation.
- *
- * @return the RuleType currently being used
- */
- public RuleType getRuleType() {
- return this.engine.getRuleType();
- }
-
- /**
- * Discovers if multiple possible encodings are concatenated.
- *
- * @return true if multiple encodings are concatenated, false if just the first one is returned
- */
- public boolean isConcat() {
- return this.engine.isConcat();
- }
-
- /**
- * Sets how multiple possible phonetic encodings are combined.
- *
- * @param concat true if multiple encodings are to be combined with a '|', false if just the first one is
- * to be considered
- */
- public void setConcat(final boolean concat) {
- this.engine = new PhoneticEngine(this.engine.getNameType(),
- this.engine.getRuleType(),
- concat,
- this.engine.getMaxPhonemes());
- }
-
- /**
- * Sets the type of name. Use {@link NameType#GENERIC} unless you specifically want phonetic encodings
- * optimized for Ashkenazi or Sephardic Jewish family names.
- *
- * @param nameType the NameType in use
- */
- public void setNameType(final NameType nameType) {
- this.engine = new PhoneticEngine(nameType,
- this.engine.getRuleType(),
- this.engine.isConcat(),
- this.engine.getMaxPhonemes());
- }
-
- /**
- * Sets the rule type to apply. This will widen or narrow the range of phonetic encodings considered.
- *
- * @param ruleType {@link RuleType#APPROX} or {@link RuleType#EXACT} for approximate or exact phonetic matches
- */
- public void setRuleType(final RuleType ruleType) {
- this.engine = new PhoneticEngine(this.engine.getNameType(),
- ruleType,
- this.engine.isConcat(),
- this.engine.getMaxPhonemes());
- }
-
- /**
- * Sets the number of maximum of phonemes that shall be considered by the engine.
- *
- * @param maxPhonemes the maximum number of phonemes returned by the engine
- * @since 1.7
- */
- public void setMaxPhonemes(final int maxPhonemes) {
- this.engine = new PhoneticEngine(this.engine.getNameType(),
- this.engine.getRuleType(),
- this.engine.isConcat(),
- maxPhonemes);
- }
-}
diff --git a/src/org/apache/commons/codec/language/bm/Lang.java b/src/org/apache/commons/codec/language/bm/Lang.java
deleted file mode 100644
index e9ca514a..00000000
--- a/src/org/apache/commons/codec/language/bm/Lang.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language.bm;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Scanner;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-/**
- * Language guessing utility.
- *
- * This class encapsulates rules used to guess the possible languages that a word originates from. This is
- * done by reference to a whole series of rules distributed in resource files.
- *
- * Instances of this class are typically managed through the static factory method instance().
- * Unless you are developing your own language guessing rules, you will not need to interact with this class directly.
- *
- * This class is intended to be immutable and thread-safe.
- *
- * Lang resources
- *
- * Language guessing rules are typically loaded from resource files. These are UTF-8 encoded text files.
- * They are systematically named following the pattern:
- *
org/apache/commons/codec/language/bm/lang.txt
- * The format of these resources is the following:
- *
- * Rules: whitespace separated strings.
- * There should be 3 columns to each row, and these will be interpreted as:
- *
- * pattern: a regular expression.
- * languages: a '+'-separated list of languages.
- * acceptOnMatch: 'true' or 'false' indicating if a match rules in or rules out the language.
- *
- *
- * End-of-line comments: Any occurrence of '//' will cause all text following on that line to be
- * discarded as a comment.
- * Multi-line comments: Any line starting with '/*' will start multi-line commenting mode.
- * This will skip all content until a line ending in '*' and '/' is found.
- * Blank lines: All blank lines will be skipped.
- *
- *
- * Port of lang.php
- *
- * @version $Id$
- * @since 1.6
- */
-public class Lang {
- // Implementation note: This class is divided into two sections. The first part is a static factory interface that
- // exposes the LANGUAGE_RULES_RN resource as a Lang instance. The second part is the Lang instance methods that
- // encapsulate a particular language-guessing rule table and the language guessing itself.
- //
- // It may make sense in the future to expose the private constructor to allow power users to build custom language-
- // guessing rules, perhaps by marking it protected and allowing sub-classing. However, the vast majority of users
- // should be strongly encouraged to use the static factory instance
method to get their Lang instances.
-
- private static final class LangRule {
- private final boolean acceptOnMatch;
- private final Set languages;
- private final Pattern pattern;
-
- private LangRule(final Pattern pattern, final Set languages, final boolean acceptOnMatch) {
- this.pattern = pattern;
- this.languages = languages;
- this.acceptOnMatch = acceptOnMatch;
- }
-
- public boolean matches(final String txt) {
- return this.pattern.matcher(txt).find();
- }
- }
-
- private static final Map Langs = new EnumMap(NameType.class);
-
- private static final String LANGUAGE_RULES_RN = "org/apache/commons/codec/language/bm/%s_lang.txt";
-
- static {
- for (final NameType s : NameType.values()) {
- Langs.put(s, loadFromResource(String.format(LANGUAGE_RULES_RN, s.getName()), Languages.getInstance(s)));
- }
- }
-
- /**
- * Gets a Lang instance for one of the supported NameTypes.
- *
- * @param nameType the NameType to look up
- * @return a Lang encapsulating the language guessing rules for that name type
- */
- public static Lang instance(final NameType nameType) {
- return Langs.get(nameType);
- }
-
- /**
- * Loads language rules from a resource.
- *
- * In normal use, you will obtain instances of Lang through the {@link #instance(NameType)} method.
- * You will only need to call this yourself if you are developing custom language mapping rules.
- *
- * @param languageRulesResourceName the fully-qualified resource name to load
- * @param languages the languages that these rules will support
- * @return a Lang encapsulating the loaded language-guessing rules.
- */
- public static Lang loadFromResource(final String languageRulesResourceName, final Languages languages) {
- final List rules = new ArrayList();
- final InputStream lRulesIS = Lang.class.getClassLoader().getResourceAsStream(languageRulesResourceName);
-
- if (lRulesIS == null) {
- throw new IllegalStateException("Unable to resolve required resource:" + LANGUAGE_RULES_RN);
- }
-
- final Scanner scanner = new Scanner(lRulesIS, ResourceConstants.ENCODING);
- try {
- boolean inExtendedComment = false;
- while (scanner.hasNextLine()) {
- final String rawLine = scanner.nextLine();
- String line = rawLine;
- if (inExtendedComment) {
- // check for closing comment marker, otherwise discard doc comment line
- if (line.endsWith(ResourceConstants.EXT_CMT_END)) {
- inExtendedComment = false;
- }
- } else {
- if (line.startsWith(ResourceConstants.EXT_CMT_START)) {
- inExtendedComment = true;
- } else {
- // discard comments
- final int cmtI = line.indexOf(ResourceConstants.CMT);
- if (cmtI >= 0) {
- line = line.substring(0, cmtI);
- }
-
- // trim leading-trailing whitespace
- line = line.trim();
-
- if (line.length() == 0) {
- continue; // empty lines can be safely skipped
- }
-
- // split it up
- final String[] parts = line.split("\\s+");
-
- if (parts.length != 3) {
- throw new IllegalArgumentException("Malformed line '" + rawLine +
- "' in language resource '" + languageRulesResourceName + "'");
- }
-
- final Pattern pattern = Pattern.compile(parts[0]);
- final String[] langs = parts[1].split("\\+");
- final boolean accept = parts[2].equals("true");
-
- rules.add(new LangRule(pattern, new HashSet(Arrays.asList(langs)), accept));
- }
- }
- }
- } finally {
- scanner.close();
- }
- return new Lang(rules, languages);
- }
-
- private final Languages languages;
- private final List rules;
-
- private Lang(final List rules, final Languages languages) {
- this.rules = Collections.unmodifiableList(rules);
- this.languages = languages;
- }
-
- /**
- * Guesses the language of a word.
- *
- * @param text the word
- * @return the language that the word originates from or {@link Languages#ANY} if there was no unique match
- */
- public String guessLanguage(final String text) {
- final Languages.LanguageSet ls = guessLanguages(text);
- return ls.isSingleton() ? ls.getAny() : Languages.ANY;
- }
-
- /**
- * Guesses the languages of a word.
- *
- * @param input the word
- * @return a Set of Strings of language names that are potential matches for the input word
- */
- public Languages.LanguageSet guessLanguages(final String input) {
- final String text = input.toLowerCase(Locale.ENGLISH);
-
- final Set langs = new HashSet(this.languages.getLanguages());
- for (final LangRule rule : this.rules) {
- if (rule.matches(text)) {
- if (rule.acceptOnMatch) {
- langs.retainAll(rule.languages);
- } else {
- langs.removeAll(rule.languages);
- }
- }
- }
-
- final Languages.LanguageSet ls = Languages.LanguageSet.from(langs);
- return ls.equals(Languages.NO_LANGUAGES) ? Languages.ANY_LANGUAGE : ls;
- }
-}
diff --git a/src/org/apache/commons/codec/language/bm/Languages.java b/src/org/apache/commons/codec/language/bm/Languages.java
deleted file mode 100644
index 3d9666c2..00000000
--- a/src/org/apache/commons/codec/language/bm/Languages.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language.bm;
-
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Scanner;
-import java.util.Set;
-
-/**
- * Language codes.
- *
- * Language codes are typically loaded from resource files. These are UTF-8 encoded text files. They are
- * systematically named following the pattern:
- *
org/apache/commons/codec/language/bm/${{@link NameType#getName()} languages.txt
- *
- * The format of these resources is the following:
- *
- * Language: a single string containing no whitespace
- * End-of-line comments: Any occurrence of '//' will cause all text following on that line to be
- * discarded as a comment.
- * Multi-line comments: Any line starting with '/*' will start multi-line commenting mode.
- * This will skip all content until a line ending in '*' and '/' is found.
- * Blank lines: All blank lines will be skipped.
- *
- *
- * Ported from language.php
- *
- * This class is immutable and thread-safe.
- *
- * @version $Id$
- * @since 1.6
- */
-public class Languages {
- // Implementation note: This class is divided into two sections. The first part is a static factory interface that
- // exposes org/apache/commons/codec/language/bm/%s_languages.txt for %s in NameType.* as a list of supported
- // languages, and a second part that provides instance methods for accessing this set for supported languages.
-
- /**
- * A set of languages.
- */
- public static abstract class LanguageSet {
-
- public static LanguageSet from(final Set langs) {
- return langs.isEmpty() ? NO_LANGUAGES : new SomeLanguages(langs);
- }
-
- public abstract boolean contains(String language);
-
- public abstract String getAny();
-
- public abstract boolean isEmpty();
-
- public abstract boolean isSingleton();
-
- public abstract LanguageSet restrictTo(LanguageSet other);
-
- abstract LanguageSet merge(LanguageSet other);
- }
-
- /**
- * Some languages, explicitly enumerated.
- */
- public static final class SomeLanguages extends LanguageSet {
- private final Set languages;
-
- private SomeLanguages(final Set languages) {
- this.languages = Collections.unmodifiableSet(languages);
- }
-
- @Override
- public boolean contains(final String language) {
- return this.languages.contains(language);
- }
-
- @Override
- public String getAny() {
- return this.languages.iterator().next();
- }
-
- public Set getLanguages() {
- return this.languages;
- }
-
- @Override
- public boolean isEmpty() {
- return this.languages.isEmpty();
- }
-
- @Override
- public boolean isSingleton() {
- return this.languages.size() == 1;
- }
-
- @Override
- public LanguageSet restrictTo(final LanguageSet other) {
- if (other == NO_LANGUAGES) {
- return other;
- } else if (other == ANY_LANGUAGE) {
- return this;
- } else {
- final SomeLanguages sl = (SomeLanguages) other;
- final Set ls = new HashSet(Math.min(languages.size(), sl.languages.size()));
- for (String lang : languages) {
- if (sl.languages.contains(lang)) {
- ls.add(lang);
- }
- }
- return from(ls);
- }
- }
-
- @Override
- public LanguageSet merge(final LanguageSet other) {
- if (other == NO_LANGUAGES) {
- return this;
- } else if (other == ANY_LANGUAGE) {
- return other;
- } else {
- final SomeLanguages sl = (SomeLanguages) other;
- final Set ls = new HashSet(languages);
- for (String lang : sl.languages) {
- ls.add(lang);
- }
- return from(ls);
- }
- }
-
- @Override
- public String toString() {
- return "Languages(" + languages.toString() + ")";
- }
-
- }
-
- public static final String ANY = "any";
-
- private static final Map LANGUAGES = new EnumMap(NameType.class);
-
- static {
- for (final NameType s : NameType.values()) {
- LANGUAGES.put(s, getInstance(langResourceName(s)));
- }
- }
-
- public static Languages getInstance(final NameType nameType) {
- return LANGUAGES.get(nameType);
- }
-
- public static Languages getInstance(final String languagesResourceName) {
- // read languages list
- final Set ls = new HashSet();
- final InputStream langIS = Languages.class.getClassLoader().getResourceAsStream(languagesResourceName);
-
- if (langIS == null) {
- throw new IllegalArgumentException("Unable to resolve required resource: " + languagesResourceName);
- }
-
- final Scanner lsScanner = new Scanner(langIS, ResourceConstants.ENCODING);
- try {
- boolean inExtendedComment = false;
- while (lsScanner.hasNextLine()) {
- final String line = lsScanner.nextLine().trim();
- if (inExtendedComment) {
- if (line.endsWith(ResourceConstants.EXT_CMT_END)) {
- inExtendedComment = false;
- }
- } else {
- if (line.startsWith(ResourceConstants.EXT_CMT_START)) {
- inExtendedComment = true;
- } else if (line.length() > 0) {
- ls.add(line);
- }
- }
- }
- } finally {
- lsScanner.close();
- }
-
- return new Languages(Collections.unmodifiableSet(ls));
- }
-
- private static String langResourceName(final NameType nameType) {
- return String.format("org/apache/commons/codec/language/bm/%s_languages.txt", nameType.getName());
- }
-
- private final Set languages;
-
- /**
- * No languages at all.
- */
- public static final LanguageSet NO_LANGUAGES = new LanguageSet() {
- @Override
- public boolean contains(final String language) {
- return false;
- }
-
- @Override
- public String getAny() {
- throw new NoSuchElementException("Can't fetch any language from the empty language set.");
- }
-
- @Override
- public boolean isEmpty() {
- return true;
- }
-
- @Override
- public boolean isSingleton() {
- return false;
- }
-
- @Override
- public LanguageSet restrictTo(final LanguageSet other) {
- return this;
- }
-
- @Override
- public LanguageSet merge(final LanguageSet other) {
- return other;
- }
-
- @Override
- public String toString() {
- return "NO_LANGUAGES";
- }
- };
-
- /**
- * Any/all languages.
- */
- public static final LanguageSet ANY_LANGUAGE = new LanguageSet() {
- @Override
- public boolean contains(final String language) {
- return true;
- }
-
- @Override
- public String getAny() {
- throw new NoSuchElementException("Can't fetch any language from the any language set.");
- }
-
- @Override
- public boolean isEmpty() {
- return false;
- }
-
- @Override
- public boolean isSingleton() {
- return false;
- }
-
- @Override
- public LanguageSet restrictTo(final LanguageSet other) {
- return other;
- }
-
- @Override
- public LanguageSet merge(final LanguageSet other) {
- return other;
- }
-
- @Override
- public String toString() {
- return "ANY_LANGUAGE";
- }
- };
-
- private Languages(final Set languages) {
- this.languages = languages;
- }
-
- public Set getLanguages() {
- return this.languages;
- }
-}
diff --git a/src/org/apache/commons/codec/language/bm/NameType.java b/src/org/apache/commons/codec/language/bm/NameType.java
deleted file mode 100644
index cefee17c..00000000
--- a/src/org/apache/commons/codec/language/bm/NameType.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language.bm;
-
-/**
- * Supported types of names. Unless you are matching particular family names, use {@link #GENERIC}. The
- * GENERIC
NameType should work reasonably well for non-name words. The other encodings are
- * specifically tuned to family names, and may not work well at all for general text.
- *
- * @version $Id$
- * @since 1.6
- */
-public enum NameType {
-
- /**
- * Ashkenazi family names
- */
- ASHKENAZI("ash"),
-
- /**
- * Generic names and words
- */
- GENERIC("gen"),
-
- /**
- * Sephardic family names
- */
- SEPHARDIC("sep");
-
- private final String name;
-
- NameType(final String name) {
- this.name = name;
- }
-
- /**
- * Gets the short version of the name type.
- *
- * @return the NameType short string
- */
- public String getName() {
- return this.name;
- }
-}
diff --git a/src/org/apache/commons/codec/language/bm/PhoneticEngine.java b/src/org/apache/commons/codec/language/bm/PhoneticEngine.java
deleted file mode 100644
index 2726369f..00000000
--- a/src/org/apache/commons/codec/language/bm/PhoneticEngine.java
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language.bm;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-import org.apache.commons.codec.language.bm.Languages.LanguageSet;
-import org.apache.commons.codec.language.bm.Rule.Phoneme;
-
-/**
- * Converts words into potential phonetic representations.
- *
- * This is a two-stage process. Firstly, the word is converted into a phonetic representation that takes
- * into account the likely source language. Next, this phonetic representation is converted into a
- * pan-European 'average' representation, allowing comparison between different versions of essentially
- * the same word from different languages.
- *
- * This class is intentionally immutable and thread-safe.
- * If you wish to alter the settings for a PhoneticEngine, you
- * must make a new one with the updated settings.
- *
- * Ported from phoneticengine.php
- *
- * @version $Id$
- * @since 1.6
- */
-public class PhoneticEngine {
-
- /**
- * Utility for manipulating a set of phonemes as they are being built up. Not intended for use outside
- * this package, and probably not outside the {@link PhoneticEngine} class.
- *
- * @since 1.6
- */
- static final class PhonemeBuilder {
-
- /**
- * An empty builder where all phonemes must come from some set of languages. This will contain a single
- * phoneme of zero characters. This can then be appended to. This should be the only way to create a new
- * phoneme from scratch.
- *
- * @param languages the set of languages
- * @return a new, empty phoneme builder
- */
- public static PhonemeBuilder empty(final Languages.LanguageSet languages) {
- return new PhonemeBuilder(new Rule.Phoneme("", languages));
- }
-
- private final Set phonemes;
-
- private PhonemeBuilder(final Rule.Phoneme phoneme) {
- this.phonemes = new LinkedHashSet();
- this.phonemes.add(phoneme);
- }
-
- private PhonemeBuilder(final Set phonemes) {
- this.phonemes = phonemes;
- }
-
- /**
- * Creates a new phoneme builder containing all phonemes in this one extended by str
.
- *
- * @param str the characters to append to the phonemes
- */
- public void append(final CharSequence str) {
- for (final Rule.Phoneme ph : this.phonemes) {
- ph.append(str);
- }
- }
-
- /**
- * Applies the given phoneme expression to all phonemes in this phoneme builder.
- *
- * This will lengthen phonemes that have compatible language sets to the expression, and drop those that are
- * incompatible.
- *
- * @param phonemeExpr the expression to apply
- * @param maxPhonemes the maximum number of phonemes to build up
- */
- public void apply(final Rule.PhonemeExpr phonemeExpr, final int maxPhonemes) {
- final Set newPhonemes = new LinkedHashSet(maxPhonemes);
-
- EXPR:
- for (final Rule.Phoneme left : this.phonemes) {
- for (final Rule.Phoneme right : phonemeExpr.getPhonemes()) {
- final LanguageSet languages = left.getLanguages().restrictTo(right.getLanguages());
- if (!languages.isEmpty()) {
- final Rule.Phoneme join = new Phoneme(left, right, languages);
- if (newPhonemes.size() < maxPhonemes) {
- newPhonemes.add(join);
- if (newPhonemes.size() >= maxPhonemes) {
- break EXPR;
- }
- }
- }
- }
- }
-
- this.phonemes.clear();
- this.phonemes.addAll(newPhonemes);
- }
-
- /**
- * Gets underlying phoneme set. Please don't mutate.
- *
- * @return the phoneme set
- */
- public Set getPhonemes() {
- return this.phonemes;
- }
-
- /**
- * Stringifies the phoneme set. This produces a single string of the strings of each phoneme,
- * joined with a pipe. This is explicitly provided in place of toString as it is a potentially
- * expensive operation, which should be avoided when debugging.
- *
- * @return the stringified phoneme set
- */
- public String makeString() {
- final StringBuilder sb = new StringBuilder();
-
- for (final Rule.Phoneme ph : this.phonemes) {
- if (sb.length() > 0) {
- sb.append("|");
- }
- sb.append(ph.getPhonemeText());
- }
-
- return sb.toString();
- }
- }
-
- /**
- * A function closure capturing the application of a list of rules to an input sequence at a particular offset.
- * After invocation, the values i
and found
are updated. i
points to the
- * index of the next char in input
that must be processed next (the input up to that index having been
- * processed already), and found
indicates if a matching rule was found or not. In the case where a
- * matching rule was found, phonemeBuilder
is replaced with a new builder containing the phonemes
- * updated by the matching rule.
- *
- * Although this class is not thread-safe (it has mutable unprotected fields), it is not shared between threads
- * as it is constructed as needed by the calling methods.
- *
- * @since 1.6
- */
- private static final class RulesApplication {
- private final Map> finalRules;
- private final CharSequence input;
-
- private PhonemeBuilder phonemeBuilder;
- private int i;
- private final int maxPhonemes;
- private boolean found;
-
- public RulesApplication(final Map> finalRules, final CharSequence input,
- final PhonemeBuilder phonemeBuilder, final int i, final int maxPhonemes) {
- if (finalRules == null) {
- throw new NullPointerException("The finalRules argument must not be null");
- }
- this.finalRules = finalRules;
- this.phonemeBuilder = phonemeBuilder;
- this.input = input;
- this.i = i;
- this.maxPhonemes = maxPhonemes;
- }
-
- public int getI() {
- return this.i;
- }
-
- public PhonemeBuilder getPhonemeBuilder() {
- return this.phonemeBuilder;
- }
-
- /**
- * Invokes the rules. Loops over the rules list, stopping at the first one that has a matching context
- * and pattern. Then applies this rule to the phoneme builder to produce updated phonemes. If there was no
- * match, i
is advanced one and the character is silently dropped from the phonetic spelling.
- *
- * @return this
- */
- public RulesApplication invoke() {
- this.found = false;
- int patternLength = 1;
- final List rules = this.finalRules.get(input.subSequence(i, i + patternLength));
- if (rules != null) {
- for (final Rule rule : rules) {
- final String pattern = rule.getPattern();
- patternLength = pattern.length();
- if (rule.patternAndContextMatches(this.input, this.i)) {
- this.phonemeBuilder.apply(rule.getPhoneme(), maxPhonemes);
- this.found = true;
- break;
- }
- }
- }
-
- if (!this.found) {
- patternLength = 1;
- }
-
- this.i += patternLength;
- return this;
- }
-
- public boolean isFound() {
- return this.found;
- }
- }
-
- private static final Map> NAME_PREFIXES = new EnumMap>(NameType.class);
-
- static {
- NAME_PREFIXES.put(NameType.ASHKENAZI,
- Collections.unmodifiableSet(
- new HashSet(Arrays.asList("bar", "ben", "da", "de", "van", "von"))));
- NAME_PREFIXES.put(NameType.SEPHARDIC,
- Collections.unmodifiableSet(
- new HashSet(Arrays.asList("al", "el", "da", "dal", "de", "del", "dela", "de la",
- "della", "des", "di", "do", "dos", "du", "van", "von"))));
- NAME_PREFIXES.put(NameType.GENERIC,
- Collections.unmodifiableSet(
- new HashSet(Arrays.asList("da", "dal", "de", "del", "dela", "de la", "della",
- "des", "di", "do", "dos", "du", "van", "von"))));
- }
-
- /**
- * Joins some strings with an internal separator.
- *
- * @param strings Strings to join
- * @param sep String to separate them with
- * @return a single String consisting of each element of strings
interleaved by sep
- */
- private static String join(final Iterable strings, final String sep) {
- final StringBuilder sb = new StringBuilder();
- final Iterator si = strings.iterator();
- if (si.hasNext()) {
- sb.append(si.next());
- }
- while (si.hasNext()) {
- sb.append(sep).append(si.next());
- }
-
- return sb.toString();
- }
-
- private static final int DEFAULT_MAX_PHONEMES = 20;
-
- private final Lang lang;
-
- private final NameType nameType;
-
- private final RuleType ruleType;
-
- private final boolean concat;
-
- private final int maxPhonemes;
-
- /**
- * Generates a new, fully-configured phonetic engine.
- *
- * @param nameType the type of names it will use
- * @param ruleType the type of rules it will apply
- * @param concat if it will concatenate multiple encodings
- */
- public PhoneticEngine(final NameType nameType, final RuleType ruleType, final boolean concat) {
- this(nameType, ruleType, concat, DEFAULT_MAX_PHONEMES);
- }
-
- /**
- * Generates a new, fully-configured phonetic engine.
- *
- * @param nameType the type of names it will use
- * @param ruleType the type of rules it will apply
- * @param concat if it will concatenate multiple encodings
- * @param maxPhonemes the maximum number of phonemes that will be handled
- * @since 1.7
- */
- public PhoneticEngine(final NameType nameType, final RuleType ruleType, final boolean concat,
- final int maxPhonemes) {
- if (ruleType == RuleType.RULES) {
- throw new IllegalArgumentException("ruleType must not be " + RuleType.RULES);
- }
- this.nameType = nameType;
- this.ruleType = ruleType;
- this.concat = concat;
- this.lang = Lang.instance(nameType);
- this.maxPhonemes = maxPhonemes;
- }
-
- /**
- * Applies the final rules to convert from a language-specific phonetic representation to a
- * language-independent representation.
- *
- * @param phonemeBuilder the current phonemes
- * @param finalRules the final rules to apply
- * @return the resulting phonemes
- */
- private PhonemeBuilder applyFinalRules(final PhonemeBuilder phonemeBuilder,
- final Map> finalRules) {
- if (finalRules == null) {
- throw new NullPointerException("finalRules can not be null");
- }
- if (finalRules.isEmpty()) {
- return phonemeBuilder;
- }
-
- final Map phonemes =
- new TreeMap(Rule.Phoneme.COMPARATOR);
-
- for (final Rule.Phoneme phoneme : phonemeBuilder.getPhonemes()) {
- PhonemeBuilder subBuilder = PhonemeBuilder.empty(phoneme.getLanguages());
- final String phonemeText = phoneme.getPhonemeText().toString();
-
- for (int i = 0; i < phonemeText.length(); ) {
- final RulesApplication rulesApplication =
- new RulesApplication(finalRules, phonemeText, subBuilder, i, maxPhonemes).invoke();
- final boolean found = rulesApplication.isFound();
- subBuilder = rulesApplication.getPhonemeBuilder();
-
- if (!found) {
- // not found, appending as-is
- subBuilder.append(phonemeText.subSequence(i, i + 1));
- }
-
- i = rulesApplication.getI();
- }
-
- // the phonemes map orders the phonemes only based on their text, but ignores the language set
- // when adding new phonemes, check for equal phonemes and merge their language set, otherwise
- // phonemes with the same text but different language set get lost
- for (final Rule.Phoneme newPhoneme : subBuilder.getPhonemes()) {
- if (phonemes.containsKey(newPhoneme)) {
- final Rule.Phoneme oldPhoneme = phonemes.remove(newPhoneme);
- final Rule.Phoneme mergedPhoneme = oldPhoneme.mergeWithLanguage(newPhoneme.getLanguages());
- phonemes.put(mergedPhoneme, mergedPhoneme);
- } else {
- phonemes.put(newPhoneme, newPhoneme);
- }
- }
- }
-
- return new PhonemeBuilder(phonemes.keySet());
- }
-
- /**
- * Encodes a string to its phonetic representation.
- *
- * @param input the String to encode
- * @return the encoding of the input
- */
- public String encode(final String input) {
- final Languages.LanguageSet languageSet = this.lang.guessLanguages(input);
- return encode(input, languageSet);
- }
-
- /**
- * Encodes an input string into an output phonetic representation, given a set of possible origin languages.
- *
- * @param input String to phoneticise; a String with dashes or spaces separating each word
- * @param languageSet set of possible origin languages
- * @return a phonetic representation of the input; a String containing '-'-separated phonetic representations of the
- * input
- */
- public String encode(String input, final Languages.LanguageSet languageSet) {
- final Map> rules = Rule.getInstanceMap(this.nameType, RuleType.RULES, languageSet);
- // rules common across many (all) languages
- final Map> finalRules1 = Rule.getInstanceMap(this.nameType, this.ruleType, "common");
- // rules that apply to a specific language that may be ambiguous or wrong if applied to other languages
- final Map> finalRules2 = Rule.getInstanceMap(this.nameType, this.ruleType, languageSet);
-
- // tidy the input
- // lower case is a locale-dependent operation
- input = input.toLowerCase(Locale.ENGLISH).replace('-', ' ').trim();
-
- if (this.nameType == NameType.GENERIC) {
- if (input.length() >= 2 && input.substring(0, 2).equals("d'")) { // check for d'
- final String remainder = input.substring(2);
- final String combined = "d" + remainder;
- return "(" + encode(remainder) + ")-(" + encode(combined) + ")";
- }
- for (final String l : NAME_PREFIXES.get(this.nameType)) {
- // handle generic prefixes
- if (input.startsWith(l + " ")) {
- // check for any prefix in the words list
- final String remainder = input.substring(l.length() + 1); // input without the prefix
- final String combined = l + remainder; // input with prefix without space
- return "(" + encode(remainder) + ")-(" + encode(combined) + ")";
- }
- }
- }
-
- final List words = Arrays.asList(input.split("\\s+"));
- final List words2 = new ArrayList();
-
- // special-case handling of word prefixes based upon the name type
- switch (this.nameType) {
- case SEPHARDIC:
- for (final String aWord : words) {
- final String[] parts = aWord.split("'");
- final String lastPart = parts[parts.length - 1];
- words2.add(lastPart);
- }
- words2.removeAll(NAME_PREFIXES.get(this.nameType));
- break;
- case ASHKENAZI:
- words2.addAll(words);
- words2.removeAll(NAME_PREFIXES.get(this.nameType));
- break;
- case GENERIC:
- words2.addAll(words);
- break;
- default:
- throw new IllegalStateException("Unreachable case: " + this.nameType);
- }
-
- if (this.concat) {
- // concat mode enabled
- input = join(words2, " ");
- } else if (words2.size() == 1) {
- // not a multi-word name
- input = words.iterator().next();
- } else {
- // encode each word in a multi-word name separately (normally used for approx matches)
- final StringBuilder result = new StringBuilder();
- for (final String word : words2) {
- result.append("-").append(encode(word));
- }
- // return the result without the leading "-"
- return result.substring(1);
- }
-
- PhonemeBuilder phonemeBuilder = PhonemeBuilder.empty(languageSet);
-
- // loop over each char in the input - we will handle the increment manually
- for (int i = 0; i < input.length(); ) {
- final RulesApplication rulesApplication =
- new RulesApplication(rules, input, phonemeBuilder, i, maxPhonemes).invoke();
- i = rulesApplication.getI();
- phonemeBuilder = rulesApplication.getPhonemeBuilder();
- }
-
- // Apply the general rules
- phonemeBuilder = applyFinalRules(phonemeBuilder, finalRules1);
- // Apply the language-specific rules
- phonemeBuilder = applyFinalRules(phonemeBuilder, finalRules2);
-
- return phonemeBuilder.makeString();
- }
-
- /**
- * Gets the Lang language guessing rules being used.
- *
- * @return the Lang in use
- */
- public Lang getLang() {
- return this.lang;
- }
-
- /**
- * Gets the NameType being used.
- *
- * @return the NameType in use
- */
- public NameType getNameType() {
- return this.nameType;
- }
-
- /**
- * Gets the RuleType being used.
- *
- * @return the RuleType in use
- */
- public RuleType getRuleType() {
- return this.ruleType;
- }
-
- /**
- * Gets if multiple phonetic encodings are concatenated or if just the first one is kept.
- *
- * @return true if multiple phonetic encodings are returned, false if just the first is
- */
- public boolean isConcat() {
- return this.concat;
- }
-
- /**
- * Gets the maximum number of phonemes the engine will calculate for a given input.
- *
- * @return the maximum number of phonemes
- * @since 1.7
- */
- public int getMaxPhonemes() {
- return this.maxPhonemes;
- }
-}
diff --git a/src/org/apache/commons/codec/language/bm/ResourceConstants.java b/src/org/apache/commons/codec/language/bm/ResourceConstants.java
deleted file mode 100644
index f8600cc7..00000000
--- a/src/org/apache/commons/codec/language/bm/ResourceConstants.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language.bm;
-
-import org.apache.commons.codec.CharEncoding;
-
-/**
- * Constants used to process resource files.
- *
- *
This class is immutable and thread-safe.
- *
- * @version $Id$
- * @since 1.6
- */
-class ResourceConstants {
-
- static final String CMT = "//";
- static final String ENCODING = CharEncoding.UTF_8;
- static final String EXT_CMT_END = "*/";
- static final String EXT_CMT_START = "/*";
-}
diff --git a/src/org/apache/commons/codec/language/bm/Rule.java b/src/org/apache/commons/codec/language/bm/Rule.java
deleted file mode 100644
index a10d0df7..00000000
--- a/src/org/apache/commons/codec/language/bm/Rule.java
+++ /dev/null
@@ -1,701 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language.bm;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Scanner;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.commons.codec.language.bm.Languages.LanguageSet;
-
-/**
- * A phoneme rule.
- *
- * Rules have a pattern, left context, right context, output phoneme, set of languages for which they apply
- * and a logical flag indicating if all languages must be in play. A rule matches if:
- *
- * the pattern matches at the current position
- * the string up until the beginning of the pattern matches the left context
- * the string from the end of the pattern matches the right context
- * logical is ALL and all languages are in scope; or
- * logical is any other value and at least one language is in scope
- *
- *
- * Rules are typically generated by parsing rules resources. In normal use, there will be no need for the user
- * to explicitly construct their own.
- *
- * Rules are immutable and thread-safe.
- *
- * Rules resources
- *
- * Rules are typically loaded from resource files. These are UTF-8 encoded text files. They are systematically
- * named following the pattern:
- *
org/apache/commons/codec/language/bm/${NameType#getName}_${RuleType#getName}_${language}.txt
- *
- * The format of these resources is the following:
- *
- * Rules: whitespace separated, double-quoted strings. There should be 4 columns to each row, and these
- * will be interpreted as:
- *
- * pattern
- * left context
- * right context
- * phoneme
- *
- *
- * End-of-line comments: Any occurrence of '//' will cause all text following on that line to be discarded
- * as a comment.
- * Multi-line comments: Any line starting with '/*' will start multi-line commenting mode. This will skip
- * all content until a line ending in '*' and '/' is found.
- * Blank lines: All blank lines will be skipped.
- *
- *
- * @version $Id$
- * @since 1.6
- */
-public class Rule {
-
- public static final class Phoneme implements PhonemeExpr {
- public static final Comparator COMPARATOR = new Comparator() {
- @Override
- public int compare(final Phoneme o1, final Phoneme o2) {
- for (int i = 0; i < o1.phonemeText.length(); i++) {
- if (i >= o2.phonemeText.length()) {
- return +1;
- }
- final int c = o1.phonemeText.charAt(i) - o2.phonemeText.charAt(i);
- if (c != 0) {
- return c;
- }
- }
-
- if (o1.phonemeText.length() < o2.phonemeText.length()) {
- return -1;
- }
-
- return 0;
- }
- };
-
- private final StringBuilder phonemeText;
- private final Languages.LanguageSet languages;
-
- public Phoneme(final CharSequence phonemeText, final Languages.LanguageSet languages) {
- this.phonemeText = new StringBuilder(phonemeText);
- this.languages = languages;
- }
-
- public Phoneme(final Phoneme phonemeLeft, final Phoneme phonemeRight) {
- this(phonemeLeft.phonemeText, phonemeLeft.languages);
- this.phonemeText.append(phonemeRight.phonemeText);
- }
-
- public Phoneme(final Phoneme phonemeLeft, final Phoneme phonemeRight, final Languages.LanguageSet languages) {
- this(phonemeLeft.phonemeText, languages);
- this.phonemeText.append(phonemeRight.phonemeText);
- }
-
- public Phoneme append(final CharSequence str) {
- this.phonemeText.append(str);
- return this;
- }
-
- public Languages.LanguageSet getLanguages() {
- return this.languages;
- }
-
- @Override
- public Iterable getPhonemes() {
- return Collections.singleton(this);
- }
-
- public CharSequence getPhonemeText() {
- return this.phonemeText;
- }
-
- /**
- * Deprecated since 1.9.
- *
- * @param right the Phoneme to join
- * @return a new Phoneme
- * @deprecated since 1.9
- */
- @Deprecated
- public Phoneme join(final Phoneme right) {
- return new Phoneme(this.phonemeText.toString() + right.phonemeText.toString(),
- this.languages.restrictTo(right.languages));
- }
-
- /**
- * Returns a new Phoneme with the same text but a union of its
- * current language set and the given one.
- *
- * @param lang the language set to merge
- * @return a new Phoneme
- */
- public Phoneme mergeWithLanguage(final LanguageSet lang) {
- return new Phoneme(this.phonemeText.toString(), this.languages.merge(lang));
- }
-
- @Override
- public String toString() {
- return phonemeText.toString() + "[" + languages + "]";
- }
- }
-
- public interface PhonemeExpr {
- Iterable getPhonemes();
- }
-
- public static final class PhonemeList implements PhonemeExpr {
- private final List phonemes;
-
- public PhonemeList(final List phonemes) {
- this.phonemes = phonemes;
- }
-
- @Override
- public List getPhonemes() {
- return this.phonemes;
- }
- }
-
- /**
- * A minimal wrapper around the functionality of Pattern that we use, to allow for alternate implementations.
- */
- public interface RPattern {
- boolean isMatch(CharSequence input);
- }
-
- public static final RPattern ALL_STRINGS_RMATCHER = new RPattern() {
- @Override
- public boolean isMatch(final CharSequence input) {
- return true;
- }
- };
-
- public static final String ALL = "ALL";
-
- private static final String DOUBLE_QUOTE = "\"";
-
- private static final String HASH_INCLUDE = "#include";
-
- private static final Map>>>> RULES =
- new EnumMap>>>>(NameType.class);
-
- static {
- for (final NameType s : NameType.values()) {
- final Map>>> rts =
- new EnumMap>>>(RuleType.class);
-
- for (final RuleType rt : RuleType.values()) {
- final Map>> rs = new HashMap>>();
-
- final Languages ls = Languages.getInstance(s);
- for (final String l : ls.getLanguages()) {
- try {
- rs.put(l, parseRules(createScanner(s, rt, l), createResourceName(s, rt, l)));
- } catch (final IllegalStateException e) {
- throw new IllegalStateException("Problem processing " + createResourceName(s, rt, l), e);
- }
- }
- if (!rt.equals(RuleType.RULES)) {
- rs.put("common", parseRules(createScanner(s, rt, "common"), createResourceName(s, rt, "common")));
- }
-
- rts.put(rt, Collections.unmodifiableMap(rs));
- }
-
- RULES.put(s, Collections.unmodifiableMap(rts));
- }
- }
-
- private static boolean contains(final CharSequence chars, final char input) {
- for (int i = 0; i < chars.length(); i++) {
- if (chars.charAt(i) == input) {
- return true;
- }
- }
- return false;
- }
-
- private static String createResourceName(final NameType nameType, final RuleType rt, final String lang) {
- return String.format("org/apache/commons/codec/language/bm/%s_%s_%s.txt",
- nameType.getName(), rt.getName(), lang);
- }
-
- private static Scanner createScanner(final NameType nameType, final RuleType rt, final String lang) {
- final String resName = createResourceName(nameType, rt, lang);
- final InputStream rulesIS = Languages.class.getClassLoader().getResourceAsStream(resName);
-
- if (rulesIS == null) {
- throw new IllegalArgumentException("Unable to load resource: " + resName);
- }
-
- return new Scanner(rulesIS, ResourceConstants.ENCODING);
- }
-
- private static Scanner createScanner(final String lang) {
- final String resName = String.format("org/apache/commons/codec/language/bm/%s.txt", lang);
- final InputStream rulesIS = Languages.class.getClassLoader().getResourceAsStream(resName);
-
- if (rulesIS == null) {
- throw new IllegalArgumentException("Unable to load resource: " + resName);
- }
-
- return new Scanner(rulesIS, ResourceConstants.ENCODING);
- }
-
- private static boolean endsWith(final CharSequence input, final CharSequence suffix) {
- if (suffix.length() > input.length()) {
- return false;
- }
- for (int i = input.length() - 1, j = suffix.length() - 1; j >= 0; i--, j--) {
- if (input.charAt(i) != suffix.charAt(j)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Gets rules for a combination of name type, rule type and languages.
- *
- * @param nameType the NameType to consider
- * @param rt the RuleType to consider
- * @param langs the set of languages to consider
- * @return a list of Rules that apply
- */
- public static List getInstance(final NameType nameType, final RuleType rt,
- final Languages.LanguageSet langs) {
- final Map> ruleMap = getInstanceMap(nameType, rt, langs);
- final List allRules = new ArrayList();
- for (final List rules : ruleMap.values()) {
- allRules.addAll(rules);
- }
- return allRules;
- }
-
- /**
- * Gets rules for a combination of name type, rule type and a single language.
- *
- * @param nameType the NameType to consider
- * @param rt the RuleType to consider
- * @param lang the language to consider
- * @return a list of Rules that apply
- */
- public static List getInstance(final NameType nameType, final RuleType rt, final String lang) {
- return getInstance(nameType, rt, LanguageSet.from(new HashSet(Arrays.asList(lang))));
- }
-
- /**
- * Gets rules for a combination of name type, rule type and languages.
- *
- * @param nameType the NameType to consider
- * @param rt the RuleType to consider
- * @param langs the set of languages to consider
- * @return a map containing all Rules that apply, grouped by the first character of the rule pattern
- * @since 1.9
- */
- public static Map> getInstanceMap(final NameType nameType, final RuleType rt,
- final Languages.LanguageSet langs) {
- return langs.isSingleton() ? getInstanceMap(nameType, rt, langs.getAny()) :
- getInstanceMap(nameType, rt, Languages.ANY);
- }
-
- /**
- * Gets rules for a combination of name type, rule type and a single language.
- *
- * @param nameType the NameType to consider
- * @param rt the RuleType to consider
- * @param lang the language to consider
- * @return a map containing all Rules that apply, grouped by the first character of the rule pattern
- * @since 1.9
- */
- public static Map> getInstanceMap(final NameType nameType, final RuleType rt,
- final String lang) {
- final Map> rules = RULES.get(nameType).get(rt).get(lang);
-
- if (rules == null) {
- throw new IllegalArgumentException(String.format("No rules found for %s, %s, %s.",
- nameType.getName(), rt.getName(), lang));
- }
-
- return rules;
- }
-
- private static Phoneme parsePhoneme(final String ph) {
- final int open = ph.indexOf("[");
- if (open >= 0) {
- if (!ph.endsWith("]")) {
- throw new IllegalArgumentException("Phoneme expression contains a '[' but does not end in ']'");
- }
- final String before = ph.substring(0, open);
- final String in = ph.substring(open + 1, ph.length() - 1);
- final Set langs = new HashSet(Arrays.asList(in.split("[+]")));
-
- return new Phoneme(before, Languages.LanguageSet.from(langs));
- } else {
- return new Phoneme(ph, Languages.ANY_LANGUAGE);
- }
- }
-
- private static PhonemeExpr parsePhonemeExpr(final String ph) {
- if (ph.startsWith("(")) { // we have a bracketed list of options
- if (!ph.endsWith(")")) {
- throw new IllegalArgumentException("Phoneme starts with '(' so must end with ')'");
- }
-
- final List phs = new ArrayList();
- final String body = ph.substring(1, ph.length() - 1);
- for (final String part : body.split("[|]")) {
- phs.add(parsePhoneme(part));
- }
- if (body.startsWith("|") || body.endsWith("|")) {
- phs.add(new Phoneme("", Languages.ANY_LANGUAGE));
- }
-
- return new PhonemeList(phs);
- } else {
- return parsePhoneme(ph);
- }
- }
-
- private static Map> parseRules(final Scanner scanner, final String location) {
- final Map> lines = new HashMap>();
- int currentLine = 0;
-
- boolean inMultilineComment = false;
- while (scanner.hasNextLine()) {
- currentLine++;
- final String rawLine = scanner.nextLine();
- String line = rawLine;
-
- if (inMultilineComment) {
- if (line.endsWith(ResourceConstants.EXT_CMT_END)) {
- inMultilineComment = false;
- }
- } else {
- if (line.startsWith(ResourceConstants.EXT_CMT_START)) {
- inMultilineComment = true;
- } else {
- // discard comments
- final int cmtI = line.indexOf(ResourceConstants.CMT);
- if (cmtI >= 0) {
- line = line.substring(0, cmtI);
- }
-
- // trim leading-trailing whitespace
- line = line.trim();
-
- if (line.length() == 0) {
- continue; // empty lines can be safely skipped
- }
-
- if (line.startsWith(HASH_INCLUDE)) {
- // include statement
- final String incl = line.substring(HASH_INCLUDE.length()).trim();
- if (incl.contains(" ")) {
- throw new IllegalArgumentException("Malformed import statement '" + rawLine + "' in " +
- location);
- } else {
- lines.putAll(parseRules(createScanner(incl), location + "->" + incl));
- }
- } else {
- // rule
- final String[] parts = line.split("\\s+");
- if (parts.length != 4) {
- throw new IllegalArgumentException("Malformed rule statement split into " + parts.length +
- " parts: " + rawLine + " in " + location);
- } else {
- try {
- final String pat = stripQuotes(parts[0]);
- final String lCon = stripQuotes(parts[1]);
- final String rCon = stripQuotes(parts[2]);
- final PhonemeExpr ph = parsePhonemeExpr(stripQuotes(parts[3]));
- final int cLine = currentLine;
- final Rule r = new Rule(pat, lCon, rCon, ph) {
- private final int myLine = cLine;
- private final String loc = location;
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append("Rule");
- sb.append("{line=").append(myLine);
- sb.append(", loc='").append(loc).append('\'');
- sb.append(", pat='").append(pat).append('\'');
- sb.append(", lcon='").append(lCon).append('\'');
- sb.append(", rcon='").append(rCon).append('\'');
- sb.append('}');
- return sb.toString();
- }
- };
- final String patternKey = r.pattern.substring(0, 1);
- List rules = lines.get(patternKey);
- if (rules == null) {
- rules = new ArrayList();
- lines.put(patternKey, rules);
- }
- rules.add(r);
- } catch (final IllegalArgumentException e) {
- throw new IllegalStateException("Problem parsing line '" + currentLine + "' in " +
- location, e);
- }
- }
- }
- }
- }
- }
-
- return lines;
- }
-
- /**
- * Attempts to compile the regex into direct string ops, falling back to Pattern and Matcher in the worst case.
- *
- * @param regex the regular expression to compile
- * @return an RPattern that will match this regex
- */
- private static RPattern pattern(final String regex) {
- final boolean startsWith = regex.startsWith("^");
- final boolean endsWith = regex.endsWith("$");
- final String content = regex.substring(startsWith ? 1 : 0, endsWith ? regex.length() - 1 : regex.length());
- final boolean boxes = content.contains("[");
-
- if (!boxes) {
- if (startsWith && endsWith) {
- // exact match
- if (content.length() == 0) {
- // empty
- return new RPattern() {
- @Override
- public boolean isMatch(final CharSequence input) {
- return input.length() == 0;
- }
- };
- } else {
- return new RPattern() {
- @Override
- public boolean isMatch(final CharSequence input) {
- return input.equals(content);
- }
- };
- }
- } else if ((startsWith || endsWith) && content.length() == 0) {
- // matches every string
- return ALL_STRINGS_RMATCHER;
- } else if (startsWith) {
- // matches from start
- return new RPattern() {
- @Override
- public boolean isMatch(final CharSequence input) {
- return startsWith(input, content);
- }
- };
- } else if (endsWith) {
- // matches from start
- return new RPattern() {
- @Override
- public boolean isMatch(final CharSequence input) {
- return endsWith(input, content);
- }
- };
- }
- } else {
- final boolean startsWithBox = content.startsWith("[");
- final boolean endsWithBox = content.endsWith("]");
-
- if (startsWithBox && endsWithBox) {
- String boxContent = content.substring(1, content.length() - 1);
- if (!boxContent.contains("[")) {
- // box containing alternatives
- final boolean negate = boxContent.startsWith("^");
- if (negate) {
- boxContent = boxContent.substring(1);
- }
- final String bContent = boxContent;
- final boolean shouldMatch = !negate;
-
- if (startsWith && endsWith) {
- // exact match
- return new RPattern() {
- @Override
- public boolean isMatch(final CharSequence input) {
- return input.length() == 1 && contains(bContent, input.charAt(0)) == shouldMatch;
- }
- };
- } else if (startsWith) {
- // first char
- return new RPattern() {
- @Override
- public boolean isMatch(final CharSequence input) {
- return input.length() > 0 && contains(bContent, input.charAt(0)) == shouldMatch;
- }
- };
- } else if (endsWith) {
- // last char
- return new RPattern() {
- @Override
- public boolean isMatch(final CharSequence input) {
- return input.length() > 0 &&
- contains(bContent, input.charAt(input.length() - 1)) == shouldMatch;
- }
- };
- }
- }
- }
- }
-
- return new RPattern() {
- Pattern pattern = Pattern.compile(regex);
-
- @Override
- public boolean isMatch(final CharSequence input) {
- final Matcher matcher = pattern.matcher(input);
- return matcher.find();
- }
- };
- }
-
- private static boolean startsWith(final CharSequence input, final CharSequence prefix) {
- if (prefix.length() > input.length()) {
- return false;
- }
- for (int i = 0; i < prefix.length(); i++) {
- if (input.charAt(i) != prefix.charAt(i)) {
- return false;
- }
- }
- return true;
- }
-
- private static String stripQuotes(String str) {
- if (str.startsWith(DOUBLE_QUOTE)) {
- str = str.substring(1);
- }
-
- if (str.endsWith(DOUBLE_QUOTE)) {
- str = str.substring(0, str.length() - 1);
- }
-
- return str;
- }
-
- private final RPattern lContext;
-
- private final String pattern;
-
- private final PhonemeExpr phoneme;
-
- private final RPattern rContext;
-
- /**
- * Creates a new rule.
- *
- * @param pattern the pattern
- * @param lContext the left context
- * @param rContext the right context
- * @param phoneme the resulting phoneme
- */
- public Rule(final String pattern, final String lContext, final String rContext, final PhonemeExpr phoneme) {
- this.pattern = pattern;
- this.lContext = pattern(lContext + "$");
- this.rContext = pattern("^" + rContext);
- this.phoneme = phoneme;
- }
-
- /**
- * Gets the left context. This is a regular expression that must match to the left of the pattern.
- *
- * @return the left context Pattern
- */
- public RPattern getLContext() {
- return this.lContext;
- }
-
- /**
- * Gets the pattern. This is a string-literal that must exactly match.
- *
- * @return the pattern
- */
- public String getPattern() {
- return this.pattern;
- }
-
- /**
- * Gets the phoneme. If the rule matches, this is the phoneme associated with the pattern match.
- *
- * @return the phoneme
- */
- public PhonemeExpr getPhoneme() {
- return this.phoneme;
- }
-
- /**
- * Gets the right context. This is a regular expression that must match to the right of the pattern.
- *
- * @return the right context Pattern
- */
- public RPattern getRContext() {
- return this.rContext;
- }
-
- /**
- * Decides if the pattern and context match the input starting at a position. It is a match if the
- * lContext
matches input
up to i
, pattern
matches at i and
- * rContext
matches from the end of the match of pattern
to the end of input
.
- *
- * @param input the input String
- * @param i the int position within the input
- * @return true if the pattern and left/right context match, false otherwise
- */
- public boolean patternAndContextMatches(final CharSequence input, final int i) {
- if (i < 0) {
- throw new IndexOutOfBoundsException("Can not match pattern at negative indexes");
- }
-
- final int patternLength = this.pattern.length();
- final int ipl = i + patternLength;
-
- if (ipl > input.length()) {
- // not enough room for the pattern to match
- return false;
- }
-
- // evaluate the pattern, left context and right context
- // fail early if any of the evaluations is not successful
- if (!input.subSequence(i, ipl).equals(this.pattern)) {
- return false;
- } else if (!this.rContext.isMatch(input.subSequence(ipl, input.length()))) {
- return false;
- }
- return this.lContext.isMatch(input.subSequence(0, i));
- }
-}
diff --git a/src/org/apache/commons/codec/language/bm/RuleType.java b/src/org/apache/commons/codec/language/bm/RuleType.java
deleted file mode 100644
index 9b923fcd..00000000
--- a/src/org/apache/commons/codec/language/bm/RuleType.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.language.bm;
-
-/**
- * Types of rule.
- *
- * @version $Id$
- * @since 1.6
- */
-public enum RuleType {
-
- /**
- * Approximate rules, which will lead to the largest number of phonetic interpretations.
- */
- APPROX("approx"),
- /**
- * Exact rules, which will lead to a minimum number of phonetic interpretations.
- */
- EXACT("exact"),
- /**
- * For internal use only. Please use {@link #APPROX} or {@link #EXACT}.
- */
- RULES("rules");
-
- private final String name;
-
- RuleType(final String name) {
- this.name = name;
- }
-
- /**
- * Gets the rule name.
- *
- * @return the rule name.
- */
- public String getName() {
- return this.name;
- }
-}
diff --git a/src/org/apache/commons/codec/language/bm/package.html b/src/org/apache/commons/codec/language/bm/package.html
deleted file mode 100644
index bd8026bd..00000000
--- a/src/org/apache/commons/codec/language/bm/package.html
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-Implementation details of the Beider-Morse codec.
-
-
diff --git a/src/org/apache/commons/codec/language/package.html b/src/org/apache/commons/codec/language/package.html
deleted file mode 100644
index 50f82f37..00000000
--- a/src/org/apache/commons/codec/language/package.html
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-Language and phonetic encoders.
-
-
diff --git a/src/org/apache/commons/codec/net/BCodec.java b/src/org/apache/commons/codec/net/BCodec.java
deleted file mode 100644
index fb36717b..00000000
--- a/src/org/apache/commons/codec/net/BCodec.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.net;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-
-import org.apache.commons.codec.Charsets;
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringDecoder;
-import org.apache.commons.codec.StringEncoder;
-import org.apache.commons.codec.binary.Base64;
-
-/**
- * Identical to the Base64 encoding defined by RFC 1521
- * and allows a character set to be specified.
- *
- * RFC 1522 describes techniques to allow the encoding of non-ASCII
- * text in various portions of a RFC 822 [2] message header, in a manner which is unlikely to confuse existing message
- * handling software.
- *
- * This class is immutable and thread-safe.
- *
- * @version $Id$
- * @see MIME (Multipurpose Internet Mail Extensions) Part Two: Message
- * Header Extensions for Non-ASCII Text
- * @since 1.3
- */
-public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder {
- /**
- * The default charset used for string decoding and encoding.
- */
- private final Charset charset;
-
- /**
- * Default constructor.
- */
- public BCodec() {
- this(Charsets.UTF_8);
- }
-
- /**
- * Constructor which allows for the selection of a default charset
- *
- * @param charset the default string charset to use.
- * @see Standard charsets
- * @since 1.7
- */
- public BCodec(final Charset charset) {
- this.charset = charset;
- }
-
- /**
- * Constructor which allows for the selection of a default charset
- *
- * @param charsetName the default charset to use.
- * @throws java.nio.charset.UnsupportedCharsetException If the named charset is unavailable
- * @see Standard charsets
- * @since 1.7 throws UnsupportedCharsetException if the named charset is unavailable
- */
- public BCodec(final String charsetName) {
- this(Charset.forName(charsetName));
- }
-
- @Override
- protected String getEncoding() {
- return "B";
- }
-
- @Override
- protected byte[] doEncoding(final byte[] bytes) {
- if (bytes == null) {
- return null;
- }
- return Base64.encodeBase64(bytes);
- }
-
- @Override
- protected byte[] doDecoding(final byte[] bytes) {
- if (bytes == null) {
- return null;
- }
- return Base64.decodeBase64(bytes);
- }
-
- /**
- * Encodes a string into its Base64 form using the specified charset. Unsafe characters are escaped.
- *
- * @param value string to convert to Base64 form
- * @param charset the charset for value
- * @return Base64 string
- * @throws EncoderException thrown if a failure condition is encountered during the encoding process.
- * @since 1.7
- */
- public String encode(final String value, final Charset charset) throws EncoderException {
- if (value == null) {
- return null;
- }
- return encodeText(value, charset);
- }
-
- /**
- * Encodes a string into its Base64 form using the specified charset. Unsafe characters are escaped.
- *
- * @param value string to convert to Base64 form
- * @param charset the charset for value
- * @return Base64 string
- * @throws EncoderException thrown if a failure condition is encountered during the encoding process.
- */
- public String encode(final String value, final String charset) throws EncoderException {
- if (value == null) {
- return null;
- }
- try {
- return this.encodeText(value, charset);
- } catch (final UnsupportedEncodingException e) {
- throw new EncoderException(e.getMessage(), e);
- }
- }
-
- /**
- * Encodes a string into its Base64 form using the default charset. Unsafe characters are escaped.
- *
- * @param value string to convert to Base64 form
- * @return Base64 string
- * @throws EncoderException thrown if a failure condition is encountered during the encoding process.
- */
- @Override
- public String encode(final String value) throws EncoderException {
- if (value == null) {
- return null;
- }
- return encode(value, this.getCharset());
- }
-
- /**
- * Decodes a Base64 string into its original form. Escaped characters are converted back to their original
- * representation.
- *
- * @param value Base64 string to convert into its original form
- * @return original string
- * @throws DecoderException A decoder exception is thrown if a failure condition is encountered during the decode process.
- */
- @Override
- public String decode(final String value) throws DecoderException {
- if (value == null) {
- return null;
- }
- try {
- return this.decodeText(value);
- } catch (final UnsupportedEncodingException e) {
- throw new DecoderException(e.getMessage(), e);
- }
- }
-
- /**
- * Encodes an object into its Base64 form using the default charset. Unsafe characters are escaped.
- *
- * @param value object to convert to Base64 form
- * @return Base64 object
- * @throws EncoderException thrown if a failure condition is encountered during the encoding process.
- */
- @Override
- public Object encode(final Object value) throws EncoderException {
- if (value == null) {
- return null;
- } else if (value instanceof String) {
- return encode((String) value);
- } else {
- throw new EncoderException("Objects of type " +
- value.getClass().getName() +
- " cannot be encoded using BCodec");
- }
- }
-
- /**
- * Decodes a Base64 object into its original form. Escaped characters are converted back to their original
- * representation.
- *
- * @param value Base64 object to convert into its original form
- * @return original object
- * @throws DecoderException Thrown if the argument is not a String
. Thrown if a failure condition is encountered
- * during the decode process.
- */
- @Override
- public Object decode(final Object value) throws DecoderException {
- if (value == null) {
- return null;
- } else if (value instanceof String) {
- return decode((String) value);
- } else {
- throw new DecoderException("Objects of type " +
- value.getClass().getName() +
- " cannot be decoded using BCodec");
- }
- }
-
- /**
- * Gets the default charset name used for string decoding and encoding.
- *
- * @return the default charset name
- * @since 1.7
- */
- public Charset getCharset() {
- return this.charset;
- }
-
- /**
- * Gets the default charset name used for string decoding and encoding.
- *
- * @return the default charset name
- */
- public String getDefaultCharset() {
- return this.charset.name();
- }
-}
diff --git a/src/org/apache/commons/codec/net/QCodec.java b/src/org/apache/commons/codec/net/QCodec.java
deleted file mode 100644
index 010553ef..00000000
--- a/src/org/apache/commons/codec/net/QCodec.java
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.net;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.util.BitSet;
-
-import org.apache.commons.codec.Charsets;
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringDecoder;
-import org.apache.commons.codec.StringEncoder;
-
-/**
- * Similar to the Quoted-Printable content-transfer-encoding defined in
- * RFC 1521 and designed to allow text containing mostly ASCII
- * characters to be decipherable on an ASCII terminal without decoding.
- *
- * RFC 1522 describes techniques to allow the encoding of non-ASCII
- * text in various portions of a RFC 822 [2] message header, in a manner which is unlikely to confuse existing message
- * handling software.
- *
- * This class is conditionally thread-safe.
- * The instance field {@link #encodeBlanks} is mutable {@link #setEncodeBlanks(boolean)}
- * but is not volatile, and accesses are not synchronised.
- * If an instance of the class is shared between threads, the caller needs to ensure that suitable synchronisation
- * is used to ensure safe publication of the value between threads, and must not invoke
- * {@link #setEncodeBlanks(boolean)} after initial setup.
- *
- * @version $Id$
- * @see MIME (Multipurpose Internet Mail Extensions) Part Two: Message
- * Header Extensions for Non-ASCII Text
- * @since 1.3
- */
-public class QCodec extends RFC1522Codec implements StringEncoder, StringDecoder {
- /**
- * The default charset used for string decoding and encoding.
- */
- private final Charset charset;
-
- /**
- * BitSet of printable characters as defined in RFC 1522.
- */
- private static final BitSet PRINTABLE_CHARS = new BitSet(256);
-
- // Static initializer for printable chars collection
- static {
- // alpha characters
- PRINTABLE_CHARS.set(' ');
- PRINTABLE_CHARS.set('!');
- PRINTABLE_CHARS.set('"');
- PRINTABLE_CHARS.set('#');
- PRINTABLE_CHARS.set('$');
- PRINTABLE_CHARS.set('%');
- PRINTABLE_CHARS.set('&');
- PRINTABLE_CHARS.set('\'');
- PRINTABLE_CHARS.set('(');
- PRINTABLE_CHARS.set(')');
- PRINTABLE_CHARS.set('*');
- PRINTABLE_CHARS.set('+');
- PRINTABLE_CHARS.set(',');
- PRINTABLE_CHARS.set('-');
- PRINTABLE_CHARS.set('.');
- PRINTABLE_CHARS.set('/');
- for (int i = '0'; i <= '9'; i++) {
- PRINTABLE_CHARS.set(i);
- }
- PRINTABLE_CHARS.set(':');
- PRINTABLE_CHARS.set(';');
- PRINTABLE_CHARS.set('<');
- PRINTABLE_CHARS.set('>');
- PRINTABLE_CHARS.set('@');
- for (int i = 'A'; i <= 'Z'; i++) {
- PRINTABLE_CHARS.set(i);
- }
- PRINTABLE_CHARS.set('[');
- PRINTABLE_CHARS.set('\\');
- PRINTABLE_CHARS.set(']');
- PRINTABLE_CHARS.set('^');
- PRINTABLE_CHARS.set('`');
- for (int i = 'a'; i <= 'z'; i++) {
- PRINTABLE_CHARS.set(i);
- }
- PRINTABLE_CHARS.set('{');
- PRINTABLE_CHARS.set('|');
- PRINTABLE_CHARS.set('}');
- PRINTABLE_CHARS.set('~');
- }
-
- private static final byte BLANK = 32;
-
- private static final byte UNDERSCORE = 95;
-
- private boolean encodeBlanks = false;
-
- /**
- * Default constructor.
- */
- public QCodec() {
- this(Charsets.UTF_8);
- }
-
- /**
- * Constructor which allows for the selection of a default charset.
- *
- * @param charset the default string charset to use.
- * @see Standard charsets
- * @since 1.7
- */
- public QCodec(final Charset charset) {
- super();
- this.charset = charset;
- }
-
- /**
- * Constructor which allows for the selection of a default charset.
- *
- * @param charsetName the charset to use.
- * @throws java.nio.charset.UnsupportedCharsetException If the named charset is unavailable
- * @see Standard charsets
- * @since 1.7 throws UnsupportedCharsetException if the named charset is unavailable
- */
- public QCodec(final String charsetName) {
- this(Charset.forName(charsetName));
- }
-
- @Override
- protected String getEncoding() {
- return "Q";
- }
-
- @Override
- protected byte[] doEncoding(final byte[] bytes) {
- if (bytes == null) {
- return null;
- }
- final byte[] data = QuotedPrintableCodec.encodeQuotedPrintable(PRINTABLE_CHARS, bytes);
- if (this.encodeBlanks) {
- for (int i = 0; i < data.length; i++) {
- if (data[i] == BLANK) {
- data[i] = UNDERSCORE;
- }
- }
- }
- return data;
- }
-
- @Override
- protected byte[] doDecoding(final byte[] bytes) throws DecoderException {
- if (bytes == null) {
- return null;
- }
- boolean hasUnderscores = false;
- for (final byte b : bytes) {
- if (b == UNDERSCORE) {
- hasUnderscores = true;
- break;
- }
- }
- if (hasUnderscores) {
- final byte[] tmp = new byte[bytes.length];
- for (int i = 0; i < bytes.length; i++) {
- final byte b = bytes[i];
- if (b != UNDERSCORE) {
- tmp[i] = b;
- } else {
- tmp[i] = BLANK;
- }
- }
- return QuotedPrintableCodec.decodeQuotedPrintable(tmp);
- }
- return QuotedPrintableCodec.decodeQuotedPrintable(bytes);
- }
-
- /**
- * Encodes a string into its quoted-printable form using the specified charset. Unsafe characters are escaped.
- *
- * @param str string to convert to quoted-printable form
- * @param charset the charset for str
- * @return quoted-printable string
- * @throws EncoderException thrown if a failure condition is encountered during the encoding process.
- * @since 1.7
- */
- public String encode(final String str, final Charset charset) throws EncoderException {
- if (str == null) {
- return null;
- }
- return encodeText(str, charset);
- }
-
- /**
- * Encodes a string into its quoted-printable form using the specified charset. Unsafe characters are escaped.
- *
- * @param str string to convert to quoted-printable form
- * @param charset the charset for str
- * @return quoted-printable string
- * @throws EncoderException thrown if a failure condition is encountered during the encoding process.
- */
- public String encode(final String str, final String charset) throws EncoderException {
- if (str == null) {
- return null;
- }
- try {
- return encodeText(str, charset);
- } catch (final UnsupportedEncodingException e) {
- throw new EncoderException(e.getMessage(), e);
- }
- }
-
- /**
- * Encodes a string into its quoted-printable form using the default charset. Unsafe characters are escaped.
- *
- * @param str string to convert to quoted-printable form
- * @return quoted-printable string
- * @throws EncoderException thrown if a failure condition is encountered during the encoding process.
- */
- @Override
- public String encode(final String str) throws EncoderException {
- if (str == null) {
- return null;
- }
- return encode(str, getCharset());
- }
-
- /**
- * Decodes a quoted-printable string into its original form. Escaped characters are converted back to their original
- * representation.
- *
- * @param str quoted-printable string to convert into its original form
- * @return original string
- * @throws DecoderException A decoder exception is thrown if a failure condition is encountered during the decode process.
- */
- @Override
- public String decode(final String str) throws DecoderException {
- if (str == null) {
- return null;
- }
- try {
- return decodeText(str);
- } catch (final UnsupportedEncodingException e) {
- throw new DecoderException(e.getMessage(), e);
- }
- }
-
- /**
- * Encodes an object into its quoted-printable form using the default charset. Unsafe characters are escaped.
- *
- * @param obj object to convert to quoted-printable form
- * @return quoted-printable object
- * @throws EncoderException thrown if a failure condition is encountered during the encoding process.
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (obj == null) {
- return null;
- } else if (obj instanceof String) {
- return encode((String) obj);
- } else {
- throw new EncoderException("Objects of type " +
- obj.getClass().getName() +
- " cannot be encoded using Q codec");
- }
- }
-
- /**
- * Decodes a quoted-printable object into its original form. Escaped characters are converted back to their original
- * representation.
- *
- * @param obj quoted-printable object to convert into its original form
- * @return original object
- * @throws DecoderException Thrown if the argument is not a String
. Thrown if a failure condition is encountered
- * during the decode process.
- */
- @Override
- public Object decode(final Object obj) throws DecoderException {
- if (obj == null) {
- return null;
- } else if (obj instanceof String) {
- return decode((String) obj);
- } else {
- throw new DecoderException("Objects of type " +
- obj.getClass().getName() +
- " cannot be decoded using Q codec");
- }
- }
-
- /**
- * Gets the default charset name used for string decoding and encoding.
- *
- * @return the default charset name
- * @since 1.7
- */
- public Charset getCharset() {
- return this.charset;
- }
-
- /**
- * Gets the default charset name used for string decoding and encoding.
- *
- * @return the default charset name
- */
- public String getDefaultCharset() {
- return this.charset.name();
- }
-
- /**
- * Tests if optional transformation of SPACE characters is to be used
- *
- * @return true
if SPACE characters are to be transformed, false
otherwise
- */
- public boolean isEncodeBlanks() {
- return this.encodeBlanks;
- }
-
- /**
- * Defines whether optional transformation of SPACE characters is to be used
- *
- * @param b true
if SPACE characters are to be transformed, false
otherwise
- */
- public void setEncodeBlanks(final boolean b) {
- this.encodeBlanks = b;
- }
-}
diff --git a/src/org/apache/commons/codec/net/QuotedPrintableCodec.java b/src/org/apache/commons/codec/net/QuotedPrintableCodec.java
deleted file mode 100644
index 1f9c6b40..00000000
--- a/src/org/apache/commons/codec/net/QuotedPrintableCodec.java
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.net;
-
-import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.BitSet;
-
-import org.apache.commons.codec.BinaryDecoder;
-import org.apache.commons.codec.BinaryEncoder;
-import org.apache.commons.codec.Charsets;
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringDecoder;
-import org.apache.commons.codec.StringEncoder;
-import org.apache.commons.codec.binary.StringUtils;
-
-/**
- * Codec for the Quoted-Printable section of RFC 1521 .
- *
- * The Quoted-Printable encoding is intended to represent data that largely consists of octets that correspond to
- * printable characters in the ASCII character set. It encodes the data in such a way that the resulting octets are
- * unlikely to be modified by mail transport. If the data being encoded are mostly ASCII text, the encoded form of the
- * data remains largely recognizable by humans. A body which is entirely ASCII may also be encoded in Quoted-Printable
- * to ensure the integrity of the data should the message pass through a character- translating, and/or line-wrapping
- * gateway.
- *
- * Note:
- *
- * Depending on the selected {@code strict} parameter, this class will implement a different set of rules of the
- * quoted-printable spec:
- *
- * {@code strict=false}: only rules #1 and #2 are implemented
- * {@code strict=true}: all rules #1 through #5 are implemented
- *
- * Originally, this class only supported the non-strict mode, but the codec in this partial form could already be used
- * for certain applications that do not require quoted-printable line formatting (rules #3, #4, #5), for instance
- * Q codec. The strict mode has been added in 1.10.
- *
- * This class is immutable and thread-safe.
- *
- * @version $Id$
- * @see RFC 1521 MIME (Multipurpose Internet Mail Extensions) Part One:
- * Mechanisms for Specifying and Describing the Format of Internet Message Bodies
- * @since 1.3
- */
-public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, StringDecoder {
- /**
- * The default charset used for string decoding and encoding.
- */
- private final Charset charset;
-
- /**
- * Indicates whether soft line breaks shall be used during encoding (rule #3-5).
- */
- private final boolean strict;
-
- /**
- * BitSet of printable characters as defined in RFC 1521.
- */
- private static final BitSet PRINTABLE_CHARS = new BitSet(256);
-
- private static final byte ESCAPE_CHAR = '=';
-
- private static final byte TAB = 9;
-
- private static final byte SPACE = 32;
-
- private static final byte CR = 13;
-
- private static final byte LF = 10;
-
- /**
- * Safe line length for quoted printable encoded text.
- */
- private static final int SAFE_LENGTH = 73;
-
- // Static initializer for printable chars collection
- static {
- // alpha characters
- for (int i = 33; i <= 60; i++) {
- PRINTABLE_CHARS.set(i);
- }
- for (int i = 62; i <= 126; i++) {
- PRINTABLE_CHARS.set(i);
- }
- PRINTABLE_CHARS.set(TAB);
- PRINTABLE_CHARS.set(SPACE);
- }
-
- /**
- * Default constructor, assumes default charset of {@link Charsets#UTF_8}
- */
- public QuotedPrintableCodec() {
- this(Charsets.UTF_8, false);
- }
-
- /**
- * Constructor which allows for the selection of the strict mode.
- *
- * @param strict if {@code true}, soft line breaks will be used
- * @since 1.10
- */
- public QuotedPrintableCodec(final boolean strict) {
- this(Charsets.UTF_8, strict);
- }
-
- /**
- * Constructor which allows for the selection of a default charset.
- *
- * @param charset the default string charset to use.
- * @since 1.7
- */
- public QuotedPrintableCodec(final Charset charset) {
- this(charset, false);
- }
-
- /**
- * Constructor which allows for the selection of a default charset and strict mode.
- *
- * @param charset the default string charset to use.
- * @param strict if {@code true}, soft line breaks will be used
- * @since 1.10
- */
- public QuotedPrintableCodec(final Charset charset, final boolean strict) {
- this.charset = charset;
- this.strict = strict;
- }
-
- /**
- * Constructor which allows for the selection of a default charset.
- *
- * @param charsetName the default string charset to use.
- * @throws UnsupportedCharsetException If no support for the named charset is available
- * in this instance of the Java virtual machine
- * @throws IllegalArgumentException If the given charsetName is null
- * @throws IllegalCharsetNameException If the given charset name is illegal
- * @since 1.7 throws UnsupportedCharsetException if the named charset is unavailable
- */
- public QuotedPrintableCodec(final String charsetName)
- throws IllegalCharsetNameException, IllegalArgumentException, UnsupportedCharsetException {
- this(Charset.forName(charsetName), false);
- }
-
- /**
- * Encodes byte into its quoted-printable representation.
- *
- * @param b byte to encode
- * @param buffer the buffer to write to
- * @return The number of bytes written to the buffer
- */
- private static final int encodeQuotedPrintable(final int b, final ByteArrayOutputStream buffer) {
- buffer.write(ESCAPE_CHAR);
- final char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16));
- final char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, 16));
- buffer.write(hex1);
- buffer.write(hex2);
- return 3;
- }
-
- /**
- * Return the byte at position index
of the byte array and
- * make sure it is unsigned.
- *
- * @param index position in the array
- * @param bytes the byte array
- * @return the unsigned octet at position index
from the array
- */
- private static int getUnsignedOctet(final int index, final byte[] bytes) {
- int b = bytes[index];
- if (b < 0) {
- b = 256 + b;
- }
- return b;
- }
-
- /**
- * Write a byte to the buffer.
- *
- * @param b byte to write
- * @param encode indicates whether the octet shall be encoded
- * @param buffer the buffer to write to
- * @return the number of bytes that have been written to the buffer
- */
- private static int encodeByte(final int b, final boolean encode,
- final ByteArrayOutputStream buffer) {
- if (encode) {
- return encodeQuotedPrintable(b, buffer);
- } else {
- buffer.write(b);
- return 1;
- }
- }
-
- /**
- * Checks whether the given byte is whitespace.
- *
- * @param b byte to be checked
- * @return true
if the byte is either a space or tab character
- */
- private static boolean isWhitespace(final int b) {
- return b == SPACE || b == TAB;
- }
-
- /**
- * Encodes an array of bytes into an array of quoted-printable 7-bit characters. Unsafe characters are escaped.
- *
- * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
- * RFC 1521 and is suitable for encoding binary data and unformatted text.
- *
- * @param printable bitset of characters deemed quoted-printable
- * @param bytes array of bytes to be encoded
- * @return array of bytes containing quoted-printable data
- */
- public static final byte[] encodeQuotedPrintable(BitSet printable, final byte[] bytes) {
- return encodeQuotedPrintable(printable, bytes, false);
- }
-
- /**
- * Encodes an array of bytes into an array of quoted-printable 7-bit characters. Unsafe characters are escaped.
- *
- * Depending on the selection of the {@code strict} parameter, this function either implements the full ruleset
- * or only a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
- * RFC 1521 and is suitable for encoding binary data and unformatted text.
- *
- * @param printable bitset of characters deemed quoted-printable
- * @param bytes array of bytes to be encoded
- * @param strict if {@code true} the full ruleset is used, otherwise only rule #1 and rule #2
- * @return array of bytes containing quoted-printable data
- * @since 1.10
- */
- public static final byte[] encodeQuotedPrintable(BitSet printable, final byte[] bytes, boolean strict) {
- if (bytes == null) {
- return null;
- }
- if (printable == null) {
- printable = PRINTABLE_CHARS;
- }
- final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-
- if (strict) {
- int pos = 1;
- // encode up to buffer.length - 3, the last three octets will be treated
- // separately for simplification of note #3
- for (int i = 0; i < bytes.length - 3; i++) {
- int b = getUnsignedOctet(i, bytes);
- if (pos < SAFE_LENGTH) {
- // up to this length it is safe to add any byte, encoded or not
- pos += encodeByte(b, !printable.get(b), buffer);
- } else {
- // rule #3: whitespace at the end of a line *must* be encoded
- encodeByte(b, !printable.get(b) || isWhitespace(b), buffer);
-
- // rule #5: soft line break
- buffer.write(ESCAPE_CHAR);
- buffer.write(CR);
- buffer.write(LF);
- pos = 1;
- }
- }
-
- // rule #3: whitespace at the end of a line *must* be encoded
- // if we would do a soft break line after this octet, encode whitespace
- int b = getUnsignedOctet(bytes.length - 3, bytes);
- boolean encode = !printable.get(b) || (isWhitespace(b) && pos > SAFE_LENGTH - 5);
- pos += encodeByte(b, encode, buffer);
-
- // note #3: '=' *must not* be the ultimate or penultimate character
- // simplification: if < 6 bytes left, do a soft line break as we may need
- // exactly 6 bytes space for the last 2 bytes
- if (pos > SAFE_LENGTH - 2) {
- buffer.write(ESCAPE_CHAR);
- buffer.write(CR);
- buffer.write(LF);
- }
- for (int i = bytes.length - 2; i < bytes.length; i++) {
- b = getUnsignedOctet(i, bytes);
- // rule #3: trailing whitespace shall be encoded
- encode = !printable.get(b) || (i > bytes.length - 2 && isWhitespace(b));
- encodeByte(b, encode, buffer);
- }
- } else {
- for (final byte c : bytes) {
- int b = c;
- if (b < 0) {
- b = 256 + b;
- }
- if (printable.get(b)) {
- buffer.write(b);
- } else {
- encodeQuotedPrintable(b, buffer);
- }
- }
- }
- return buffer.toByteArray();
- }
-
- /**
- * Decodes an array quoted-printable characters into an array of original bytes. Escaped characters are converted
- * back to their original representation.
- *
- * This function fully implements the quoted-printable encoding specification (rule #1 through rule #5) as
- * defined in RFC 1521.
- *
- * @param bytes array of quoted-printable characters
- * @return array of original bytes
- * @throws DecoderException Thrown if quoted-printable decoding is unsuccessful
- */
- public static final byte[] decodeQuotedPrintable(final byte[] bytes) throws DecoderException {
- if (bytes == null) {
- return null;
- }
- final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- for (int i = 0; i < bytes.length; i++) {
- final int b = bytes[i];
- if (b == ESCAPE_CHAR) {
- try {
- // if the next octet is a CR we have found a soft line break
- if (bytes[++i] == CR) {
- continue;
- }
- final int u = Utils.digit16(bytes[i]);
- final int l = Utils.digit16(bytes[++i]);
- buffer.write((char) ((u << 4) + l));
- } catch (final ArrayIndexOutOfBoundsException e) {
- throw new DecoderException("Invalid quoted-printable encoding", e);
- }
- } else if (b != CR && b != LF) {
- // every other octet is appended except for CR & LF
- buffer.write(b);
- }
- }
- return buffer.toByteArray();
- }
-
- /**
- * Encodes an array of bytes into an array of quoted-printable 7-bit characters. Unsafe characters are escaped.
- *
- * Depending on the selection of the {@code strict} parameter, this function either implements the full ruleset
- * or only a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
- * RFC 1521 and is suitable for encoding binary data and unformatted text.
- *
- * @param bytes array of bytes to be encoded
- * @return array of bytes containing quoted-printable data
- */
- @Override
- public byte[] encode(final byte[] bytes) {
- return encodeQuotedPrintable(PRINTABLE_CHARS, bytes, strict);
- }
-
- /**
- * Decodes an array of quoted-printable characters into an array of original bytes. Escaped characters are converted
- * back to their original representation.
- *
- * This function fully implements the quoted-printable encoding specification (rule #1 through rule #5) as
- * defined in RFC 1521.
- *
- * @param bytes array of quoted-printable characters
- * @return array of original bytes
- * @throws DecoderException Thrown if quoted-printable decoding is unsuccessful
- */
- @Override
- public byte[] decode(final byte[] bytes) throws DecoderException {
- return decodeQuotedPrintable(bytes);
- }
-
- /**
- * Encodes a string into its quoted-printable form using the default string charset. Unsafe characters are escaped.
- *
- * Depending on the selection of the {@code strict} parameter, this function either implements the full ruleset
- * or only a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
- * RFC 1521 and is suitable for encoding binary data and unformatted text.
- *
- * @param str string to convert to quoted-printable form
- * @return quoted-printable string
- * @throws EncoderException Thrown if quoted-printable encoding is unsuccessful
- * @see #getCharset()
- */
- @Override
- public String encode(final String str) throws EncoderException {
- return this.encode(str, getCharset());
- }
-
- /**
- * Decodes a quoted-printable string into its original form using the specified string charset. Escaped characters
- * are converted back to their original representation.
- *
- * @param str quoted-printable string to convert into its original form
- * @param charset the original string charset
- * @return original string
- * @throws DecoderException Thrown if quoted-printable decoding is unsuccessful
- * @since 1.7
- */
- public String decode(final String str, final Charset charset) throws DecoderException {
- if (str == null) {
- return null;
- }
- return new String(this.decode(StringUtils.getBytesUsAscii(str)), charset);
- }
-
- /**
- * Decodes a quoted-printable string into its original form using the specified string charset. Escaped characters
- * are converted back to their original representation.
- *
- * @param str quoted-printable string to convert into its original form
- * @param charset the original string charset
- * @return original string
- * @throws DecoderException Thrown if quoted-printable decoding is unsuccessful
- * @throws UnsupportedEncodingException Thrown if charset is not supported
- */
- public String decode(final String str, final String charset) throws DecoderException, UnsupportedEncodingException {
- if (str == null) {
- return null;
- }
- return new String(decode(StringUtils.getBytesUsAscii(str)), charset);
- }
-
- /**
- * Decodes a quoted-printable string into its original form using the default string charset. Escaped characters are
- * converted back to their original representation.
- *
- * @param str quoted-printable string to convert into its original form
- * @return original string
- * @throws DecoderException Thrown if quoted-printable decoding is unsuccessful. Thrown if charset is not supported.
- * @see #getCharset()
- */
- @Override
- public String decode(final String str) throws DecoderException {
- return this.decode(str, this.getCharset());
- }
-
- /**
- * Encodes an object into its quoted-printable safe form. Unsafe characters are escaped.
- *
- * @param obj string to convert to a quoted-printable form
- * @return quoted-printable object
- * @throws EncoderException Thrown if quoted-printable encoding is not applicable to objects of this type or if encoding is
- * unsuccessful
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (obj == null) {
- return null;
- } else if (obj instanceof byte[]) {
- return encode((byte[]) obj);
- } else if (obj instanceof String) {
- return encode((String) obj);
- } else {
- throw new EncoderException("Objects of type " +
- obj.getClass().getName() +
- " cannot be quoted-printable encoded");
- }
- }
-
- /**
- * Decodes a quoted-printable object into its original form. Escaped characters are converted back to their original
- * representation.
- *
- * @param obj quoted-printable object to convert into its original form
- * @return original object
- * @throws DecoderException Thrown if the argument is not a String
or byte[]
. Thrown if a failure
- * condition is encountered during the decode process.
- */
- @Override
- public Object decode(final Object obj) throws DecoderException {
- if (obj == null) {
- return null;
- } else if (obj instanceof byte[]) {
- return decode((byte[]) obj);
- } else if (obj instanceof String) {
- return decode((String) obj);
- } else {
- throw new DecoderException("Objects of type " +
- obj.getClass().getName() +
- " cannot be quoted-printable decoded");
- }
- }
-
- /**
- * Gets the default charset name used for string decoding and encoding.
- *
- * @return the default charset name
- * @since 1.7
- */
- public Charset getCharset() {
- return this.charset;
- }
-
- /**
- * Gets the default charset name used for string decoding and encoding.
- *
- * @return the default charset name
- */
- public String getDefaultCharset() {
- return this.charset.name();
- }
-
- /**
- * Encodes a string into its quoted-printable form using the specified charset. Unsafe characters are escaped.
- *
- * Depending on the selection of the {@code strict} parameter, this function either implements the full ruleset
- * or only a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
- * RFC 1521 and is suitable for encoding binary data and unformatted text.
- *
- * @param str string to convert to quoted-printable form
- * @param charset the charset for str
- * @return quoted-printable string
- * @since 1.7
- */
- public String encode(final String str, final Charset charset) {
- if (str == null) {
- return null;
- }
- return StringUtils.newStringUsAscii(this.encode(str.getBytes(charset)));
- }
-
- /**
- * Encodes a string into its quoted-printable form using the specified charset. Unsafe characters are escaped.
- *
- * Depending on the selection of the {@code strict} parameter, this function either implements the full ruleset
- * or only a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
- * RFC 1521 and is suitable for encoding binary data and unformatted text.
- *
- * @param str string to convert to quoted-printable form
- * @param charset the charset for str
- * @return quoted-printable string
- * @throws UnsupportedEncodingException Thrown if the charset is not supported
- */
- public String encode(final String str, final String charset) throws UnsupportedEncodingException {
- if (str == null) {
- return null;
- }
- return StringUtils.newStringUsAscii(encode(str.getBytes(charset)));
- }
-}
diff --git a/src/org/apache/commons/codec/net/RFC1522Codec.java b/src/org/apache/commons/codec/net/RFC1522Codec.java
deleted file mode 100644
index 169e31cf..00000000
--- a/src/org/apache/commons/codec/net/RFC1522Codec.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.net;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.binary.StringUtils;
-
-/**
- * Implements methods common to all codecs defined in RFC 1522.
- *
- * RFC 1522 describes techniques to allow the
- * encoding of non-ASCII text in various portions of a RFC 822 [2] message header, in a manner which
- * is unlikely to confuse existing message handling software.
- *
- * This class is immutable and thread-safe.
- *
- * @version $Id$
- * @see MIME (Multipurpose Internet Mail Extensions) Part Two:
- * Message Header Extensions for Non-ASCII Text
- * @since 1.3
- */
-abstract class RFC1522Codec {
-
- /**
- * Separator.
- */
- protected static final char SEP = '?';
-
- /**
- * Prefix.
- */
- protected static final String POSTFIX = "?=";
-
- /**
- * Postfix.
- */
- protected static final String PREFIX = "=?";
-
- /**
- * Applies an RFC 1522 compliant encoding scheme to the given string of text with the given charset.
- *
- * This method constructs the "encoded-word" header common to all the RFC 1522 codecs and then invokes
- * {@link RFC1522Codec#doEncoding(byte[])} method of a concrete class to perform the specific encoding.
- *
- * @param text a string to encode
- * @param charset a charset to be used
- * @return RFC 1522 compliant "encoded-word"
- * @throws EncoderException thrown if there is an error condition during the Encoding process.
- * @see Standard charsets
- */
- protected String encodeText(final String text, final Charset charset) throws EncoderException {
- if (text == null) {
- return null;
- }
- final StringBuilder buffer = new StringBuilder();
- buffer.append(PREFIX);
- buffer.append(charset);
- buffer.append(SEP);
- buffer.append(this.getEncoding());
- buffer.append(SEP);
- final byte[] rawData = this.doEncoding(text.getBytes(charset));
- buffer.append(StringUtils.newStringUsAscii(rawData));
- buffer.append(POSTFIX);
- return buffer.toString();
- }
-
- /**
- * Applies an RFC 1522 compliant encoding scheme to the given string of text with the given charset.
- *
- * This method constructs the "encoded-word" header common to all the RFC 1522 codecs and then invokes
- * {@link RFC1522Codec#doEncoding(byte[])} method of a concrete class to perform the specific encoding.
- *
- * @param text a string to encode
- * @param charsetName the charset to use
- * @return RFC 1522 compliant "encoded-word"
- * @throws EncoderException thrown if there is an error condition during the Encoding process.
- * @throws UnsupportedEncodingException if charset is not available
- * @see Standard charsets
- */
- protected String encodeText(final String text, final String charsetName)
- throws EncoderException, UnsupportedEncodingException {
- if (text == null) {
- return null;
- }
- return this.encodeText(text, Charset.forName(charsetName));
- }
-
- /**
- * Applies an RFC 1522 compliant decoding scheme to the given string of text.
- *
- * This method processes the "encoded-word" header common to all the RFC 1522 codecs and then invokes
- * {@link RFC1522Codec#doEncoding(byte[])} method of a concrete class to perform the specific decoding.
- *
- * @param text a string to decode
- * @return A new decoded String or null
if the input is null
.
- * @throws DecoderException thrown if there is an error condition during the decoding process.
- * @throws UnsupportedEncodingException thrown if charset specified in the "encoded-word" header is not supported
- */
- protected String decodeText(final String text)
- throws DecoderException, UnsupportedEncodingException {
- if (text == null) {
- return null;
- }
- if (!text.startsWith(PREFIX) || !text.endsWith(POSTFIX)) {
- throw new DecoderException("RFC 1522 violation: malformed encoded content");
- }
- final int terminator = text.length() - 2;
- int from = 2;
- int to = text.indexOf(SEP, from);
- if (to == terminator) {
- throw new DecoderException("RFC 1522 violation: charset token not found");
- }
- final String charset = text.substring(from, to);
- if (charset.equals("")) {
- throw new DecoderException("RFC 1522 violation: charset not specified");
- }
- from = to + 1;
- to = text.indexOf(SEP, from);
- if (to == terminator) {
- throw new DecoderException("RFC 1522 violation: encoding token not found");
- }
- final String encoding = text.substring(from, to);
- if (!getEncoding().equalsIgnoreCase(encoding)) {
- throw new DecoderException("This codec cannot decode " + encoding + " encoded content");
- }
- from = to + 1;
- to = text.indexOf(SEP, from);
- byte[] data = StringUtils.getBytesUsAscii(text.substring(from, to));
- data = doDecoding(data);
- return new String(data, charset);
- }
-
- /**
- * Returns the codec name (referred to as encoding in the RFC 1522).
- *
- * @return name of the codec
- */
- protected abstract String getEncoding();
-
- /**
- * Encodes an array of bytes using the defined encoding scheme.
- *
- * @param bytes Data to be encoded
- * @return A byte array containing the encoded data
- * @throws EncoderException thrown if the Encoder encounters a failure condition during the encoding process.
- */
- protected abstract byte[] doEncoding(byte[] bytes) throws EncoderException;
-
- /**
- * Decodes an array of bytes using the defined encoding scheme.
- *
- * @param bytes Data to be decoded
- * @return a byte array that contains decoded data
- * @throws DecoderException A decoder exception is thrown if a Decoder encounters a failure condition during the decode process.
- */
- protected abstract byte[] doDecoding(byte[] bytes) throws DecoderException;
-}
diff --git a/src/org/apache/commons/codec/net/URLCodec.java b/src/org/apache/commons/codec/net/URLCodec.java
deleted file mode 100644
index 5c2559c0..00000000
--- a/src/org/apache/commons/codec/net/URLCodec.java
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.net;
-
-import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
-import java.util.BitSet;
-
-import org.apache.commons.codec.BinaryDecoder;
-import org.apache.commons.codec.BinaryEncoder;
-import org.apache.commons.codec.CharEncoding;
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.EncoderException;
-import org.apache.commons.codec.StringDecoder;
-import org.apache.commons.codec.StringEncoder;
-import org.apache.commons.codec.binary.StringUtils;
-
-/**
- * Implements the 'www-form-urlencoded' encoding scheme, also misleadingly known as URL encoding.
- *
- * This codec is meant to be a replacement for standard Java classes {@link java.net.URLEncoder} and
- * {@link java.net.URLDecoder} on older Java platforms, as these classes in Java versions below
- * 1.4 rely on the platform's default charset encoding.
- *
- * This class is immutable and thread-safe.
- *
- * @version $Id$
- * @see Chapter 17.13.4 Form content types
- * of the HTML 4.01 Specification
- * @since 1.2
- */
-public class URLCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, StringDecoder {
-
- /**
- * Radix used in encoding and decoding.
- */
- static final int RADIX = 16;
-
- /**
- * The default charset used for string decoding and encoding.
- *
- * @deprecated TODO: This field will be changed to a private final Charset in 2.0.
- */
- @Deprecated
- protected String charset;
-
- /**
- * Release 1.5 made this field final.
- */
- protected static final byte ESCAPE_CHAR = '%';
- /**
- * BitSet of www-form-url safe characters.
- */
- protected static final BitSet WWW_FORM_URL = new BitSet(256);
-
- // Static initializer for www_form_url
- static {
- // alpha characters
- for (int i = 'a'; i <= 'z'; i++) {
- WWW_FORM_URL.set(i);
- }
- for (int i = 'A'; i <= 'Z'; i++) {
- WWW_FORM_URL.set(i);
- }
- // numeric characters
- for (int i = '0'; i <= '9'; i++) {
- WWW_FORM_URL.set(i);
- }
- // special chars
- WWW_FORM_URL.set('-');
- WWW_FORM_URL.set('_');
- WWW_FORM_URL.set('.');
- WWW_FORM_URL.set('*');
- // blank to be replaced with +
- WWW_FORM_URL.set(' ');
- }
-
-
- /**
- * Default constructor.
- */
- public URLCodec() {
- this(CharEncoding.UTF_8);
- }
-
- /**
- * Constructor which allows for the selection of a default charset.
- *
- * @param charset the default string charset to use.
- */
- public URLCodec(final String charset) {
- super();
- this.charset = charset;
- }
-
- /**
- * Encodes an array of bytes into an array of URL safe 7-bit characters. Unsafe characters are escaped.
- *
- * @param urlsafe bitset of characters deemed URL safe
- * @param bytes array of bytes to convert to URL safe characters
- * @return array of bytes containing URL safe characters
- */
- public static final byte[] encodeUrl(BitSet urlsafe, final byte[] bytes) {
- if (bytes == null) {
- return null;
- }
- if (urlsafe == null) {
- urlsafe = WWW_FORM_URL;
- }
-
- final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- for (final byte c : bytes) {
- int b = c;
- if (b < 0) {
- b = 256 + b;
- }
- if (urlsafe.get(b)) {
- if (b == ' ') {
- b = '+';
- }
- buffer.write(b);
- } else {
- buffer.write(ESCAPE_CHAR);
- final char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, RADIX));
- final char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, RADIX));
- buffer.write(hex1);
- buffer.write(hex2);
- }
- }
- return buffer.toByteArray();
- }
-
- /**
- * Decodes an array of URL safe 7-bit characters into an array of original bytes. Escaped characters are converted
- * back to their original representation.
- *
- * @param bytes array of URL safe characters
- * @return array of original bytes
- * @throws DecoderException Thrown if URL decoding is unsuccessful
- */
- public static final byte[] decodeUrl(final byte[] bytes) throws DecoderException {
- if (bytes == null) {
- return null;
- }
- final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- for (int i = 0; i < bytes.length; i++) {
- final int b = bytes[i];
- if (b == '+') {
- buffer.write(' ');
- } else if (b == ESCAPE_CHAR) {
- try {
- final int u = Utils.digit16(bytes[++i]);
- final int l = Utils.digit16(bytes[++i]);
- buffer.write((char) ((u << 4) + l));
- } catch (final ArrayIndexOutOfBoundsException e) {
- throw new DecoderException("Invalid URL encoding: ", e);
- }
- } else {
- buffer.write(b);
- }
- }
- return buffer.toByteArray();
- }
-
- /**
- * Encodes an array of bytes into an array of URL safe 7-bit characters. Unsafe characters are escaped.
- *
- * @param bytes array of bytes to convert to URL safe characters
- * @return array of bytes containing URL safe characters
- */
- @Override
- public byte[] encode(final byte[] bytes) {
- return encodeUrl(WWW_FORM_URL, bytes);
- }
-
-
- /**
- * Decodes an array of URL safe 7-bit characters into an array of original bytes. Escaped characters are converted
- * back to their original representation.
- *
- * @param bytes array of URL safe characters
- * @return array of original bytes
- * @throws DecoderException Thrown if URL decoding is unsuccessful
- */
- @Override
- public byte[] decode(final byte[] bytes) throws DecoderException {
- return decodeUrl(bytes);
- }
-
- /**
- * Encodes a string into its URL safe form using the specified string charset. Unsafe characters are escaped.
- *
- * @param str string to convert to a URL safe form
- * @param charset the charset for str
- * @return URL safe string
- * @throws UnsupportedEncodingException Thrown if charset is not supported
- */
- public String encode(final String str, final String charset) throws UnsupportedEncodingException {
- if (str == null) {
- return null;
- }
- return StringUtils.newStringUsAscii(encode(str.getBytes(charset)));
- }
-
- /**
- * Encodes a string into its URL safe form using the default string charset. Unsafe characters are escaped.
- *
- * @param str string to convert to a URL safe form
- * @return URL safe string
- * @throws EncoderException Thrown if URL encoding is unsuccessful
- * @see #getDefaultCharset()
- */
- @Override
- public String encode(final String str) throws EncoderException {
- if (str == null) {
- return null;
- }
- try {
- return encode(str, getDefaultCharset());
- } catch (final UnsupportedEncodingException e) {
- throw new EncoderException(e.getMessage(), e);
- }
- }
-
-
- /**
- * Decodes a URL safe string into its original form using the specified encoding. Escaped characters are converted
- * back to their original representation.
- *
- * @param str URL safe string to convert into its original form
- * @param charset the original string charset
- * @return original string
- * @throws DecoderException Thrown if URL decoding is unsuccessful
- * @throws UnsupportedEncodingException Thrown if charset is not supported
- */
- public String decode(final String str, final String charset) throws DecoderException, UnsupportedEncodingException {
- if (str == null) {
- return null;
- }
- return new String(decode(StringUtils.getBytesUsAscii(str)), charset);
- }
-
- /**
- * Decodes a URL safe string into its original form using the default string charset. Escaped characters are
- * converted back to their original representation.
- *
- * @param str URL safe string to convert into its original form
- * @return original string
- * @throws DecoderException Thrown if URL decoding is unsuccessful
- * @see #getDefaultCharset()
- */
- @Override
- public String decode(final String str) throws DecoderException {
- if (str == null) {
- return null;
- }
- try {
- return decode(str, getDefaultCharset());
- } catch (final UnsupportedEncodingException e) {
- throw new DecoderException(e.getMessage(), e);
- }
- }
-
- /**
- * Encodes an object into its URL safe form. Unsafe characters are escaped.
- *
- * @param obj string to convert to a URL safe form
- * @return URL safe object
- * @throws EncoderException Thrown if URL encoding is not applicable to objects of this type or if encoding is unsuccessful
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (obj == null) {
- return null;
- } else if (obj instanceof byte[]) {
- return encode((byte[]) obj);
- } else if (obj instanceof String) {
- return encode((String) obj);
- } else {
- throw new EncoderException("Objects of type " + obj.getClass().getName() + " cannot be URL encoded");
-
- }
- }
-
- /**
- * Decodes a URL safe object into its original form. Escaped characters are converted back to their original
- * representation.
- *
- * @param obj URL safe object to convert into its original form
- * @return original object
- * @throws DecoderException Thrown if the argument is not a String
or byte[]
. Thrown if a failure
- * condition is encountered during the decode process.
- */
- @Override
- public Object decode(final Object obj) throws DecoderException {
- if (obj == null) {
- return null;
- } else if (obj instanceof byte[]) {
- return decode((byte[]) obj);
- } else if (obj instanceof String) {
- return decode((String) obj);
- } else {
- throw new DecoderException("Objects of type " + obj.getClass().getName() + " cannot be URL decoded");
-
- }
- }
-
- /**
- * The default charset used for string decoding and encoding.
- *
- * @return the default string charset.
- */
- public String getDefaultCharset() {
- return this.charset;
- }
-
- /**
- * The String
encoding used for decoding and encoding.
- *
- * @return Returns the encoding.
- * @deprecated Use {@link #getDefaultCharset()}, will be removed in 2.0.
- */
- @Deprecated
- public String getEncoding() {
- return this.charset;
- }
-}
diff --git a/src/org/apache/commons/codec/net/Utils.java b/src/org/apache/commons/codec/net/Utils.java
deleted file mode 100644
index 99f55df9..00000000
--- a/src/org/apache/commons/codec/net/Utils.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.codec.net;
-
-import org.apache.commons.codec.DecoderException;
-
-/**
- * Utility methods for this package.
- *
- *
This class is immutable and thread-safe.
- *
- * @version $Id$
- * @since 1.4
- */
-class Utils {
-
- /**
- * Returns the numeric value of the character b
in radix 16.
- *
- * @param b The byte to be converted.
- * @return The numeric value represented by the character in radix 16.
- * @throws DecoderException Thrown when the byte is not valid per {@link Character#digit(char, int)}
- */
- static int digit16(final byte b) throws DecoderException {
- final int i = Character.digit((char) b, URLCodec.RADIX);
- if (i == -1) {
- throw new DecoderException("Invalid URL encoding: not a valid digit (radix " + URLCodec.RADIX + "): " + b);
- }
- return i;
- }
-}
diff --git a/src/org/apache/commons/codec/net/package.html b/src/org/apache/commons/codec/net/package.html
deleted file mode 100644
index 807c7ea3..00000000
--- a/src/org/apache/commons/codec/net/package.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
- Network related encoding and decoding.
-
-
-
diff --git a/src/org/apache/commons/codec/overview.html b/src/org/apache/commons/codec/overview.html
deleted file mode 100644
index cb4298b8..00000000
--- a/src/org/apache/commons/codec/overview.html
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
- This document is the API specification for the Apache Commons Codec Library, version 1.3.
-
-
- This library requires a JRE version of 1.2.2 or greater.
- The hypertext links originating from this document point to Sun's version 1.3 API as the 1.2.2 API documentation
- is no longer on-line.
-
-
-
diff --git a/src/org/apache/commons/codec/package.html b/src/org/apache/commons/codec/package.html
deleted file mode 100644
index 94b0e067..00000000
--- a/src/org/apache/commons/codec/package.html
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
-
-
-
-
-Interfaces and classes used by
- the various implementations in the sub-packages.
-
-Definitive implementations of commonly used encoders and decoders.
-
-Codec is currently comprised of a modest set of utilities and a
- simple framework for String encoding and decoding in three categories:
- Binary Encoders, Language Encoders, and Network Encoders.
-
-
-
-
-
-
- Codec contains a number of commonly used language and phonetic
- encoders
-
-
-
-
- Codec contains network related encoders
-
-
-
-
diff --git a/src/org/imgscalr/AsyncScalr.java b/src/org/imgscalr/AsyncScalr.java
deleted file mode 100644
index c66d4a78..00000000
--- a/src/org/imgscalr/AsyncScalr.java
+++ /dev/null
@@ -1,594 +0,0 @@
-/**
- * Copyright 2011 The Buzz Media, LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.imgscalr;
-
-import java.awt.Color;
-import java.awt.image.BufferedImage;
-import java.awt.image.BufferedImageOp;
-import java.awt.image.ImagingOpException;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.imgscalr.Scalr.Method;
-import org.imgscalr.Scalr.Mode;
-import org.imgscalr.Scalr.Rotation;
-
-/**
- * Class used to provide the asynchronous versions of all the methods defined in
- * {@link Scalr} for the purpose of efficiently handling large amounts of image
- * operations via a select number of processing threads asynchronously.
- *
- * Given that image-scaling operations, especially when working with large
- * images, can be very hardware-intensive (both CPU and memory), in large-scale
- * deployments (e.g. a busy web application) it becomes increasingly important
- * that the scale operations performed by imgscalr be manageable so as not to
- * fire off too many simultaneous operations that the JVM's heap explodes and
- * runs out of memory or pegs the CPU on the host machine, staving all other
- * running processes.
- *
- * Up until now it was left to the caller to implement their own serialization
- * or limiting logic to handle these use-cases. Given imgscalr's popularity in
- * web applications it was determined that this requirement be common enough
- * that it should be integrated directly into the imgscalr library for everyone
- * to benefit from.
- *
- * Every method in this class wraps the matching methods in the {@link Scalr}
- * class in new {@link Callable} instances that are submitted to an internal
- * {@link ExecutorService} for execution at a later date. A {@link Future} is
- * returned to the caller representing the task that is either currently
- * performing the scale operation or will at a future date depending on where it
- * is in the {@link ExecutorService}'s queue. {@link Future#get()} or
- * {@link Future#get(long, TimeUnit)} can be used to block on the
- * Future
, waiting for the scale operation to complete and return
- * the resultant {@link BufferedImage} to the caller.
- *
- * This design provides the following features:
- *
- * Non-blocking, asynchronous scale operations that can continue execution
- * while waiting on the scaled result.
- * Serialize all scale requests down into a maximum number of
- * simultaneous scale operations with no additional/complex logic. The
- * number of simultaneous scale operations is caller-configurable (see
- * {@link #THREAD_COUNT}) so as best to optimize the host system (e.g. 1 scale
- * thread per core).
- * No need to worry about overloading the host system with too many scale
- * operations, they will simply queue up in this class and execute in-order.
- * Synchronous/blocking behavior can still be achieved (if desired) by
- * calling get()
or get(long, TimeUnit)
immediately on
- * the returned {@link Future} from any of the methods below.
- *
- * Performance
- * When tuning this class for optimal performance, benchmarking your particular
- * hardware is the best approach. For some rough guidelines though, there are
- * two resources you want to watch closely:
- *
- * JVM Heap Memory (Assume physical machine memory is always sufficiently
- * large)
- * # of CPU Cores
- *
- * You never want to allocate more scaling threads than you have CPU cores and
- * on a sufficiently busy host where some of the cores may be busy running a
- * database or a web server, you will want to allocate even less scaling
- * threads.
- *
- * So as a maximum you would never want more scaling threads than CPU cores in
- * any situation and less so on a busy server.
- *
- * If you allocate more threads than you have available CPU cores, your scaling
- * operations will slow down as the CPU will spend a considerable amount of time
- * context-switching between threads on the same core trying to finish all the
- * tasks in parallel. You might still be tempted to do this because of the I/O
- * delay some threads will encounter reading images off disk, but when you do
- * your own benchmarking you'll likely find (as I did) that the actual disk I/O
- * necessary to pull the image data off disk is a much smaller portion of the
- * execution time than the actual scaling operations.
- *
- * If you are executing on a storage medium that is unexpectedly slow and I/O is
- * a considerable portion of the scaling operation (e.g. S3 or EBS volumes),
- * feel free to try using more threads than CPU cores to see if that helps; but
- * in most normal cases, it will only slow down all other parallel scaling
- * operations.
- *
- * As for memory, every time an image is scaled it is decoded into a
- * {@link BufferedImage} and stored in the JVM Heap space (decoded image
- * instances are always larger than the source images on-disk). For larger
- * images, that can use up quite a bit of memory. You will need to benchmark
- * your particular use-cases on your hardware to get an idea of where the sweet
- * spot is for this; if you are operating within tight memory bounds, you may
- * want to limit simultaneous scaling operations to 1 or 2 regardless of the
- * number of cores just to avoid having too many {@link BufferedImage} instances
- * in JVM Heap space at the same time.
- *
- * These are rough metrics and behaviors to give you an idea of how best to tune
- * this class for your deployment, but nothing can replacement writing a small
- * Java class that scales a handful of images in a number of different ways and
- * testing that directly on your deployment hardware.
- * Resource Overhead
- * The {@link ExecutorService} utilized by this class won't be initialized until
- * one of the operation methods are called, at which point the
- * service
will be instantiated for the first time and operation
- * queued up.
- *
- * More specifically, if you have no need for asynchronous image processing
- * offered by this class, you don't need to worry about wasted resources or
- * hanging/idle threads as they will never be created if you never use this
- * class.
- * Cleaning up Service Threads
- * By default the {@link Thread}s created by the internal
- * {@link ThreadPoolExecutor} do not run in daemon
mode; which
- * means they will block the host VM from exiting until they are explicitly shut
- * down in a client application; in a server application the container will shut
- * down the pool forcibly.
- *
- * If you have used the {@link AsyncScalr} class and are trying to shut down a
- * client application, you will need to call {@link #getService()} then
- * {@link ExecutorService#shutdown()} or {@link ExecutorService#shutdownNow()}
- * to have the threads terminated; you may also want to look at the
- * {@link ExecutorService#awaitTermination(long, TimeUnit)} method if you'd like
- * to more closely monitor the shutting down process (and finalization of
- * pending scale operations).
- * Reusing Shutdown AsyncScalr
- * If you have previously called shutdown
on the underlying service
- * utilized by this class, subsequent calls to any of the operations this class
- * provides will invoke the internal {@link #checkService()} method which will
- * replace the terminated underlying {@link ExecutorService} with a new one via
- * the {@link #createService()} method.
- * Custom Implementations
- * If a subclass wants to customize the {@link ExecutorService} or
- * {@link ThreadFactory} used under the covers, this can be done by overriding
- * the {@link #createService()} method which is invoked by this class anytime a
- * new {@link ExecutorService} is needed.
- *
- * By default the {@link #createService()} method delegates to the
- * {@link #createService(ThreadFactory)} method with a new instance of
- * {@link DefaultThreadFactory}. Either of these methods can be overridden and
- * customized easily if desired.
- *
- * TIP : A common customization to this class is to make the
- * {@link Thread}s generated by the underlying factory more server-friendly, in
- * which case the caller would want to use an instance of the
- * {@link ServerThreadFactory} when creating the new {@link ExecutorService}.
- *
- * This can be done in one line by overriding {@link #createService()} and
- * returning the result of:
- * return createService(new ServerThreadFactory());
- *
- * By default this class uses an {@link ThreadPoolExecutor} internally to handle
- * execution of queued image operations. If a different type of
- * {@link ExecutorService} is desired, again, simply overriding the
- * {@link #createService()} method of choice is the right way to do that.
- *
- * @author Riyad Kalla (software@thebuzzmedia.com)
- * @since 3.2
- */
-@SuppressWarnings("javadoc")
-public class AsyncScalr {
- /**
- * System property name used to set the number of threads the default
- * underlying {@link ExecutorService} will use to process async image
- * operations.
- *
- * Value is "imgscalr.async.threadCount
".
- */
- public static final String THREAD_COUNT_PROPERTY_NAME = "imgscalr.async.threadCount";
-
- /**
- * Number of threads the internal {@link ExecutorService} will use to
- * simultaneously execute scale requests.
- *
- * This value can be changed by setting the
- * imgscalr.async.threadCount
system property (see
- * {@link #THREAD_COUNT_PROPERTY_NAME}) to a valid integer value > 0.
- *
- * Default value is 2
.
- */
- public static final int THREAD_COUNT = Integer.getInteger(
- THREAD_COUNT_PROPERTY_NAME, 2);
-
- /**
- * Initializer used to verify the THREAD_COUNT system property.
- */
- static {
- if (THREAD_COUNT < 1)
- throw new RuntimeException("System property '"
- + THREAD_COUNT_PROPERTY_NAME + "' set THREAD_COUNT to "
- + THREAD_COUNT + ", but THREAD_COUNT must be > 0.");
- }
-
- protected static ExecutorService service;
-
- /**
- * Used to get access to the internal {@link ExecutorService} used by this
- * class to process scale operations.
- *
- * NOTE : You will need to explicitly shutdown any service
- * currently set on this class before the host JVM exits.
- *
- * You can call {@link ExecutorService#shutdown()} to wait for all scaling
- * operations to complete first or call
- * {@link ExecutorService#shutdownNow()} to kill any in-process operations
- * and purge all pending operations before exiting.
- *
- * Additionally you can use
- * {@link ExecutorService#awaitTermination(long, TimeUnit)} after issuing a
- * shutdown command to try and wait until the service has finished all
- * tasks.
- *
- * @return the current {@link ExecutorService} used by this class to process
- * scale operations.
- */
- public static ExecutorService getService() {
- return service;
- }
-
- /**
- * @see Scalr#apply(BufferedImage, BufferedImageOp...)
- */
- public static Future apply(final BufferedImage src,
- final BufferedImageOp... ops) throws IllegalArgumentException,
- ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.apply(src, ops);
- }
- });
- }
-
- /**
- * @see Scalr#crop(BufferedImage, int, int, BufferedImageOp...)
- */
- public static Future crop(final BufferedImage src,
- final int width, final int height, final BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.crop(src, width, height, ops);
- }
- });
- }
-
- /**
- * @see Scalr#crop(BufferedImage, int, int, int, int, BufferedImageOp...)
- */
- public static Future crop(final BufferedImage src,
- final int x, final int y, final int width, final int height,
- final BufferedImageOp... ops) throws IllegalArgumentException,
- ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.crop(src, x, y, width, height, ops);
- }
- });
- }
-
- /**
- * @see Scalr#pad(BufferedImage, int, BufferedImageOp...)
- */
- public static Future pad(final BufferedImage src,
- final int padding, final BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.pad(src, padding, ops);
- }
- });
- }
-
- /**
- * @see Scalr#pad(BufferedImage, int, Color, BufferedImageOp...)
- */
- public static Future pad(final BufferedImage src,
- final int padding, final Color color, final BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.pad(src, padding, color, ops);
- }
- });
- }
-
- /**
- * @see Scalr#resize(BufferedImage, int, BufferedImageOp...)
- */
- public static Future resize(final BufferedImage src,
- final int targetSize, final BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.resize(src, targetSize, ops);
- }
- });
- }
-
- /**
- * @see Scalr#resize(BufferedImage, Method, int, BufferedImageOp...)
- */
- public static Future resize(final BufferedImage src,
- final Method scalingMethod, final int targetSize,
- final BufferedImageOp... ops) throws IllegalArgumentException,
- ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.resize(src, scalingMethod, targetSize, ops);
- }
- });
- }
-
- /**
- * @see Scalr#resize(BufferedImage, Mode, int, BufferedImageOp...)
- */
- public static Future resize(final BufferedImage src,
- final Mode resizeMode, final int targetSize,
- final BufferedImageOp... ops) throws IllegalArgumentException,
- ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.resize(src, resizeMode, targetSize, ops);
- }
- });
- }
-
- /**
- * @see Scalr#resize(BufferedImage, Method, Mode, int, BufferedImageOp...)
- */
- public static Future resize(final BufferedImage src,
- final Method scalingMethod, final Mode resizeMode,
- final int targetSize, final BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.resize(src, scalingMethod, resizeMode, targetSize,
- ops);
- }
- });
- }
-
- /**
- * @see Scalr#resize(BufferedImage, int, int, BufferedImageOp...)
- */
- public static Future resize(final BufferedImage src,
- final int targetWidth, final int targetHeight,
- final BufferedImageOp... ops) throws IllegalArgumentException,
- ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.resize(src, targetWidth, targetHeight, ops);
- }
- });
- }
-
- /**
- * @see Scalr#resize(BufferedImage, Method, int, int, BufferedImageOp...)
- */
- public static Future resize(final BufferedImage src,
- final Method scalingMethod, final int targetWidth,
- final int targetHeight, final BufferedImageOp... ops) {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.resize(src, scalingMethod, targetWidth,
- targetHeight, ops);
- }
- });
- }
-
- /**
- * @see Scalr#resize(BufferedImage, Mode, int, int, BufferedImageOp...)
- */
- public static Future resize(final BufferedImage src,
- final Mode resizeMode, final int targetWidth,
- final int targetHeight, final BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.resize(src, resizeMode, targetWidth, targetHeight,
- ops);
- }
- });
- }
-
- /**
- * @see Scalr#resize(BufferedImage, Method, Mode, int, int,
- * BufferedImageOp...)
- */
- public static Future resize(final BufferedImage src,
- final Method scalingMethod, final Mode resizeMode,
- final int targetWidth, final int targetHeight,
- final BufferedImageOp... ops) throws IllegalArgumentException,
- ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.resize(src, scalingMethod, resizeMode,
- targetWidth, targetHeight, ops);
- }
- });
- }
-
- /**
- * @see Scalr#rotate(BufferedImage, Rotation, BufferedImageOp...)
- */
- public static Future rotate(final BufferedImage src,
- final Rotation rotation, final BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- checkService();
-
- return service.submit(new Callable() {
- public BufferedImage call() throws Exception {
- return Scalr.rotate(src, rotation, ops);
- }
- });
- }
-
- protected static ExecutorService createService() {
- return createService(new DefaultThreadFactory());
- }
-
- protected static ExecutorService createService(ThreadFactory factory)
- throws IllegalArgumentException {
- if (factory == null)
- throw new IllegalArgumentException("factory cannot be null");
-
- return Executors.newFixedThreadPool(THREAD_COUNT, factory);
- }
-
- /**
- * Used to verify that the underlying service
points at an
- * active {@link ExecutorService} instance that can be used by this class.
- *
- * If service
is null
, has been shutdown or
- * terminated then this method will replace it with a new
- * {@link ExecutorService} by calling the {@link #createService()} method
- * and assigning the returned value to service
.
- *
- * Any subclass that wants to customize the {@link ExecutorService} or
- * {@link ThreadFactory} used internally by this class should override the
- * {@link #createService()}.
- */
- protected static void checkService() {
- if (service == null || service.isShutdown() || service.isTerminated()) {
- /*
- * If service was shutdown or terminated, assigning a new value will
- * free the reference to the instance, allowing it to be GC'ed when
- * it is done shutting down (assuming it hadn't already).
- */
- service = createService();
- }
- }
-
- /**
- * Default {@link ThreadFactory} used by the internal
- * {@link ExecutorService} to creates execution {@link Thread}s for image
- * scaling.
- *
- * More or less a copy of the hidden class backing the
- * {@link Executors#defaultThreadFactory()} method, but exposed here to make
- * it easier for implementors to extend and customize.
- *
- * @author Doug Lea
- * @author Riyad Kalla (software@thebuzzmedia.com)
- * @since 4.0
- */
- protected static class DefaultThreadFactory implements ThreadFactory {
- protected static final AtomicInteger poolNumber = new AtomicInteger(1);
-
- protected final ThreadGroup group;
- protected final AtomicInteger threadNumber = new AtomicInteger(1);
- protected final String namePrefix;
-
- DefaultThreadFactory() {
- SecurityManager manager = System.getSecurityManager();
-
- /*
- * Determine the group that threads created by this factory will be
- * in.
- */
- group = (manager == null ? Thread.currentThread().getThreadGroup()
- : manager.getThreadGroup());
-
- /*
- * Define a common name prefix for the threads created by this
- * factory.
- */
- namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
- }
-
- /**
- * Used to create a {@link Thread} capable of executing the given
- * {@link Runnable}.
- *
- * Thread created by this factory are utilized by the parent
- * {@link ExecutorService} when processing queued up scale operations.
- */
- public Thread newThread(Runnable r) {
- /*
- * Create a new thread in our specified group with a meaningful
- * thread name so it is easy to identify.
- */
- Thread thread = new Thread(group, r, namePrefix
- + threadNumber.getAndIncrement(), 0);
-
- // Configure thread according to class or subclass
- thread.setDaemon(false);
- thread.setPriority(Thread.NORM_PRIORITY);
-
- return thread;
- }
- }
-
- /**
- * An extension of the {@link DefaultThreadFactory} class that makes two
- * changes to the execution {@link Thread}s it generations:
- *
- * Threads are set to be daemon threads instead of user threads.
- * Threads execute with a priority of {@link Thread#MIN_PRIORITY} to
- * make them more compatible with server environment deployments.
- *
- * This class is provided as a convenience for subclasses to use if they
- * want this (common) customization to the {@link Thread}s used internally
- * by {@link AsyncScalr} to process images, but don't want to have to write
- * the implementation.
- *
- * @author Riyad Kalla (software@thebuzzmedia.com)
- * @since 4.0
- */
- protected static class ServerThreadFactory extends DefaultThreadFactory {
- /**
- * Overridden to set daemon
property to true
- * and decrease the priority of the new thread to
- * {@link Thread#MIN_PRIORITY} before returning it.
- */
- @Override
- public Thread newThread(Runnable r) {
- Thread thread = super.newThread(r);
-
- thread.setDaemon(true);
- thread.setPriority(Thread.MIN_PRIORITY);
-
- return thread;
- }
- }
-}
\ No newline at end of file
diff --git a/src/org/imgscalr/Scalr.java b/src/org/imgscalr/Scalr.java
deleted file mode 100644
index 1d280bc3..00000000
--- a/src/org/imgscalr/Scalr.java
+++ /dev/null
@@ -1,2172 +0,0 @@
-/**
- * Copyright 2011 The Buzz Media, LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.imgscalr;
-
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Image;
-import java.awt.RenderingHints;
-import java.awt.Transparency;
-import java.awt.color.ColorSpace;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.AreaAveragingScaleFilter;
-import java.awt.image.BufferedImage;
-import java.awt.image.BufferedImageOp;
-import java.awt.image.ColorConvertOp;
-import java.awt.image.ColorModel;
-import java.awt.image.ConvolveOp;
-import java.awt.image.ImagingOpException;
-import java.awt.image.IndexColorModel;
-import java.awt.image.Kernel;
-import java.awt.image.RasterFormatException;
-import java.awt.image.RescaleOp;
-
-import javax.imageio.ImageIO;
-
-/**
- * Class used to implement performant, high-quality and intelligent image
- * scaling and manipulation algorithms in native Java 2D.
- *
- * This class utilizes the Java2D "best practices" for image manipulation,
- * ensuring that all operations (even most user-provided {@link BufferedImageOp}
- * s) are hardware accelerated if provided by the platform and host-VM.
- *
- * Image Quality
- * This class implements a few different methods for scaling an image, providing
- * either the best-looking result, the fastest result or a balanced result
- * between the two depending on the scaling hint provided (see {@link Method}).
- *
- * This class also implements an optimized version of the incremental scaling
- * algorithm presented by Chris Campbell in his Perils of
- * Image.getScaledInstance() article in order to give the best-looking image
- * resize results (e.g. generating thumbnails that aren't blurry or jagged).
- *
- * The results generated by imgscalr using this method, as compared to a single
- * {@link RenderingHints#VALUE_INTERPOLATION_BICUBIC} scale operation look much
- * better, especially when using the {@link Method#ULTRA_QUALITY} method.
- *
- * Only when scaling using the {@link Method#AUTOMATIC} method will this class
- * look at the size of the image before selecting an approach to scaling the
- * image. If {@link Method#QUALITY} is specified, the best-looking algorithm
- * possible is always used.
- *
- * Minor modifications are made to Campbell's original implementation in the
- * form of:
- *
- * Instead of accepting a user-supplied interpolation method,
- * {@link RenderingHints#VALUE_INTERPOLATION_BICUBIC} interpolation is always
- * used. This was done after A/B comparison testing with large images
- * down-scaled to thumbnail sizes showed noticeable "blurring" when BILINEAR
- * interpolation was used. Given that Campbell's algorithm is only used in
- * QUALITY mode when down-scaling, it was determined that the user's expectation
- * of a much less blurry picture would require that BICUBIC be the default
- * interpolation in order to meet the QUALITY expectation.
- * After each iteration of the do-while loop that incrementally scales the
- * source image down, an explicit effort is made to call
- * {@link BufferedImage#flush()} on the interim temporary {@link BufferedImage}
- * instances created by the algorithm in an attempt to ensure a more complete GC
- * cycle by the VM when cleaning up the temporary instances (this is in addition
- * to disposing of the temporary {@link Graphics2D} references as well).
- * Extensive comments have been added to increase readability of the code.
- * Variable names have been expanded to increase readability of the code.
- *
- *
- * NOTE : This class does not call {@link BufferedImage#flush()}
- * on any of the source images passed in by calling code; it is up to
- * the original caller to dispose of their source images when they are no longer
- * needed so the VM can most efficiently GC them.
- * Image Proportions
- * All scaling operations implemented by this class maintain the proportions of
- * the original image unless a mode of {@link Mode#FIT_EXACT} is specified; in
- * which case the orientation and proportion of the source image is ignored and
- * the image is stretched (if necessary) to fit the exact dimensions given.
- *
- * When not using {@link Mode#FIT_EXACT}, in order to maintain the
- * proportionality of the original images, this class implements the following
- * behavior:
- *
- * If the image is LANDSCAPE-oriented or SQUARE, treat the
- * targetWidth
as the primary dimension and re-calculate the
- * targetHeight
regardless of what is passed in.
- * If image is PORTRAIT-oriented, treat the targetHeight
as the
- * primary dimension and re-calculate the targetWidth
regardless of
- * what is passed in.
- * If a {@link Mode} value of {@link Mode#FIT_TO_WIDTH} or
- * {@link Mode#FIT_TO_HEIGHT} is passed in to the resize
method,
- * the image's orientation is ignored and the scaled image is fit to the
- * preferred dimension by using the value passed in by the user for that
- * dimension and recalculating the other (regardless of image orientation). This
- * is useful, for example, when working with PORTRAIT oriented images that you
- * need to all be the same width or visa-versa (e.g. showing user profile
- * pictures in a directory listing).
- *
- * Optimized Image Handling
- * Java2D provides support for a number of different image types defined as
- * BufferedImage.TYPE_*
variables, unfortunately not all image
- * types are supported equally in the Java2D rendering pipeline.
- *
- * Some more obscure image types either have poor or no support, leading to
- * severely degraded quality and processing performance when an attempt is made
- * by imgscalr to create a scaled instance of the same type as the
- * source image. In many cases, especially when applying {@link BufferedImageOp}
- * s, using poorly supported image types can even lead to exceptions or total
- * corruption of the image (e.g. solid black image).
- *
- * imgscalr specifically accounts for and automatically hands
- * ALL of these pain points for you internally by shuffling all
- * images into one of two types:
- *
- * {@link BufferedImage#TYPE_INT_RGB}
- * {@link BufferedImage#TYPE_INT_ARGB}
- *
- * depending on if the source image utilizes transparency or not. This is a
- * recommended approach by the Java2D team for dealing with poorly (or non)
- * supported image types. More can be read about this issue here .
- *
- * This is also the reason we recommend using
- * {@link #apply(BufferedImage, BufferedImageOp...)} to apply your own ops to
- * images even if you aren't using imgscalr for anything else.
- * GIF Transparency
- * Unfortunately in Java 6 and earlier, support for GIF's
- * {@link IndexColorModel} is sub-par, both in accurate color-selection and in
- * maintaining transparency when moving to an image of type
- * {@link BufferedImage#TYPE_INT_ARGB}; because of this issue when a GIF image
- * is processed by imgscalr and the result saved as a GIF file (instead of PNG),
- * it is possible to lose the alpha channel of a transparent image or in the
- * case of applying an optional {@link BufferedImageOp}, lose the entire picture
- * all together in the result (long standing JDK bugs are filed for all of these
- * issues).
- *
- * imgscalr currently does nothing to work around this manually because it is a
- * defect in the native platform code itself. Fortunately it looks like the
- * issues are half-fixed in Java 7 and any manual workarounds we could attempt
- * internally are relatively expensive, in the form of hand-creating and setting
- * RGB values pixel-by-pixel with a custom {@link ColorModel} in the scaled
- * image. This would lead to a very measurable negative impact on performance
- * without the caller understanding why.
- *
- * Workaround : A workaround to this issue with all version of
- * Java is to simply save a GIF as a PNG; no change to your code needs to be
- * made except when the image is saved out, e.g. using {@link ImageIO}.
- *
- * When a file type of "PNG" is used, both the transparency and high color
- * quality will be maintained as the PNG code path in Java2D is superior to the
- * GIF implementation.
- *
- * If the issue with optional {@link BufferedImageOp}s destroying GIF image
- * content is ever fixed in the platform, saving out resulting images as GIFs
- * should suddenly start working.
- *
- * More can be read about the issue here and here .
- *
Thread Safety
- * The {@link Scalr} class is thread-safe (as all the methods
- * are static
); this class maintains no internal state while
- * performing any of the provided operations and is safe to call simultaneously
- * from multiple threads.
- * Logging
- * This class implements all its debug logging via the
- * {@link #log(int, String, Object...)} method. At this time logging is done
- * directly to System.out
via the printf
method. This
- * allows the logging to be light weight and easy to capture (every imgscalr log
- * message is prefixed with the {@link #LOG_PREFIX} string) while adding no
- * dependencies to the library.
- *
- * Implementation of logging in this class is as efficient as possible; avoiding
- * any calls to the logger method or passing of arguments if logging is not
- * enabled to avoid the (hidden) cost of constructing the Object[] argument for
- * the varargs-based method call.
- *
- * @author Riyad Kalla (software@thebuzzmedia.com)
- * @since 1.1
- */
-public class Scalr {
- /**
- * System property name used to define the debug boolean flag.
- *
- * Value is "imgscalr.debug
".
- */
- public static final String DEBUG_PROPERTY_NAME = "imgscalr.debug";
-
- /**
- * System property name used to define a custom log prefix.
- *
- * Value is "imgscalr.logPrefix
".
- */
- public static final String LOG_PREFIX_PROPERTY_NAME = "imgscalr.logPrefix";
-
- /**
- * Flag used to indicate if debugging output has been enabled by setting the
- * "imgscalr.debug
" system property to true
. This
- * value will be false
if the "imgscalr.debug
"
- * system property is undefined or set to false
.
- *
- * This property can be set on startup with:
- *
- * -Dimgscalr.debug=true
- *
or by calling {@link System#setProperty(String, String)} to set a
- * new property value for {@link #DEBUG_PROPERTY_NAME} before this class is
- * loaded.
- *
- * Default value is false
.
- */
- public static final boolean DEBUG = Boolean.getBoolean(DEBUG_PROPERTY_NAME);
-
- /**
- * Prefix to every log message this library logs. Using a well-defined
- * prefix helps make it easier both visually and programmatically to scan
- * log files for messages produced by this library.
- *
- * This property can be set on startup with:
- *
- * -Dimgscalr.logPrefix=<YOUR PREFIX HERE>
- *
or by calling {@link System#setProperty(String, String)} to set a
- * new property value for {@link #LOG_PREFIX_PROPERTY_NAME} before this
- * class is loaded.
- *
- * Default value is "[imgscalr]
" (including the space).
- */
- public static final String LOG_PREFIX = System.getProperty(
- LOG_PREFIX_PROPERTY_NAME, "[imgscalr] ");
-
- /**
- * A {@link ConvolveOp} using a very light "blur" kernel that acts like an
- * anti-aliasing filter (softens the image a bit) when applied to an image.
- *
- * A common request by users of the library was that they wished to "soften"
- * resulting images when scaling them down drastically. After quite a bit of
- * A/B testing, the kernel used by this Op was selected as the closest match
- * for the target which was the softer results from the deprecated
- * {@link AreaAveragingScaleFilter} (which is used internally by the
- * deprecated {@link Image#getScaledInstance(int, int, int)} method in the
- * JDK that imgscalr is meant to replace).
- *
- * This ConvolveOp uses a 3x3 kernel with the values:
- *
- *
- * .0f
- * .08f
- * .0f
- *
- *
- * .08f
- * .68f
- * .08f
- *
- *
- * .0f
- * .08f
- * .0f
- *
- *
- *
- * For those that have worked with ConvolveOps before, this Op uses the
- * {@link ConvolveOp#EDGE_NO_OP} instruction to not process the pixels along
- * the very edge of the image (otherwise EDGE_ZERO_FILL would create a
- * black-border around the image). If you have not worked with a ConvolveOp
- * before, it just means this default OP will "do the right thing" and not
- * give you garbage results.
- *
- * This ConvolveOp uses no {@link RenderingHints} values as internally the
- * {@link ConvolveOp} class only uses hints when doing a color conversion
- * between the source and destination {@link BufferedImage} targets.
- * imgscalr allows the {@link ConvolveOp} to create its own destination
- * image every time, so no color conversion is ever needed and thus no
- * hints.
- * Performance
- * Use of this (and other) {@link ConvolveOp}s are hardware accelerated when
- * possible. For more information on if your image op is hardware
- * accelerated or not, check the source code of the underlying JDK class
- * that actually executes the Op code, sun.awt.image.ImagingLib .
- * Known Issues
- * In all versions of Java (tested up to Java 7 preview Build 131), running
- * this op against a GIF with transparency and attempting to save the
- * resulting image as a GIF results in a corrupted/empty file. The file must
- * be saved out as a PNG to maintain the transparency.
- *
- * @since 3.0
- */
- public static final ConvolveOp OP_ANTIALIAS = new ConvolveOp(
- new Kernel(3, 3, new float[]{.0f, .08f, .0f, .08f, .68f, .08f,
- .0f, .08f, .0f}), ConvolveOp.EDGE_NO_OP, null);
-
- /**
- * A {@link RescaleOp} used to make any input image 10% darker.
- *
- * This operation can be applied multiple times in a row if greater than 10%
- * changes in brightness are desired.
- *
- * @since 4.0
- */
- public static final RescaleOp OP_DARKER = new RescaleOp(0.9f, 0, null);
-
- /**
- * A {@link RescaleOp} used to make any input image 10% brighter.
- *
- * This operation can be applied multiple times in a row if greater than 10%
- * changes in brightness are desired.
- *
- * @since 4.0
- */
- public static final RescaleOp OP_BRIGHTER = new RescaleOp(1.1f, 0, null);
-
- /**
- * A {@link ColorConvertOp} used to convert any image to a grayscale color
- * palette.
- *
- * Applying this op multiple times to the same image has no compounding
- * effects.
- *
- * @since 4.0
- */
- public static final ColorConvertOp OP_GRAYSCALE = new ColorConvertOp(
- ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
-
- /**
- * Static initializer used to prepare some of the variables used by this
- * class.
- */
- static {
- log(0, "Debug output ENABLED");
- }
-
- /**
- * Used to define the different scaling hints that the algorithm can use.
- *
- * @author Riyad Kalla (software@thebuzzmedia.com)
- * @since 1.1
- */
- public static enum Method {
- /**
- * Used to indicate that the scaling implementation should decide which
- * method to use in order to get the best looking scaled image in the
- * least amount of time.
- *
- * The scaling algorithm will use the
- * {@link Scalr#THRESHOLD_QUALITY_BALANCED} or
- * {@link Scalr#THRESHOLD_BALANCED_SPEED} thresholds as cut-offs to
- * decide between selecting the QUALITY
,
- * BALANCED
or SPEED
scaling algorithms.
- *
- * By default the thresholds chosen will give nearly the best looking
- * result in the fastest amount of time. We intend this method to work
- * for 80% of people looking to scale an image quickly and get a good
- * looking result.
- */
- AUTOMATIC,
- /**
- * Used to indicate that the scaling implementation should scale as fast
- * as possible and return a result. For smaller images (800px in size)
- * this can result in noticeable aliasing but it can be a few magnitudes
- * times faster than using the QUALITY method.
- */
- SPEED,
- /**
- * Used to indicate that the scaling implementation should use a scaling
- * operation balanced between SPEED and QUALITY. Sometimes SPEED looks
- * too low quality to be useful (e.g. text can become unreadable when
- * scaled using SPEED) but using QUALITY mode will increase the
- * processing time too much. This mode provides a "better than SPEED"
- * quality in a "less than QUALITY" amount of time.
- */
- BALANCED,
- /**
- * Used to indicate that the scaling implementation should do everything
- * it can to create as nice of a result as possible. This approach is
- * most important for smaller pictures (800px or smaller) and less
- * important for larger pictures as the difference between this method
- * and the SPEED method become less and less noticeable as the
- * source-image size increases. Using the AUTOMATIC method will
- * automatically prefer the QUALITY method when scaling an image down
- * below 800px in size.
- */
- QUALITY,
- /**
- * Used to indicate that the scaling implementation should go above and
- * beyond the work done by {@link Method#QUALITY} to make the image look
- * exceptionally good at the cost of more processing time. This is
- * especially evident when generating thumbnails of images that look
- * jagged with some of the other {@link Method}s (even
- * {@link Method#QUALITY}).
- */
- ULTRA_QUALITY;
- }
-
- /**
- * Used to define the different modes of resizing that the algorithm can
- * use.
- *
- * @author Riyad Kalla (software@thebuzzmedia.com)
- * @since 3.1
- */
- public static enum Mode {
- /**
- * Used to indicate that the scaling implementation should calculate
- * dimensions for the resultant image by looking at the image's
- * orientation and generating proportional dimensions that best fit into
- * the target width and height given
- *
- * See "Image Proportions" in the {@link Scalr} class description for
- * more detail.
- */
- AUTOMATIC,
- /**
- * Used to fit the image to the exact dimensions given regardless of the
- * image's proportions. If the dimensions are not proportionally
- * correct, this will introduce vertical or horizontal stretching to the
- * image.
- *
- * It is recommended that you use one of the other FIT_TO
- * modes or {@link Mode#AUTOMATIC} if you want the image to look
- * correct, but if dimension-fitting is the #1 priority regardless of
- * how it makes the image look, that is what this mode is for.
- */
- FIT_EXACT,
- /**
- * Used to indicate that the scaling implementation should calculate
- * dimensions for the largest image that fit within the bounding box,
- * without cropping or distortion, retaining the original proportions.
- */
- BEST_FIT_BOTH,
- /**
- * Used to indicate that the scaling implementation should calculate
- * dimensions for the resultant image that best-fit within the given
- * width, regardless of the orientation of the image.
- */
- FIT_TO_WIDTH,
- /**
- * Used to indicate that the scaling implementation should calculate
- * dimensions for the resultant image that best-fit within the given
- * height, regardless of the orientation of the image.
- */
- FIT_TO_HEIGHT;
- }
-
- /**
- * Used to define the different types of rotations that can be applied to an
- * image during a resize operation.
- *
- * @author Riyad Kalla (software@thebuzzmedia.com)
- * @since 3.2
- */
- public static enum Rotation {
- /**
- * 90-degree, clockwise rotation (to the right). This is equivalent to a
- * quarter-turn of the image to the right; moving the picture on to its
- * right side.
- */
- CW_90,
- /**
- * 180-degree, clockwise rotation (to the right). This is equivalent to
- * 1 half-turn of the image to the right; rotating the picture around
- * until it is upside down from the original position.
- */
- CW_180,
- /**
- * 270-degree, clockwise rotation (to the right). This is equivalent to
- * a quarter-turn of the image to the left; moving the picture on to its
- * left side.
- */
- CW_270,
- /**
- * Flip the image horizontally by reflecting it around the y axis.
- *
- * This is not a standard rotation around a center point, but instead
- * creates the mirrored reflection of the image horizontally.
- *
- * More specifically, the vertical orientation of the image stays the
- * same (the top stays on top, and the bottom on bottom), but the right
- * and left sides flip. This is different than a standard rotation where
- * the top and bottom would also have been flipped.
- */
- FLIP_HORZ,
- /**
- * Flip the image vertically by reflecting it around the x axis.
- *
- * This is not a standard rotation around a center point, but instead
- * creates the mirrored reflection of the image vertically.
- *
- * More specifically, the horizontal orientation of the image stays the
- * same (the left stays on the left and the right stays on the right),
- * but the top and bottom sides flip. This is different than a standard
- * rotation where the left and right would also have been flipped.
- */
- FLIP_VERT;
- }
-
- /**
- * Threshold (in pixels) at which point the scaling operation using the
- * {@link Method#AUTOMATIC} method will decide if a {@link Method#BALANCED}
- * method will be used (if smaller than or equal to threshold) or a
- * {@link Method#SPEED} method will be used (if larger than threshold).
- *
- * The bigger the image is being scaled to, the less noticeable degradations
- * in the image becomes and the faster algorithms can be selected.
- *
- * The value of this threshold (1600) was chosen after visual, by-hand, A/B
- * testing between different types of images scaled with this library; both
- * photographs and screenshots. It was determined that images below this
- * size need to use a {@link Method#BALANCED} scale method to look decent in
- * most all cases while using the faster {@link Method#SPEED} method for
- * images bigger than this threshold showed no noticeable degradation over a
- * BALANCED
scale.
- */
- public static final int THRESHOLD_BALANCED_SPEED = 1600;
-
- /**
- * Threshold (in pixels) at which point the scaling operation using the
- * {@link Method#AUTOMATIC} method will decide if a {@link Method#QUALITY}
- * method will be used (if smaller than or equal to threshold) or a
- * {@link Method#BALANCED} method will be used (if larger than threshold).
- *
- * The bigger the image is being scaled to, the less noticeable degradations
- * in the image becomes and the faster algorithms can be selected.
- *
- * The value of this threshold (800) was chosen after visual, by-hand, A/B
- * testing between different types of images scaled with this library; both
- * photographs and screenshots. It was determined that images below this
- * size need to use a {@link Method#QUALITY} scale method to look decent in
- * most all cases while using the faster {@link Method#BALANCED} method for
- * images bigger than this threshold showed no noticeable degradation over a
- * QUALITY
scale.
- */
- public static final int THRESHOLD_QUALITY_BALANCED = 800;
-
- /**
- * Used to apply, in the order given, 1 or more {@link BufferedImageOp}s to
- * a given {@link BufferedImage} and return the result.
- *
- * Feature : This implementation works around a
- * decade-old JDK bug that can cause a {@link RasterFormatException}
- * when applying a perfectly valid {@link BufferedImageOp}s to images.
- *
- * Feature : This implementation also works around
- * {@link BufferedImageOp}s failing to apply and throwing
- * {@link ImagingOpException}s when run against a src
image
- * type that is poorly supported. Unfortunately using {@link ImageIO} and
- * standard Java methods to load images provides no consistency in getting
- * images in well-supported formats. This method automatically accounts and
- * corrects for all those problems (if necessary).
- *
- * It is recommended you always use this method to apply any
- * {@link BufferedImageOp}s instead of relying on directly using the
- * {@link BufferedImageOp#filter(BufferedImage, BufferedImage)} method.
- *
- * Performance : Not all {@link BufferedImageOp}s are
- * hardware accelerated operations, but many of the most popular (like
- * {@link ConvolveOp}) are. For more information on if your image op is
- * hardware accelerated or not, check the source code of the underlying JDK
- * class that actually executes the Op code, sun.awt.image.ImagingLib .
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image that will have the ops applied to it.
- * @param ops 1
or more ops to apply to the image.
- * @return a new {@link BufferedImage} that represents the src
- * with all the given operations applied to it.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if ops
is null
or empty.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- */
- public static BufferedImage apply(BufferedImage src, BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- long t = -1;
- if (DEBUG)
- t = System.currentTimeMillis();
-
- if (src == null)
- throw new IllegalArgumentException("src cannot be null");
- if (ops == null || ops.length == 0)
- throw new IllegalArgumentException("ops cannot be null or empty");
-
- int type = src.getType();
-
- /*
- * Ensure the src image is in the best supported image type before we
- * continue, otherwise it is possible our calls below to getBounds2D and
- * certainly filter(...) may fail if not.
- *
- * Java2D makes an attempt at applying most BufferedImageOps using
- * hardware acceleration via the ImagingLib internal library.
- *
- * Unfortunately may of the BufferedImageOp are written to simply fail
- * with an ImagingOpException if the operation cannot be applied with no
- * additional information about what went wrong or attempts at
- * re-applying it in different ways.
- *
- * This is assuming the failing BufferedImageOp even returns a null
- * image after failing to apply; some simply return a corrupted/black
- * image that result in no exception and it is up to the user to
- * discover this.
- *
- * In internal testing, EVERY failure I've ever seen was the result of
- * the source image being in a poorly-supported BufferedImage Type like
- * BGR or ABGR (even though it was loaded with ImageIO).
- *
- * To avoid this nasty/stupid surprise with BufferedImageOps, we always
- * ensure that the src image starts in an optimally supported format
- * before we try and apply the filter.
- */
- if (!(type == BufferedImage.TYPE_INT_RGB || type == BufferedImage.TYPE_INT_ARGB))
- src = copyToOptimalImage(src);
-
- if (DEBUG)
- log(0, "Applying %d BufferedImageOps...", ops.length);
-
- boolean hasReassignedSrc = false;
-
- for (int i = 0; i < ops.length; i++) {
- long subT = -1;
- if (DEBUG)
- subT = System.currentTimeMillis();
- BufferedImageOp op = ops[i];
-
- // Skip null ops instead of throwing an exception.
- if (op == null)
- continue;
-
- if (DEBUG)
- log(1, "Applying BufferedImageOp [class=%s, toString=%s]...",
- op.getClass(), op.toString());
-
- /*
- * Must use op.getBounds instead of src.getWidth and src.getHeight
- * because we are trying to create an image big enough to hold the
- * result of this operation (which may be to scale the image
- * smaller), in that case the bounds reported by this op and the
- * bounds reported by the source image will be different.
- */
- Rectangle2D resultBounds = op.getBounds2D(src);
-
- // Watch out for flaky/misbehaving ops that fail to work right.
- if (resultBounds == null)
- throw new ImagingOpException(
- "BufferedImageOp ["
- + op.toString()
- + "] getBounds2D(src) returned null bounds for the target image; this should not happen and indicates a problem with application of this type of op.");
-
- /*
- * We must manually create the target image; we cannot rely on the
- * null-destination filter() method to create a valid destination
- * for us thanks to this JDK bug that has been filed for almost a
- * decade:
- * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4965606
- */
- BufferedImage dest = createOptimalImage(src,
- (int) Math.round(resultBounds.getWidth()),
- (int) Math.round(resultBounds.getHeight()));
-
- // Perform the operation, update our result to return.
- BufferedImage result = op.filter(src, dest);
-
- /*
- * Flush the 'src' image ONLY IF it is one of our interim temporary
- * images being used when applying 2 or more operations back to
- * back. We never want to flush the original image passed in.
- */
- if (hasReassignedSrc)
- src.flush();
-
- /*
- * Incase there are more operations to perform, update what we
- * consider the 'src' reference to our last result so on the next
- * iteration the next op is applied to this result and not back
- * against the original src passed in.
- */
- src = result;
-
- /*
- * Keep track of when we re-assign 'src' to an interim temporary
- * image, so we know when we can explicitly flush it and clean up
- * references on future iterations.
- */
- hasReassignedSrc = true;
-
- if (DEBUG)
- log(1,
- "Applied BufferedImageOp in %d ms, result [width=%d, height=%d]",
- System.currentTimeMillis() - subT, result.getWidth(),
- result.getHeight());
- }
-
- if (DEBUG)
- log(0, "All %d BufferedImageOps applied in %d ms", ops.length,
- System.currentTimeMillis() - t);
-
- return src;
- }
-
- /**
- * Used to crop the given src
image from the top-left corner
- * and applying any optional {@link BufferedImageOp}s to the result before
- * returning it.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image to crop.
- * @param width The width of the bounding cropping box.
- * @param height The height of the bounding cropping box.
- * @param ops 0
or more ops to apply to the image. If
- * null
or empty then src
is return
- * unmodified.
- * @return a new {@link BufferedImage} representing the cropped region of
- * the src
image with any optional operations applied
- * to it.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if any coordinates of the bounding crop box is invalid within
- * the bounds of the src
image (e.g. negative or
- * too big).
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- */
- public static BufferedImage crop(BufferedImage src, int width, int height,
- BufferedImageOp... ops) throws IllegalArgumentException,
- ImagingOpException {
- return crop(src, 0, 0, width, height, ops);
- }
-
- /**
- * Used to crop the given src
image and apply any optional
- * {@link BufferedImageOp}s to it before returning the result.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image to crop.
- * @param x The x-coordinate of the top-left corner of the bounding box
- * used for cropping.
- * @param y The y-coordinate of the top-left corner of the bounding box
- * used for cropping.
- * @param width The width of the bounding cropping box.
- * @param height The height of the bounding cropping box.
- * @param ops 0
or more ops to apply to the image. If
- * null
or empty then src
is return
- * unmodified.
- * @return a new {@link BufferedImage} representing the cropped region of
- * the src
image with any optional operations applied
- * to it.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if any coordinates of the bounding crop box is invalid within
- * the bounds of the src
image (e.g. negative or
- * too big).
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- */
- public static BufferedImage crop(BufferedImage src, int x, int y,
- int width, int height, BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- long t = -1;
- if (DEBUG)
- t = System.currentTimeMillis();
-
- if (src == null)
- throw new IllegalArgumentException("src cannot be null");
- if (x < 0 || y < 0 || width < 0 || height < 0)
- throw new IllegalArgumentException("Invalid crop bounds: x [" + x
- + "], y [" + y + "], width [" + width + "] and height ["
- + height + "] must all be >= 0");
-
- int srcWidth = src.getWidth();
- int srcHeight = src.getHeight();
-
- if ((x + width) > srcWidth)
- throw new IllegalArgumentException(
- "Invalid crop bounds: x + width [" + (x + width)
- + "] must be <= src.getWidth() [" + srcWidth + "]");
- if ((y + height) > srcHeight)
- throw new IllegalArgumentException(
- "Invalid crop bounds: y + height [" + (y + height)
- + "] must be <= src.getHeight() [" + srcHeight
- + "]");
-
- if (DEBUG)
- log(0,
- "Cropping Image [width=%d, height=%d] to [x=%d, y=%d, width=%d, height=%d]...",
- srcWidth, srcHeight, x, y, width, height);
-
- // Create a target image of an optimal type to render into.
- BufferedImage result = createOptimalImage(src, width, height);
- Graphics g = result.getGraphics();
-
- /*
- * Render the region specified by our crop bounds from the src image
- * directly into our result image (which is the exact size of the crop
- * region).
- */
- g.drawImage(src, 0, 0, width, height, x, y, (x + width), (y + height),
- null);
- g.dispose();
-
- if (DEBUG)
- log(0, "Cropped Image in %d ms", System.currentTimeMillis() - t);
-
- // Apply any optional operations (if specified).
- if (ops != null && ops.length > 0)
- result = apply(result, ops);
-
- return result;
- }
-
- /**
- * Used to apply padding around the edges of an image using
- * {@link Color#BLACK} to fill the extra padded space and then return the
- * result.
- *
- * The amount of padding
specified is applied to all sides;
- * more specifically, a padding
of 2
would add 2
- * extra pixels of space (filled by the given color
) on the
- * top, bottom, left and right sides of the resulting image causing the
- * result to be 4 pixels wider and 4 pixels taller than the src
- * image.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image the padding will be added to.
- * @param padding The number of pixels of padding to add to each side in the
- * resulting image. If this value is 0
then
- * src
is returned unmodified.
- * @param ops 0
or more ops to apply to the image. If
- * null
or empty then src
is return
- * unmodified.
- * @return a new {@link BufferedImage} representing src
with
- * the given padding applied to it.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if padding
is < 1
.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- */
- public static BufferedImage pad(BufferedImage src, int padding,
- BufferedImageOp... ops) throws IllegalArgumentException,
- ImagingOpException {
- return pad(src, padding, Color.BLACK);
- }
-
- /**
- * Used to apply padding around the edges of an image using the given color
- * to fill the extra padded space and then return the result. {@link Color}s
- * using an alpha channel (i.e. transparency) are supported.
- *
- * The amount of padding
specified is applied to all sides;
- * more specifically, a padding
of 2
would add 2
- * extra pixels of space (filled by the given color
) on the
- * top, bottom, left and right sides of the resulting image causing the
- * result to be 4 pixels wider and 4 pixels taller than the src
- * image.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image the padding will be added to.
- * @param padding The number of pixels of padding to add to each side in the
- * resulting image. If this value is 0
then
- * src
is returned unmodified.
- * @param color The color to fill the padded space with. {@link Color}s using
- * an alpha channel (i.e. transparency) are supported.
- * @param ops 0
or more ops to apply to the image. If
- * null
or empty then src
is return
- * unmodified.
- * @return a new {@link BufferedImage} representing src
with
- * the given padding applied to it.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if padding
is < 1
.
- * @throws IllegalArgumentException if color
is null
.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- */
- public static BufferedImage pad(BufferedImage src, int padding,
- Color color, BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- long t = -1;
- if (DEBUG)
- t = System.currentTimeMillis();
-
- if (src == null)
- throw new IllegalArgumentException("src cannot be null");
- if (padding < 1)
- throw new IllegalArgumentException("padding [" + padding
- + "] must be > 0");
- if (color == null)
- throw new IllegalArgumentException("color cannot be null");
-
- int srcWidth = src.getWidth();
- int srcHeight = src.getHeight();
-
- /*
- * Double the padding to account for all sides of the image. More
- * specifically, if padding is "1" we add 2 pixels to width and 2 to
- * height, so we have 1 new pixel of padding all the way around our
- * image.
- */
- int sizeDiff = (padding * 2);
- int newWidth = srcWidth + sizeDiff;
- int newHeight = srcHeight + sizeDiff;
-
- if (DEBUG)
- log(0,
- "Padding Image from [originalWidth=%d, originalHeight=%d, padding=%d] to [newWidth=%d, newHeight=%d]...",
- srcWidth, srcHeight, padding, newWidth, newHeight);
-
- boolean colorHasAlpha = (color.getAlpha() != 255);
- boolean imageHasAlpha = (src.getTransparency() != BufferedImage.OPAQUE);
-
- BufferedImage result;
-
- /*
- * We need to make sure our resulting image that we render into contains
- * alpha if either our original image OR the padding color we are using
- * contain it.
- */
- if (colorHasAlpha || imageHasAlpha) {
- if (DEBUG)
- log(1,
- "Transparency FOUND in source image or color, using ARGB image type...");
-
- result = new BufferedImage(newWidth, newHeight,
- BufferedImage.TYPE_INT_ARGB);
- } else {
- if (DEBUG)
- log(1,
- "Transparency NOT FOUND in source image or color, using RGB image type...");
-
- result = new BufferedImage(newWidth, newHeight,
- BufferedImage.TYPE_INT_RGB);
- }
-
- Graphics g = result.getGraphics();
-
- // "Clear" the background of the new image with our padding color first.
- g.setColor(color);
- g.fillRect(0, 0, newWidth, newHeight);
-
- // Draw the image into the center of the new padded image.
- g.drawImage(src, padding, padding, null);
- g.dispose();
-
- if (DEBUG)
- log(0, "Padding Applied in %d ms", System.currentTimeMillis() - t);
-
- // Apply any optional operations (if specified).
- if (ops != null && ops.length > 0)
- result = apply(result, ops);
-
- return result;
- }
-
- /**
- * Resize a given image (maintaining its original proportion) to a width and
- * height no bigger than targetSize
and apply the given
- * {@link BufferedImageOp}s (if any) to the result before returning it.
- *
- * A scaling method of {@link Method#AUTOMATIC} and mode of
- * {@link Mode#AUTOMATIC} are used.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image that will be scaled.
- * @param targetSize The target width and height (square) that you wish the image
- * to fit within.
- * @param ops 0
or more optional image operations (e.g.
- * sharpen, blur, etc.) that can be applied to the final result
- * before returning the image.
- * @return a new {@link BufferedImage} representing the scaled
- * src
image.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if targetSize
is < 0.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- */
- public static BufferedImage resize(BufferedImage src, int targetSize,
- BufferedImageOp... ops) throws IllegalArgumentException,
- ImagingOpException {
- return resize(src, Method.AUTOMATIC, Mode.AUTOMATIC, targetSize,
- targetSize, ops);
- }
-
- /**
- * Resize a given image (maintaining its original proportion) to a width and
- * height no bigger than targetSize
using the given scaling
- * method and apply the given {@link BufferedImageOp}s (if any) to the
- * result before returning it.
- *
- * A mode of {@link Mode#AUTOMATIC} is used.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image that will be scaled.
- * @param scalingMethod The method used for scaling the image; preferring speed to
- * quality or a balance of both.
- * @param targetSize The target width and height (square) that you wish the image
- * to fit within.
- * @param ops 0
or more optional image operations (e.g.
- * sharpen, blur, etc.) that can be applied to the final result
- * before returning the image.
- * @return a new {@link BufferedImage} representing the scaled
- * src
image.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if scalingMethod
is null
.
- * @throws IllegalArgumentException if targetSize
is < 0.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- * @see Method
- */
- public static BufferedImage resize(BufferedImage src, Method scalingMethod,
- int targetSize, BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- return resize(src, scalingMethod, Mode.AUTOMATIC, targetSize,
- targetSize, ops);
- }
-
- /**
- * Resize a given image (maintaining its original proportion) to a width and
- * height no bigger than targetSize
(or fitting the image to
- * the given WIDTH or HEIGHT explicitly, depending on the {@link Mode}
- * specified) and apply the given {@link BufferedImageOp}s (if any) to the
- * result before returning it.
- *
- * A scaling method of {@link Method#AUTOMATIC} is used.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image that will be scaled.
- * @param resizeMode Used to indicate how imgscalr should calculate the final
- * target size for the image, either fitting the image to the
- * given width ({@link Mode#FIT_TO_WIDTH}) or fitting the image
- * to the given height ({@link Mode#FIT_TO_HEIGHT}). If
- * {@link Mode#AUTOMATIC} is passed in, imgscalr will calculate
- * proportional dimensions for the scaled image based on its
- * orientation (landscape, square or portrait). Unless you have
- * very specific size requirements, most of the time you just
- * want to use {@link Mode#AUTOMATIC} to "do the right thing".
- * @param targetSize The target width and height (square) that you wish the image
- * to fit within.
- * @param ops 0
or more optional image operations (e.g.
- * sharpen, blur, etc.) that can be applied to the final result
- * before returning the image.
- * @return a new {@link BufferedImage} representing the scaled
- * src
image.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if resizeMode
is null
.
- * @throws IllegalArgumentException if targetSize
is < 0.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- * @see Mode
- */
- public static BufferedImage resize(BufferedImage src, Mode resizeMode,
- int targetSize, BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- return resize(src, Method.AUTOMATIC, resizeMode, targetSize,
- targetSize, ops);
- }
-
- /**
- * Resize a given image (maintaining its original proportion) to a width and
- * height no bigger than targetSize
(or fitting the image to
- * the given WIDTH or HEIGHT explicitly, depending on the {@link Mode}
- * specified) using the given scaling method and apply the given
- * {@link BufferedImageOp}s (if any) to the result before returning it.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image that will be scaled.
- * @param scalingMethod The method used for scaling the image; preferring speed to
- * quality or a balance of both.
- * @param resizeMode Used to indicate how imgscalr should calculate the final
- * target size for the image, either fitting the image to the
- * given width ({@link Mode#FIT_TO_WIDTH}) or fitting the image
- * to the given height ({@link Mode#FIT_TO_HEIGHT}). If
- * {@link Mode#AUTOMATIC} is passed in, imgscalr will calculate
- * proportional dimensions for the scaled image based on its
- * orientation (landscape, square or portrait). Unless you have
- * very specific size requirements, most of the time you just
- * want to use {@link Mode#AUTOMATIC} to "do the right thing".
- * @param targetSize The target width and height (square) that you wish the image
- * to fit within.
- * @param ops 0
or more optional image operations (e.g.
- * sharpen, blur, etc.) that can be applied to the final result
- * before returning the image.
- * @return a new {@link BufferedImage} representing the scaled
- * src
image.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if scalingMethod
is null
.
- * @throws IllegalArgumentException if resizeMode
is null
.
- * @throws IllegalArgumentException if targetSize
is < 0.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- * @see Method
- * @see Mode
- */
- public static BufferedImage resize(BufferedImage src, Method scalingMethod,
- Mode resizeMode, int targetSize, BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- return resize(src, scalingMethod, resizeMode, targetSize, targetSize,
- ops);
- }
-
- /**
- * Resize a given image (maintaining its original proportion) to the target
- * width and height and apply the given {@link BufferedImageOp}s (if any) to
- * the result before returning it.
- *
- * A scaling method of {@link Method#AUTOMATIC} and mode of
- * {@link Mode#AUTOMATIC} are used.
- *
- * TIP : See the class description to understand how this
- * class handles recalculation of the targetWidth
or
- * targetHeight
depending on the image's orientation in order
- * to maintain the original proportion.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image that will be scaled.
- * @param targetWidth The target width that you wish the image to have.
- * @param targetHeight The target height that you wish the image to have.
- * @param ops 0
or more optional image operations (e.g.
- * sharpen, blur, etc.) that can be applied to the final result
- * before returning the image.
- * @return a new {@link BufferedImage} representing the scaled
- * src
image.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if targetWidth
is < 0 or if
- * targetHeight
is < 0.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- */
- public static BufferedImage resize(BufferedImage src, int targetWidth,
- int targetHeight, BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- return resize(src, Method.AUTOMATIC, Mode.AUTOMATIC, targetWidth,
- targetHeight, ops);
- }
-
- /**
- * Resize a given image (maintaining its original proportion) to the target
- * width and height using the given scaling method and apply the given
- * {@link BufferedImageOp}s (if any) to the result before returning it.
- *
- * A mode of {@link Mode#AUTOMATIC} is used.
- *
- * TIP : See the class description to understand how this
- * class handles recalculation of the targetWidth
or
- * targetHeight
depending on the image's orientation in order
- * to maintain the original proportion.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image that will be scaled.
- * @param scalingMethod The method used for scaling the image; preferring speed to
- * quality or a balance of both.
- * @param targetWidth The target width that you wish the image to have.
- * @param targetHeight The target height that you wish the image to have.
- * @param ops 0
or more optional image operations (e.g.
- * sharpen, blur, etc.) that can be applied to the final result
- * before returning the image.
- * @return a new {@link BufferedImage} representing the scaled
- * src
image.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if scalingMethod
is null
.
- * @throws IllegalArgumentException if targetWidth
is < 0 or if
- * targetHeight
is < 0.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- * @see Method
- */
- public static BufferedImage resize(BufferedImage src, Method scalingMethod,
- int targetWidth, int targetHeight, BufferedImageOp... ops) {
- return resize(src, scalingMethod, Mode.AUTOMATIC, targetWidth,
- targetHeight, ops);
- }
-
- /**
- * Resize a given image (maintaining its original proportion) to the target
- * width and height (or fitting the image to the given WIDTH or HEIGHT
- * explicitly, depending on the {@link Mode} specified) and apply the given
- * {@link BufferedImageOp}s (if any) to the result before returning it.
- *
- * A scaling method of {@link Method#AUTOMATIC} is used.
- *
- * TIP : See the class description to understand how this
- * class handles recalculation of the targetWidth
or
- * targetHeight
depending on the image's orientation in order
- * to maintain the original proportion.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image that will be scaled.
- * @param resizeMode Used to indicate how imgscalr should calculate the final
- * target size for the image, either fitting the image to the
- * given width ({@link Mode#FIT_TO_WIDTH}) or fitting the image
- * to the given height ({@link Mode#FIT_TO_HEIGHT}). If
- * {@link Mode#AUTOMATIC} is passed in, imgscalr will calculate
- * proportional dimensions for the scaled image based on its
- * orientation (landscape, square or portrait). Unless you have
- * very specific size requirements, most of the time you just
- * want to use {@link Mode#AUTOMATIC} to "do the right thing".
- * @param targetWidth The target width that you wish the image to have.
- * @param targetHeight The target height that you wish the image to have.
- * @param ops 0
or more optional image operations (e.g.
- * sharpen, blur, etc.) that can be applied to the final result
- * before returning the image.
- * @return a new {@link BufferedImage} representing the scaled
- * src
image.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if resizeMode
is null
.
- * @throws IllegalArgumentException if targetWidth
is < 0 or if
- * targetHeight
is < 0.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- * @see Mode
- */
- public static BufferedImage resize(BufferedImage src, Mode resizeMode,
- int targetWidth, int targetHeight, BufferedImageOp... ops)
- throws IllegalArgumentException, ImagingOpException {
- return resize(src, Method.AUTOMATIC, resizeMode, targetWidth,
- targetHeight, ops);
- }
-
- /**
- * Resize a given image (maintaining its original proportion) to the target
- * width and height (or fitting the image to the given WIDTH or HEIGHT
- * explicitly, depending on the {@link Mode} specified) using the given
- * scaling method and apply the given {@link BufferedImageOp}s (if any) to
- * the result before returning it.
- *
- * TIP : See the class description to understand how this
- * class handles recalculation of the targetWidth
or
- * targetHeight
depending on the image's orientation in order
- * to maintain the original proportion.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image that will be scaled.
- * @param scalingMethod The method used for scaling the image; preferring speed to
- * quality or a balance of both.
- * @param resizeMode Used to indicate how imgscalr should calculate the final
- * target size for the image, either fitting the image to the
- * given width ({@link Mode#FIT_TO_WIDTH}) or fitting the image
- * to the given height ({@link Mode#FIT_TO_HEIGHT}). If
- * {@link Mode#AUTOMATIC} is passed in, imgscalr will calculate
- * proportional dimensions for the scaled image based on its
- * orientation (landscape, square or portrait). Unless you have
- * very specific size requirements, most of the time you just
- * want to use {@link Mode#AUTOMATIC} to "do the right thing".
- * @param targetWidth The target width that you wish the image to have.
- * @param targetHeight The target height that you wish the image to have.
- * @param ops 0
or more optional image operations (e.g.
- * sharpen, blur, etc.) that can be applied to the final result
- * before returning the image.
- * @return a new {@link BufferedImage} representing the scaled
- * src
image.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if scalingMethod
is null
.
- * @throws IllegalArgumentException if resizeMode
is null
.
- * @throws IllegalArgumentException if targetWidth
is < 0 or if
- * targetHeight
is < 0.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- * @see Method
- * @see Mode
- */
- public static BufferedImage resize(BufferedImage src, Method scalingMethod,
- Mode resizeMode, int targetWidth, int targetHeight,
- BufferedImageOp... ops) throws IllegalArgumentException,
- ImagingOpException {
- long t = -1;
- if (DEBUG)
- t = System.currentTimeMillis();
-
- if (src == null)
- throw new IllegalArgumentException("src cannot be null");
- if (targetWidth < 0)
- throw new IllegalArgumentException("targetWidth must be >= 0");
- if (targetHeight < 0)
- throw new IllegalArgumentException("targetHeight must be >= 0");
- if (scalingMethod == null)
- throw new IllegalArgumentException(
- "scalingMethod cannot be null. A good default value is Method.AUTOMATIC.");
- if (resizeMode == null)
- throw new IllegalArgumentException(
- "resizeMode cannot be null. A good default value is Mode.AUTOMATIC.");
-
- BufferedImage result = null;
-
- int currentWidth = src.getWidth();
- int currentHeight = src.getHeight();
-
- // <= 1 is a square or landscape-oriented image, > 1 is a portrait.
- float ratio = ((float) currentHeight / (float) currentWidth);
-
- if (DEBUG)
- log(0,
- "Resizing Image [size=%dx%d, resizeMode=%s, orientation=%s, ratio(H/W)=%f] to [targetSize=%dx%d]",
- currentWidth, currentHeight, resizeMode,
- (ratio <= 1 ? "Landscape/Square" : "Portrait"), ratio,
- targetWidth, targetHeight);
-
- /*
- * First determine if ANY size calculation needs to be done, in the case
- * of FIT_EXACT, ignore image proportions and orientation and just use
- * what the user sent in, otherwise the proportion of the picture must
- * be honored.
- *
- * The way that is done is to figure out if the image is in a
- * LANDSCAPE/SQUARE or PORTRAIT orientation and depending on its
- * orientation, use the primary dimension (width for LANDSCAPE/SQUARE
- * and height for PORTRAIT) to recalculate the alternative (height and
- * width respectively) value that adheres to the existing ratio.
- *
- * This helps make life easier for the caller as they don't need to
- * pre-compute proportional dimensions before calling the API, they can
- * just specify the dimensions they would like the image to roughly fit
- * within and it will do the right thing without mangling the result.
- */
- if (resizeMode == Mode.FIT_EXACT) {
- if (DEBUG)
- log(1,
- "Resize Mode FIT_EXACT used, no width/height checking or re-calculation will be done.");
- } else if (resizeMode == Mode.BEST_FIT_BOTH) {
- float requestedHeightScaling = ((float) targetHeight / (float) currentHeight);
- float requestedWidthScaling = ((float) targetWidth / (float) currentWidth);
- float actualScaling = Math.min(requestedHeightScaling, requestedWidthScaling);
-
- targetHeight = Math.round((float) currentHeight * actualScaling);
- targetWidth = Math.round((float) currentWidth * actualScaling);
-
- if (targetHeight == currentHeight && targetWidth == currentWidth)
- return src;
-
- if (DEBUG)
- log(1, "Auto-Corrected width and height based on scalingRatio %d.", actualScaling);
- } else {
- if ((ratio <= 1 && resizeMode == Mode.AUTOMATIC)
- || (resizeMode == Mode.FIT_TO_WIDTH)) {
- // First make sure we need to do any work in the first place
- if (targetWidth == src.getWidth())
- return src;
-
- // Save for detailed logging (this is cheap).
- int originalTargetHeight = targetHeight;
-
- /*
- * Landscape or Square Orientation: Ignore the given height and
- * re-calculate a proportionally correct value based on the
- * targetWidth.
- */
- targetHeight = Math.round((float) targetWidth * ratio);
-
- if (DEBUG && originalTargetHeight != targetHeight)
- log(1,
- "Auto-Corrected targetHeight [from=%d to=%d] to honor image proportions.",
- originalTargetHeight, targetHeight);
- } else {
- // First make sure we need to do any work in the first place
- if (targetHeight == src.getHeight())
- return src;
-
- // Save for detailed logging (this is cheap).
- int originalTargetWidth = targetWidth;
-
- /*
- * Portrait Orientation: Ignore the given width and re-calculate
- * a proportionally correct value based on the targetHeight.
- */
- targetWidth = Math.round((float) targetHeight / ratio);
-
- if (DEBUG && originalTargetWidth != targetWidth)
- log(1,
- "Auto-Corrected targetWidth [from=%d to=%d] to honor image proportions.",
- originalTargetWidth, targetWidth);
- }
- }
-
- // If AUTOMATIC was specified, determine the real scaling method.
- if (scalingMethod == Scalr.Method.AUTOMATIC)
- scalingMethod = determineScalingMethod(targetWidth, targetHeight,
- ratio);
-
- if (DEBUG)
- log(1, "Using Scaling Method: %s", scalingMethod);
-
- // Now we scale the image
- if (scalingMethod == Scalr.Method.SPEED) {
- result = scaleImage(src, targetWidth, targetHeight,
- RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
- } else if (scalingMethod == Scalr.Method.BALANCED) {
- result = scaleImage(src, targetWidth, targetHeight,
- RenderingHints.VALUE_INTERPOLATION_BILINEAR);
- } else if (scalingMethod == Scalr.Method.QUALITY
- || scalingMethod == Scalr.Method.ULTRA_QUALITY) {
- /*
- * If we are scaling up (in either width or height - since we know
- * the image will stay proportional we just check if either are
- * being scaled up), directly using a single BICUBIC will give us
- * better results then using Chris Campbell's incremental scaling
- * operation (and take a lot less time).
- *
- * If we are scaling down, we must use the incremental scaling
- * algorithm for the best result.
- */
- if (targetWidth > currentWidth || targetHeight > currentHeight) {
- if (DEBUG)
- log(1,
- "QUALITY scale-up, a single BICUBIC scale operation will be used...");
-
- /*
- * BILINEAR and BICUBIC look similar the smaller the scale jump
- * upwards is, if the scale is larger BICUBIC looks sharper and
- * less fuzzy. But most importantly we have to use BICUBIC to
- * match the contract of the QUALITY rendering scalingMethod.
- * This note is just here for anyone reading the code and
- * wondering how they can speed their own calls up.
- */
- result = scaleImage(src, targetWidth, targetHeight,
- RenderingHints.VALUE_INTERPOLATION_BICUBIC);
- } else {
- if (DEBUG)
- log(1,
- "QUALITY scale-down, incremental scaling will be used...");
-
- /*
- * Originally we wanted to use BILINEAR interpolation here
- * because it takes 1/3rd the time that the BICUBIC
- * interpolation does, however, when scaling large images down
- * to most sizes bigger than a thumbnail we witnessed noticeable
- * "softening" in the resultant image with BILINEAR that would
- * be unexpectedly annoying to a user expecting a "QUALITY"
- * scale of their original image. Instead BICUBIC was chosen to
- * honor the contract of a QUALITY scale of the original image.
- */
- result = scaleImageIncrementally(src, targetWidth,
- targetHeight, scalingMethod,
- RenderingHints.VALUE_INTERPOLATION_BICUBIC);
- }
- }
-
- if (DEBUG)
- log(0, "Resized Image in %d ms", System.currentTimeMillis() - t);
-
- // Apply any optional operations (if specified).
- if (ops != null && ops.length > 0)
- result = apply(result, ops);
-
- return result;
- }
-
- /**
- * Used to apply a {@link Rotation} and then 0
or more
- * {@link BufferedImageOp}s to a given image and return the result.
- *
- * TIP : This operation leaves the original src
- * image unmodified. If the caller is done with the src
image
- * after getting the result of this operation, remember to call
- * {@link BufferedImage#flush()} on the src
to free up native
- * resources and make it easier for the GC to collect the unused image.
- *
- * @param src The image that will have the rotation applied to it.
- * @param rotation The rotation that will be applied to the image.
- * @param ops Zero or more optional image operations (e.g. sharpen, blur,
- * etc.) that can be applied to the final result before returning
- * the image.
- * @return a new {@link BufferedImage} representing src
rotated
- * by the given amount and any optional ops applied to it.
- * @throws IllegalArgumentException if src
is null
.
- * @throws IllegalArgumentException if rotation
is null
.
- * @throws ImagingOpException if one of the given {@link BufferedImageOp}s fails to apply.
- * These exceptions bubble up from the inside of most of the
- * {@link BufferedImageOp} implementations and are explicitly
- * defined on the imgscalr API to make it easier for callers to
- * catch the exception (if they are passing along optional ops
- * to be applied). imgscalr takes detailed steps to avoid the
- * most common pitfalls that will cause {@link BufferedImageOp}s
- * to fail, even when using straight forward JDK-image
- * operations.
- * @see Rotation
- */
- public static BufferedImage rotate(BufferedImage src, Rotation rotation,
- BufferedImageOp... ops) throws IllegalArgumentException,
- ImagingOpException {
- long t = -1;
- if (DEBUG)
- t = System.currentTimeMillis();
-
- if (src == null)
- throw new IllegalArgumentException("src cannot be null");
- if (rotation == null)
- throw new IllegalArgumentException("rotation cannot be null");
-
- if (DEBUG)
- log(0, "Rotating Image [%s]...", rotation);
-
- /*
- * Setup the default width/height values from our image.
- *
- * In the case of a 90 or 270 (-90) degree rotation, these two values
- * flip-flop and we will correct those cases down below in the switch
- * statement.
- */
- int newWidth = src.getWidth();
- int newHeight = src.getHeight();
-
- /*
- * We create a transform per operation request as (oddly enough) it ends
- * up being faster for the VM to create, use and destroy these instances
- * than it is to re-use a single AffineTransform per-thread via the
- * AffineTransform.setTo(...) methods which was my first choice (less
- * object creation); after benchmarking this explicit case and looking
- * at just how much code gets run inside of setTo() I opted for a new AT
- * for every rotation.
- *
- * Besides the performance win, trying to safely reuse AffineTransforms
- * via setTo(...) would have required ThreadLocal instances to avoid
- * race conditions where two or more resize threads are manipulating the
- * same transform before applying it.
- *
- * Misusing ThreadLocals are one of the #1 reasons for memory leaks in
- * server applications and since we have no nice way to hook into the
- * init/destroy Servlet cycle or any other initialization cycle for this
- * library to automatically call ThreadLocal.remove() to avoid the
- * memory leak, it would have made using this library *safely* on the
- * server side much harder.
- *
- * So we opt for creating individual transforms per rotation op and let
- * the VM clean them up in a GC. I only clarify all this reasoning here
- * for anyone else reading this code and being tempted to reuse the AT
- * instances of performance gains; there aren't any AND you get a lot of
- * pain along with it.
- */
- AffineTransform tx = new AffineTransform();
-
- switch (rotation) {
- case CW_90:
- /*
- * A 90 or -90 degree rotation will cause the height and width to
- * flip-flop from the original image to the rotated one.
- */
- newWidth = src.getHeight();
- newHeight = src.getWidth();
-
- // Reminder: newWidth == result.getHeight() at this point
- tx.translate(newWidth, 0);
- tx.rotate(Math.toRadians(90));
-
- break;
-
- case CW_270:
- /*
- * A 90 or -90 degree rotation will cause the height and width to
- * flip-flop from the original image to the rotated one.
- */
- newWidth = src.getHeight();
- newHeight = src.getWidth();
-
- // Reminder: newHeight == result.getWidth() at this point
- tx.translate(0, newHeight);
- tx.rotate(Math.toRadians(-90));
- break;
-
- case CW_180:
- tx.translate(newWidth, newHeight);
- tx.rotate(Math.toRadians(180));
- break;
-
- case FLIP_HORZ:
- tx.translate(newWidth, 0);
- tx.scale(-1.0, 1.0);
- break;
-
- case FLIP_VERT:
- tx.translate(0, newHeight);
- tx.scale(1.0, -1.0);
- break;
- }
-
- // Create our target image we will render the rotated result to.
- BufferedImage result = createOptimalImage(src, newWidth, newHeight);
- Graphics2D g2d = (Graphics2D) result.createGraphics();
-
- /*
- * Render the resultant image to our new rotatedImage buffer, applying
- * the AffineTransform that we calculated above during rendering so the
- * pixels from the old position are transposed to the new positions in
- * the resulting image correctly.
- */
- g2d.drawImage(src, tx, null);
- g2d.dispose();
-
- if (DEBUG)
- log(0, "Rotation Applied in %d ms, result [width=%d, height=%d]",
- System.currentTimeMillis() - t, result.getWidth(),
- result.getHeight());
-
- // Apply any optional operations (if specified).
- if (ops != null && ops.length > 0)
- result = apply(result, ops);
-
- return result;
- }
-
- /**
- * Used to write out a useful and well-formatted log message by any piece of
- * code inside of the imgscalr library.
- *
- * If a message cannot be logged (logging is disabled) then this method
- * returns immediately.
- *
- * NOTE : Because Java will auto-box primitive arguments
- * into Objects when building out the params
array, care should
- * be taken not to call this method with primitive values unless
- * {@link Scalr#DEBUG} is true
; otherwise the VM will be
- * spending time performing unnecessary auto-boxing calculations.
- *
- * @param depth The indentation level of the log message.
- * @param message The log message in format string syntax that will be logged.
- * @param params The parameters that will be swapped into all the place holders
- * in the original messages before being logged.
- * @see Scalr#LOG_PREFIX
- * @see Scalr#LOG_PREFIX_PROPERTY_NAME
- */
- protected static void log(int depth, String message, Object... params) {
- if (Scalr.DEBUG) {
- System.out.print(Scalr.LOG_PREFIX);
-
- for (int i = 0; i < depth; i++)
- System.out.print("\t");
-
- System.out.printf(message, params);
- System.out.println();
- }
- }
-
- /**
- * Used to create a {@link BufferedImage} with the most optimal RGB TYPE (
- * {@link BufferedImage#TYPE_INT_RGB} or {@link BufferedImage#TYPE_INT_ARGB}
- * ) capable of being rendered into from the given src
. The
- * width and height of both images will be identical.
- *
- * This does not perform a copy of the image data from src
into
- * the result image; see {@link #copyToOptimalImage(BufferedImage)} for
- * that.
- *
- * We force all rendering results into one of these two types, avoiding the
- * case where a source image is of an unsupported (or poorly supported)
- * format by Java2D causing the rendering result to end up looking terrible
- * (common with GIFs) or be totally corrupt (e.g. solid black image).
- *
- * Originally reported by Magnus Kvalheim from Movellas when scaling certain
- * GIF and PNG images.
- *
- * @param src The source image that will be analyzed to determine the most
- * optimal image type it can be rendered into.
- * @return a new {@link BufferedImage} representing the most optimal target
- * image type that src
can be rendered into.
- * @see How
- * Java2D handles poorly supported image types
- * @see Thanks
- * to Morten Nobel for implementation hint
- */
- protected static BufferedImage createOptimalImage(BufferedImage src) {
- return createOptimalImage(src, src.getWidth(), src.getHeight());
- }
-
- /**
- * Used to create a {@link BufferedImage} with the given dimensions and the
- * most optimal RGB TYPE ( {@link BufferedImage#TYPE_INT_RGB} or
- * {@link BufferedImage#TYPE_INT_ARGB} ) capable of being rendered into from
- * the given src
.
- *
- * This does not perform a copy of the image data from src
into
- * the result image; see {@link #copyToOptimalImage(BufferedImage)} for
- * that.
- *
- * We force all rendering results into one of these two types, avoiding the
- * case where a source image is of an unsupported (or poorly supported)
- * format by Java2D causing the rendering result to end up looking terrible
- * (common with GIFs) or be totally corrupt (e.g. solid black image).
- *
- * Originally reported by Magnus Kvalheim from Movellas when scaling certain
- * GIF and PNG images.
- *
- * @param src The source image that will be analyzed to determine the most
- * optimal image type it can be rendered into.
- * @param width The width of the newly created resulting image.
- * @param height The height of the newly created resulting image.
- * @return a new {@link BufferedImage} representing the most optimal target
- * image type that src
can be rendered into.
- * @throws IllegalArgumentException if width
or height
are < 0.
- * @see How
- * Java2D handles poorly supported image types
- * @see Thanks
- * to Morten Nobel for implementation hint
- */
- protected static BufferedImage createOptimalImage(BufferedImage src,
- int width, int height) throws IllegalArgumentException {
- if (width < 0 || height < 0)
- throw new IllegalArgumentException("width [" + width
- + "] and height [" + height + "] must be >= 0");
-
- return new BufferedImage(
- width,
- height,
- (src.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB
- : BufferedImage.TYPE_INT_ARGB));
- }
-
- /**
- * Used to copy a {@link BufferedImage} from a non-optimal type into a new
- * {@link BufferedImage} instance of an optimal type (RGB or ARGB). If
- * src
is already of an optimal type, then it is returned
- * unmodified.
- *
- * This method is meant to be used by any calling code (imgscalr's or
- * otherwise) to convert any inbound image from a poorly supported image
- * type into the 2 most well-supported image types in Java2D (
- * {@link BufferedImage#TYPE_INT_RGB} or {@link BufferedImage#TYPE_INT_ARGB}
- * ) in order to ensure all subsequent graphics operations are performed as
- * efficiently and correctly as possible.
- *
- * When using Java2D to work with image types that are not well supported,
- * the results can be anything from exceptions bubbling up from the depths
- * of Java2D to images being completely corrupted and just returned as solid
- * black.
- *
- * @param src The image to copy (if necessary) into an optimally typed
- * {@link BufferedImage}.
- * @return a representation of the src
image in an optimally
- * typed {@link BufferedImage}, otherwise src
if it was
- * already of an optimal type.
- * @throws IllegalArgumentException if src
is null
.
- */
- protected static BufferedImage copyToOptimalImage(BufferedImage src)
- throws IllegalArgumentException {
- if (src == null)
- throw new IllegalArgumentException("src cannot be null");
-
- // Calculate the type depending on the presence of alpha.
- int type = (src.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB
- : BufferedImage.TYPE_INT_ARGB);
- BufferedImage result = new BufferedImage(src.getWidth(),
- src.getHeight(), type);
-
- // Render the src image into our new optimal source.
- Graphics g = result.getGraphics();
- g.drawImage(src, 0, 0, null);
- g.dispose();
-
- return result;
- }
-
- /**
- * Used to determine the scaling {@link Method} that is best suited for
- * scaling the image to the targeted dimensions.
- *
- * This method is intended to be used to select a specific scaling
- * {@link Method} when a {@link Method#AUTOMATIC} method is specified. This
- * method utilizes the {@link Scalr#THRESHOLD_QUALITY_BALANCED} and
- * {@link Scalr#THRESHOLD_BALANCED_SPEED} thresholds when selecting which
- * method should be used by comparing the primary dimension (width or
- * height) against the threshold and seeing where the image falls. The
- * primary dimension is determined by looking at the orientation of the
- * image: landscape or square images use their width and portrait-oriented
- * images use their height.
- *
- * @param targetWidth The target width for the scaled image.
- * @param targetHeight The target height for the scaled image.
- * @param ratio A height/width ratio used to determine the orientation of the
- * image so the primary dimension (width or height) can be
- * selected to test if it is greater than or less than a
- * particular threshold.
- * @return the fastest {@link Method} suited for scaling the image to the
- * specified dimensions while maintaining a good-looking result.
- */
- protected static Method determineScalingMethod(int targetWidth,
- int targetHeight, float ratio) {
- // Get the primary dimension based on the orientation of the image
- int length = (ratio <= 1 ? targetWidth : targetHeight);
-
- // Default to speed
- Method result = Method.SPEED;
-
- // Figure out which scalingMethod should be used
- if (length <= Scalr.THRESHOLD_QUALITY_BALANCED)
- result = Method.QUALITY;
- else if (length <= Scalr.THRESHOLD_BALANCED_SPEED)
- result = Method.BALANCED;
-
- if (DEBUG)
- log(2, "AUTOMATIC scaling method selected: %s", result.name());
-
- return result;
- }
-
- /**
- * Used to implement a straight-forward image-scaling operation using Java
- * 2D.
- *
- * This method uses the Oracle-encouraged method of
- * Graphics2D.drawImage(...)
to scale the given image with the
- * given interpolation hint.
- *
- * @param src The image that will be scaled.
- * @param targetWidth The target width for the scaled image.
- * @param targetHeight The target height for the scaled image.
- * @param interpolationHintValue The {@link RenderingHints} interpolation value used to
- * indicate the method that {@link Graphics2D} should use when
- * scaling the image.
- * @return the result of scaling the original src
to the given
- * dimensions using the given interpolation method.
- */
- protected static BufferedImage scaleImage(BufferedImage src,
- int targetWidth, int targetHeight, Object interpolationHintValue) {
- // Setup the rendering resources to match the source image's
- BufferedImage result = createOptimalImage(src, targetWidth,
- targetHeight);
- Graphics2D resultGraphics = result.createGraphics();
-
- // Scale the image to the new buffer using the specified rendering hint.
- resultGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
- interpolationHintValue);
- resultGraphics.drawImage(src, 0, 0, targetWidth, targetHeight, null);
-
- // Just to be clean, explicitly dispose our temporary graphics object
- resultGraphics.dispose();
-
- // Return the scaled image to the caller.
- return result;
- }
-
- /**
- * Used to implement Chris Campbell's incremental-scaling algorithm: http://today.java.net/pub/a/today/2007/04/03/perils
- * -of-image-getscaledinstance.html .
- *
- * Modifications to the original algorithm are variable names and comments
- * added for clarity and the hard-coding of using BICUBIC interpolation as
- * well as the explicit "flush()" operation on the interim BufferedImage
- * instances to avoid resource leaking.
- *
- * @param src The image that will be scaled.
- * @param targetWidth The target width for the scaled image.
- * @param targetHeight The target height for the scaled image.
- * @param scalingMethod The scaling method specified by the user (or calculated by
- * imgscalr) to use for this incremental scaling operation.
- * @param interpolationHintValue The {@link RenderingHints} interpolation value used to
- * indicate the method that {@link Graphics2D} should use when
- * scaling the image.
- * @return an image scaled to the given dimensions using the given rendering
- * hint.
- */
- protected static BufferedImage scaleImageIncrementally(BufferedImage src,
- int targetWidth, int targetHeight, Method scalingMethod,
- Object interpolationHintValue) {
- boolean hasReassignedSrc = false;
- int incrementCount = 0;
- int currentWidth = src.getWidth();
- int currentHeight = src.getHeight();
-
- /*
- * The original QUALITY mode, representing Chris Campbell's algorithm,
- * is to step down by 1/2s every time when scaling the image
- * incrementally. Users pointed out that using this method to scale
- * images with noticeable straight lines left them really jagged in
- * smaller thumbnail format.
- *
- * After investigation it was discovered that scaling incrementally by
- * smaller increments was the ONLY way to make the thumbnail sized
- * images look less jagged and more accurate; almost matching the
- * accuracy of Mac's built in thumbnail generation which is the highest
- * quality resize I've come across (better than GIMP Lanczos3 and
- * Windows 7).
- *
- * A divisor of 7 was chose as using 5 still left some jaggedness in the
- * image while a divisor of 8 or higher made the resulting thumbnail too
- * soft; like our OP_ANTIALIAS convolve op had been forcibly applied to
- * the result even if the user didn't want it that soft.
- *
- * Using a divisor of 7 for the ULTRA_QUALITY seemed to be the sweet
- * spot.
- *
- * NOTE: Below when the actual fraction is used to calculate the small
- * portion to subtract from the current dimension, this is a
- * progressively smaller and smaller chunk. When the code was changed to
- * do a linear reduction of the image of equal steps for each
- * incremental resize (e.g. say 50px each time) the result was
- * significantly worse than the progressive approach used below; even
- * when a very high number of incremental steps (13) was tested.
- */
- int fraction = (scalingMethod == Method.ULTRA_QUALITY ? 7 : 2);
-
- do {
- int prevCurrentWidth = currentWidth;
- int prevCurrentHeight = currentHeight;
-
- /*
- * If the current width is bigger than our target, cut it in half
- * and sample again.
- */
- if (currentWidth > targetWidth) {
- currentWidth -= (currentWidth / fraction);
-
- /*
- * If we cut the width too far it means we are on our last
- * iteration. Just set it to the target width and finish up.
- */
- if (currentWidth < targetWidth)
- currentWidth = targetWidth;
- }
-
- /*
- * If the current height is bigger than our target, cut it in half
- * and sample again.
- */
-
- if (currentHeight > targetHeight) {
- currentHeight -= (currentHeight / fraction);
-
- /*
- * If we cut the height too far it means we are on our last
- * iteration. Just set it to the target height and finish up.
- */
-
- if (currentHeight < targetHeight)
- currentHeight = targetHeight;
- }
-
- /*
- * Stop when we cannot incrementally step down anymore.
- *
- * This used to use a || condition, but that would cause problems
- * when using FIT_EXACT such that sometimes the width OR height
- * would not change between iterations, but the other dimension
- * would (e.g. resizing 500x500 to 500x250).
- *
- * Now changing this to an && condition requires that both
- * dimensions do not change between a resize iteration before we
- * consider ourselves done.
- */
- if (prevCurrentWidth == currentWidth
- && prevCurrentHeight == currentHeight)
- break;
-
- if (DEBUG)
- log(2, "Scaling from [%d x %d] to [%d x %d]", prevCurrentWidth,
- prevCurrentHeight, currentWidth, currentHeight);
-
- // Render the incremental scaled image.
- BufferedImage incrementalImage = scaleImage(src, currentWidth,
- currentHeight, interpolationHintValue);
-
- /*
- * Before re-assigning our interim (partially scaled)
- * incrementalImage to be the new src image before we iterate around
- * again to process it down further, we want to flush() the previous
- * src image IF (and only IF) it was one of our own temporary
- * BufferedImages created during this incremental down-sampling
- * cycle. If it wasn't one of ours, then it was the original
- * caller-supplied BufferedImage in which case we don't want to
- * flush() it and just leave it alone.
- */
- if (hasReassignedSrc)
- src.flush();
-
- /*
- * Now treat our incremental partially scaled image as the src image
- * and cycle through our loop again to do another incremental
- * scaling of it (if necessary).
- */
- src = incrementalImage;
-
- /*
- * Keep track of us re-assigning the original caller-supplied source
- * image with one of our interim BufferedImages so we know when to
- * explicitly flush the interim "src" on the next cycle through.
- */
- hasReassignedSrc = true;
-
- // Track how many times we go through this cycle to scale the image.
- incrementCount++;
- } while (currentWidth != targetWidth || currentHeight != targetHeight);
-
- if (DEBUG)
- log(2, "Incrementally Scaled Image in %d steps.", incrementCount);
-
- /*
- * Once the loop has exited, the src image argument is now our scaled
- * result image that we want to return.
- */
- return src;
- }
-}
\ No newline at end of file
diff --git a/src/the/bytecode/club/bootloader/Boot.java b/src/the/bytecode/club/bootloader/Boot.java
index d5267da6..09b987a5 100644
--- a/src/the/bytecode/club/bootloader/Boot.java
+++ b/src/the/bytecode/club/bootloader/Boot.java
@@ -16,7 +16,7 @@ import me.konloch.kontainer.io.HTTPRequest;
import the.bytecode.club.bootloader.resource.EmptyExternalResource;
import the.bytecode.club.bootloader.resource.ExternalResource;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.ZipUtils;
+import the.bytecode.club.bytecodeviewer.util.ZipUtils;
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
/***************************************************************************
@@ -62,20 +62,8 @@ public class Boot {
}
}
- public static void boot(String[] args, boolean CLI) throws Exception {
- /*if(System.getProperty("java.version").startsWith("9."))
- {
- BytecodeViewer.showMessage("Java 9.x is not supported yet, please wait till BCV 2.9.11\n\rJava 8 should work <3");
- System.exit(0);
- return;
- }
- if(System.getProperty("java.version").startsWith("10."))
- {
- BytecodeViewer.showMessage("Java 10.x is not supported yet, please wait till BCV 2.9.11\n\rJava 8 should work <3");
- System.exit(0);
- return;
- }*/
-
+ public static void boot(String[] args, boolean CLI) throws Exception
+ {
bootstrap();
ILoader> loader = findLoader();
@@ -241,7 +229,7 @@ public class Boot {
}
if (delete) {
f.delete();
- System.out.println("Detected & Deleted Foriegn/Outdated Jar/File: " + f.getName());
+ System.out.println("Detected & Deleted Foreign/Outdated Jar/File: " + f.getName());
}
}
@@ -330,6 +318,82 @@ public class Boot {
}
}
+ public static void dropKrakatau()
+ {
+ File krakatauDirectory = new File(BytecodeViewer.krakatauWorkingDirectory);
+ BytecodeViewer.krakatauWorkingDirectory = BytecodeViewer.krakatauWorkingDirectory + BytecodeViewer.fs + "Krakatau-master";
+ if (!krakatauDirectory.exists())
+ {
+ setState("Bytecode Viewer Boot Screen - Extracting Krakatau");
+ System.out.println("Extracting Krakatau");
+ try
+ {
+ File temp = new File(BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "krakatau_" + BytecodeViewer.krakatauVersion + ".zip");
+
+ while (temp.exists())
+ temp.delete();
+
+ InputStream is = BytecodeViewer.class.getClassLoader().getResourceAsStream("Krakatau-" + BytecodeViewer.krakatauVersion + ".zip");
+ FileOutputStream baos = new FileOutputStream(temp);
+
+ int r = 0;
+ byte[] buffer = new byte[8192];
+ while ((r = is.read(buffer)) >= 0)
+ {
+ baos.write(buffer, 0, r);
+ }
+
+ baos.close();
+ ZipUtils.unzipFilesToPath(temp.getAbsolutePath(), krakatauDirectory.getAbsolutePath());
+ temp.delete();
+ System.out.println("Succesfully extracted Krakatau");
+ }
+ catch (Exception e)
+ {
+ setState("Bytecode Viewer Boot Screen - ERROR, please contact @Konloch with your stacktrace.");
+ new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
+ }
+ }
+ }
+
+ public static void dropEnjarify()
+ {
+ File enjarifyDirectory = new File(BytecodeViewer.enjarifyWorkingDirectory);
+ BytecodeViewer.enjarifyWorkingDirectory = BytecodeViewer.enjarifyWorkingDirectory + BytecodeViewer.fs + "enjarify-master";
+ if (!enjarifyDirectory.exists())
+ {
+ setState("Bytecode Viewer Boot Screen - Extracting Enjarify");
+ System.out.println("Extracting Enjarify");
+ try
+ {
+ File temp = new File(BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "enjarify" + BytecodeViewer.enjarifyVersion + ".zip");
+
+ while (temp.exists())
+ temp.delete();
+
+ InputStream is = BytecodeViewer.class.getClassLoader().getResourceAsStream("enjarify-" + BytecodeViewer.enjarifyVersion + ".zip");
+ FileOutputStream baos = new FileOutputStream(temp);
+
+ int r = 0;
+ byte[] buffer = new byte[8192];
+ while ((r = is.read(buffer)) >= 0)
+ {
+ baos.write(buffer, 0, r);
+ }
+
+ baos.close();
+ ZipUtils.unzipFilesToPath(temp.getAbsolutePath(), enjarifyDirectory.getAbsolutePath());
+ temp.delete();
+ System.out.println("Succesfully extracted Enjarify");
+ }
+ catch (Exception e)
+ {
+ setState("Bytecode Viewer Boot Screen - ERROR, please contact @Konloch with your stacktrace.");
+ new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
+ }
+ }
+ }
+
public static void downloadZipsOnly() throws Exception {
for (String s : urlList) {
String fileName = s.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length(), s.length());
@@ -470,6 +534,7 @@ public class Boot {
BytecodeViewer.krakatauWorkingDirectory = BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "krakatau_" +
BytecodeViewer.krakatauVersion + BytecodeViewer.fs + "Krakatau-master";
+
File krakatauDirectory = new File(BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "krakatau_" + BytecodeViewer.krakatauVersion);
if (!krakatauDirectory.exists()) {
try {
diff --git a/src/the/bytecode/club/bytecodeviewer/BytecodeViewer.java b/src/the/bytecode/club/bytecodeviewer/BytecodeViewer.java
index 5451fb61..249bfbeb 100644
--- a/src/the/bytecode/club/bytecodeviewer/BytecodeViewer.java
+++ b/src/the/bytecode/club/bytecodeviewer/BytecodeViewer.java
@@ -13,10 +13,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
-import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -49,6 +47,7 @@ import the.bytecode.club.bytecodeviewer.gui.SystemErrConsole;
import the.bytecode.club.bytecodeviewer.gui.WorkPane;
import the.bytecode.club.bytecodeviewer.obfuscators.mapping.Refactorer;
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
+import the.bytecode.club.bytecodeviewer.util.*;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -71,60 +70,53 @@ import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
/**
* A lightweight Java Reverse Engineering suite, developed by Konloch - http://konloch.me
*
+ * All you have to do is add a jar or class file into the workspace,
+ * select the file you want then it will start decompiling the class in the background.
+ * When it's done it will show the Source code, Bytecode and Hexcode of the class file you chose.
+ *
+ * There is also a plugin system that will allow you to interact with the loaded classfiles.
+ * For example you can write a String deobfuscator, a malicious code searcher,
+ * or anything else you can think of.
+ *
+ * You can either use one of the pre-written plugins, or write your own. It supports java scripting.
+ * Once a plugin is activated, it will send a ClassNode ArrayList of every single class loaded in the
+ * file system to the execute function, this allows the user to handle it completely using ASM.
+ *
* Are you a Java Reverse Engineer? Or maybe you want to learn Java Reverse Engineering?
* Join The Bytecode Club, we're noob friendly, and censorship free.
* http://the.bytecode.club
*
- *
- * All you have to do is add a jar or class file into the workspace,
- * select the file you want then it will start decompiling the class in the background,
- * when it's done it will show the Source code, Bytecode and Hexcode of the class file you chose.
- *
- * There is also a plugin system that will allow you to interact with the loaded classfiles,
- * for example you can write a String deobfuscator, a malicious code searcher,
- * or something else you can think of.
- *
- * You can either use one of the pre-written plugins, or write your own.
- * It supports groovy scripting. Once a plugin is activated,
- * it will send a ClassNode ArrayList of every single class loaded in the file system to the execute function,
- * this allows the user to handle it completely using ASM.
- *
* TODO:
- * 3.0.0: (RETIREMENT PARTY, WOHOOO)
- * Add obfuscation:
- * - Add integer boxing and other obfuscation methods contra implemented
- * - Insert unadded/debug opcodes to try to fuck up decompilers
- * - ClassAnylyzterAdapter
- * Add the jump/save mark system Ida Pro has.
- * Add class annotations to bytecode decompiler.
- * EVERYTHING BUG FREE, CHECK 100%
- * bytecode editor that works by editing per method instead of entire class, methods are in a pane like the file navigator
- * Make the tabs menu and middle mouse button click work on the tab itself not just the close button.
- *
- * before 3.0.0:
- * EVERYTHING ON THE FUCKING GITHUB ISSUES LOL
+ * Update fernflower for it's 2019 version
+ * Finish dragging code
+ * Finish right-click tab menu detection
* make it use that global last used inside of export as jar
- * Spiffy up the plugin console with hilighted lines
- * Take https://github.com/ptnkjke/Java-Bytecode-Editor visualize
+ * Add https://github.com/ptnkjke/Java-Bytecode-Editor visualize as a plugin
* make zipfile not include the decode shit
* add stackmapframes to bytecode decompiler
- * add stackmapframes remover?
* make ez-injection plugin console show all sys.out calls
* add JEB decompiler optionally, requires them to add jeb library jar externally and disable update check ?
* add decompile as zip for krakatau-bytecode, jd-gui and smali for CLI
+ * add decompile all as zip for CLI
* fix hook inject for EZ-Injection
* fix classfile searcher
- * make the decompilers launch in a separate process?
+ * make the decompilers launch in a separate process
*
* @author Konloch
+ * @author The entire BCV community
*/
public class BytecodeViewer
{
/*per version*/
- public static String version = "2.9.16";
- public static boolean previewCopy = false;
- public static boolean fatJar = true; //could be automatic by checking if it's loaded a class named whatever for a library
+ public static final String VERSION = "2.9.16";
+ public static String krakatauVersion = "12";
+ public static String enjarifyVersion = "4";
+ public static final boolean BLOCK_TAB_MENU = true;
+ public static final boolean PREVIEW_COPY = false;
+ public static final boolean FAT_JAR = true; //could be automatic by checking if it's loaded a class named whatever for a library
+ public static final boolean OFFLINE_MODE = true; //disables the automatic updater
+
/*the rest*/
public static boolean verify = false; //eventually may be a setting
public static String[] args;
@@ -137,9 +129,10 @@ public class BytecodeViewer
public static String library = "";
public static String javac = "";
public static String java = "";
- public static File krakatauTempDir;
- public static File krakatauTempJar;
+ private static File krakatauTempDir;
+ private static File krakatauTempJar;
public static int krakatauHash;
+ public static boolean displayParentInTab = false; //also change in the main GUI
public static boolean currentlyDumping = false;
public static boolean needsReDump = true;
public static boolean warnForEditing = false;
@@ -154,10 +147,8 @@ public class BytecodeViewer
public static String settingsName = getBCVDirectory() + fs + "settings.bcv";
public static String tempDirectory = getBCVDirectory() + fs + "bcv_temp" + fs;
public static String libsDirectory = getBCVDirectory() + fs + "libs" + fs;
- public static String krakatauWorkingDirectory = "";
- public static String krakatauVersion = "";
- public static String enjarifyWorkingDirectory = "";
- public static String enjarifyVersion = "";
+ public static String krakatauWorkingDirectory = getBCVDirectory() + fs + "krakatau_" + krakatauVersion;
+ public static String enjarifyWorkingDirectory = getBCVDirectory() + fs + "enjarify_" + enjarifyVersion;
private static ArrayList recentFiles = DiskReader.loadArrayList(filesName, false);
private static ArrayList recentPlugins = DiskReader.loadArrayList(pluginsName, false);
public static boolean runningObfuscation = false;
@@ -166,7 +157,7 @@ public class BytecodeViewer
public static ArrayList createdProcesses = new ArrayList();
public static Refactorer refactorer = new Refactorer();
public static boolean pingback = false;
- public static boolean deleteForiegnLibraries = true;
+ public static boolean deleteForeignLibraries = true;
/**
* The version checker thread
@@ -179,45 +170,20 @@ public class BytecodeViewer
final String version = r.readSingle();
try {
int simplemaths = Integer.parseInt(version.replace(".", ""));
- int simplemaths2 = Integer.parseInt(BytecodeViewer.version.replace(".", ""));
+ int simplemaths2 = Integer.parseInt(BytecodeViewer.VERSION.replace(".", ""));
if (simplemaths2 > simplemaths)
return; //developer version
} catch (Exception e) {
}
- if (!BytecodeViewer.version.equals(version)) {
- r = new HTTPRequest(new URL("https://raw.githubusercontent.com/Konloch/bytecode-viewer/master/CHANGELOG.md"));
- String[] readme = r.read();
-
- String changelog = "Unable to load change log, please try again later." + nl;
- boolean trigger = false;
- boolean finalTrigger = false;
- for (String st : readme) {
- if(st.equals("```")) {
- continue;
- } else if (st.equals("--- " + BytecodeViewer.version + " ---:")) {
- changelog = "";
- trigger = true;
- } else if (trigger) {
- if (st.startsWith("--- "))
- finalTrigger = true;
-
- if (finalTrigger)
- changelog += st + nl;
- }
- }
-
+ if (!BytecodeViewer.VERSION.equals(version))
+ {
JOptionPane pane = new JOptionPane("Your version: "
- + BytecodeViewer.version
+ + BytecodeViewer.VERSION
+ ", latest version: "
+ version
+ nl
- + nl
- + "Changes since your version:"
- + nl
- + changelog
- + nl
+ "What would you like to do?");
Object[] options = new String[]{"Open The Download Page", "Download The Updated Jar", "Do Nothing"};
pane.setOptions(options);
@@ -403,11 +369,19 @@ public class BytecodeViewer
@Override
public void run() {
try {
- Boot.populateUrlList();
- Boot.populateLibsDirectory();
- Boot.downloadZipsOnly();
- Boot.checkKrakatau();
- Boot.checkEnjarify();
+ if(BytecodeViewer.OFFLINE_MODE)
+ {
+ Boot.dropKrakatau();
+ Boot.dropEnjarify();
+ }
+ else
+ {
+ Boot.populateUrlList();
+ Boot.populateLibsDirectory();
+ Boot.downloadZipsOnly();
+ Boot.checkKrakatau();
+ Boot.checkEnjarify();
+ }
} catch (Exception e) {
e.printStackTrace();
}
@@ -517,23 +491,24 @@ public class BytecodeViewer
*/
public static void main(String[] args) {
BytecodeViewer.args = args;
- System.out.println("https://the.bytecode.club - Created by @Konloch - Bytecode Viewer " + version+", FatJar: " + fatJar);
+ System.out.println("https://the.bytecode.club - Created by @Konloch - Bytecode Viewer " + VERSION +", Fat-Jar: " + FAT_JAR);
System.setSecurityManager(sm);
try {
+ UIManager.put("MenuItem.disabledAreNavigable", Boolean.FALSE);
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
- if (previewCopy && !CommandLineInput.containsCommand(args))
- showMessage("WARNING: This is a preview/dev copy, you WON'T be alerted when " + version + " is actually out if you use this." + nl +
- "Make sure to watch the repo: https://github.com/Konloch/bytecode-viewer for " + version + "'s release");
+ if (PREVIEW_COPY && !CommandLineInput.containsCommand(args))
+ showMessage("WARNING: This is a preview/dev copy, you WON'T be alerted when " + VERSION + " is actually out if you use this." + nl +
+ "Make sure to watch the repo: https://github.com/Konloch/bytecode-viewer for " + VERSION + "'s release");
viewer = new MainViewerGUI();
- Settings.loadGUI();
+ Settings.loadSettings();
int CLI = CommandLineInput.parseCommandLine(args);
if (CLI == CommandLineInput.STOP)
return;
- if (!fatJar) {
+ if (!FAT_JAR) {
bootCheck.start();
if (CLI == CommandLineInput.OPEN_FILE)
@@ -566,7 +541,7 @@ public class BytecodeViewer
public void run() {
for (Process proc : createdProcesses)
proc.destroy();
- Settings.saveGUI();
+ Settings.saveSettings();
cleanup();
}
});
@@ -653,6 +628,22 @@ public class BytecodeViewer
return null;
}
+ public static FileContainer getFileContainer(String name) {
+ for (FileContainer container : files)
+ if (container.name.equals(name))
+ return container;
+
+ return null;
+ }
+
+ public static ClassNode getClassNode(FileContainer container, String name) {
+ for (ClassNode c : container.classes)
+ if (c.name.equals(name))
+ return c;
+
+ return null;
+ }
+
/**
* Grabs the file contents of the loaded resources.
*
@@ -864,10 +855,7 @@ public class BytecodeViewer
} else if (fn.endsWith(".class")) {
try {
byte[] bytes = JarUtils.getBytes(new FileInputStream(f));
- String cafebabe = String.format("%02X", bytes[0])
- + String.format("%02X", bytes[1])
- + String.format("%02X", bytes[2])
- + String.format("%02X", bytes[3]);
+ String cafebabe = String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format("%02X", bytes[2]) + String.format("%02X", bytes[3]);
if (cafebabe.toLowerCase().equals("cafebabe")) {
final ClassNode cn = JarUtils.getNode(bytes);
@@ -1002,14 +990,10 @@ public class BytecodeViewer
*
* @param ask if should require user input or not
*/
- public static void resetWorkSpace(boolean ask) {
- if (!ask) {
- files.clear();
- MainViewerGUI.getComponent(FileNavigationPane.class).resetWorkspace();
- MainViewerGUI.getComponent(WorkPane.class).resetWorkspace();
- MainViewerGUI.getComponent(SearchingPane.class).resetWorkspace();
- the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().clear();
- } else {
+ public static void resetWorkSpace(boolean ask)
+ {
+ if(ask)
+ {
JOptionPane pane = new JOptionPane(
"Are you sure you want to reset the workspace?\n\rIt will also reset your file navigator and search.");
Object[] options = new String[]{"Yes", "No"};
@@ -1023,14 +1007,16 @@ public class BytecodeViewer
if (options[k].equals(obj))
result = k;
- if (result == 0) {
- files.clear();
- MainViewerGUI.getComponent(FileNavigationPane.class).resetWorkspace();
- MainViewerGUI.getComponent(WorkPane.class).resetWorkspace();
- MainViewerGUI.getComponent(SearchingPane.class).resetWorkspace();
- the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().clear();
- }
+ if (result != 0)
+ return;
}
+
+ files.clear();
+ LazyNameUtil.reset();
+ MainViewerGUI.getComponent(FileNavigationPane.class).resetWorkspace();
+ MainViewerGUI.getComponent(WorkPane.class).resetWorkspace();
+ MainViewerGUI.getComponent(SearchingPane.class).resetWorkspace();
+ the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().clear();
}
private static ArrayList killList = new ArrayList();
@@ -1296,7 +1282,7 @@ public class BytecodeViewer
Thread t = new Thread() {
public void run() {
- if (viewer.autoCompileSmali.isSelected() && !BytecodeViewer.compile(false))
+ if (viewer.compileOnSave.isSelected() && !BytecodeViewer.compile(false))
return;
JFileChooser fc = new JFileChooser();
fc.setFileFilter(new FileFilter() {
@@ -1362,57 +1348,69 @@ public class BytecodeViewer
}
}
- public static void dumpTempFile()
+ public static File[] dumpTempFile(FileContainer container)
{
- /*int tempHash = fileContainersHash(files);
-
- if(tempHash != krakatauHash && krakatauTempJar != null)
+ File[] files = new File[2];
+ //currently won't optimize if you've got two containers with the same name, will need to add this later
+ if(!LazyNameUtil.SAME_NAME_JAR_WORKSPACE)
{
- krakatauTempDir.delete();
- krakatauTempJar.delete();
- krakatauTempDir = null;
- krakatauTempJar = null;
- }*/
+ if (krakatauTempJar != null && !krakatauTempJar.exists())
+ {
+ needsReDump = true;
+ }
- if(krakatauTempJar != null && !krakatauTempJar.exists())
+ if (needsReDump && krakatauTempJar != null)
+ {
+ krakatauTempDir = null;
+ krakatauTempJar = null;
+ }
+
+ boolean passes = false;
+
+ if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Krakatau.getModel()))
+ passes = true;
+ else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1KrakatauBytecode.getModel()))
+ passes = true;
+ else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Krakatau.getModel()))
+ passes = true;
+ else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2KrakatauBytecode.getModel()))
+ passes = true;
+ else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Krakatau.getModel()))
+ passes = true;
+ else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3KrakatauBytecode.getModel()))
+ passes = true;
+
+ if (krakatauTempJar != null || !passes)
+ {
+ files[0] = krakatauTempJar;
+ files[1] = krakatauTempDir;
+ return files;
+ }
+
+ currentlyDumping = true;
+ needsReDump = false;
+ krakatauTempDir = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs);
+ krakatauTempDir.mkdir();
+ krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar");
+ //krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar."+container.name);
+ JarUtils.saveAsJarClassesOnly(container.classes, krakatauTempJar.getAbsolutePath());
+ currentlyDumping = false;
+ }
+ else
{
- needsReDump = true;
+ currentlyDumping = true;
+ needsReDump = false;
+ krakatauTempDir = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs);
+ krakatauTempDir.mkdir();
+ krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar");
+ //krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar."+container.name);
+ JarUtils.saveAsJarClassesOnly(container.classes, krakatauTempJar.getAbsolutePath());
+ currentlyDumping = false;
}
- if(needsReDump && krakatauTempJar != null)
- {
- krakatauTempDir.delete();
- krakatauTempJar.delete();
- krakatauTempDir = null;
- krakatauTempJar = null;
- }
-
- boolean passes = false;
-
- if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Krakatau.getModel()))
- passes = true;
- else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1KrakatauBytecode.getModel()))
- passes = true;
- else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Krakatau.getModel()))
- passes = true;
- else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2KrakatauBytecode.getModel()))
- passes = true;
- else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Krakatau.getModel()))
- passes = true;
- else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3KrakatauBytecode.getModel()))
- passes = true;
-
- if(krakatauTempJar != null || !passes)
- return;
-
- currentlyDumping = true;
- needsReDump = false;
- //krakatauHash = tempHash;
- krakatauTempDir = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs);
- krakatauTempDir.mkdir();
- krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar");
- JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), krakatauTempJar.getAbsolutePath());
- currentlyDumping = false;
+ files[0] = krakatauTempJar;
+ files[1] = krakatauTempDir;
+ return files;
}
public static void rtCheck()
diff --git a/src/the/bytecode/club/bytecodeviewer/CommandLineInput.java b/src/the/bytecode/club/bytecodeviewer/CommandLineInput.java
index 230364ce..68f2b4e9 100644
--- a/src/the/bytecode/club/bytecodeviewer/CommandLineInput.java
+++ b/src/the/bytecode/club/bytecodeviewer/CommandLineInput.java
@@ -12,6 +12,7 @@ import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
+import the.bytecode.club.bytecodeviewer.util.JarUtils;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -49,7 +50,7 @@ public class CommandLineInput {
static {
options.addOption("help", false, "prints the help menu.");
- options.addOption("list", false, "lists all the available decompilers for BCV " + BytecodeViewer.version + ".");
+ options.addOption("list", false, "lists all the available decompilers for BCV " + BytecodeViewer.VERSION + ".");
options.addOption("decompiler", true, "sets the decompiler, procyon by default.");
options.addOption("i", true, "sets the input.");
options.addOption("o", true, "sets the output.");
@@ -320,7 +321,7 @@ public class CommandLineInput {
}
System.out.println("Finished.");
- System.out.println("Bytecode Viewer CLI v" + BytecodeViewer.version + " by @Konloch - http://bytecodeviewer.com");
+ System.out.println("Bytecode Viewer CLI v" + BytecodeViewer.VERSION + " by @Konloch - http://bytecodeviewer.com");
System.exit(0);
} catch (Exception e) {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
diff --git a/src/the/bytecode/club/bytecodeviewer/SecurityMan.java b/src/the/bytecode/club/bytecodeviewer/SecurityMan.java
index 2cd1590e..f4095657 100644
--- a/src/the/bytecode/club/bytecodeviewer/SecurityMan.java
+++ b/src/the/bytecode/club/bytecodeviewer/SecurityMan.java
@@ -43,7 +43,7 @@ public class SecurityMan extends SecurityManager {
executedClass.equals("the.bytecode.club.bytecodeviewer.decompilers.FernFlowerDecompiler") ||
executedClass.equals("the.bytecode.club.bytecodeviewer.decompilers.JDGUIDecompiler") ||
executedClass.equals("the.bytecode.club.bytecodeviewer.compilers.KrakatauAssembler") ||
- executedClass.equals("the.bytecode.club.bytecodeviewer.Enjarify") ||
+ executedClass.equals("the.bytecode.club.bytecodeviewer.util.Enjarify") ||
executedClass.equals("the.bytecode.club.bytecodeviewer.BytecodeViewer") ||
executedClass.equals("the.bytecode.club.bytecodeviewer.compilers.JavaCompiler")) {
blocking = false;
diff --git a/src/the/bytecode/club/bytecodeviewer/Settings.java b/src/the/bytecode/club/bytecodeviewer/Settings.java
index afda4e0c..18e60f02 100644
--- a/src/the/bytecode/club/bytecodeviewer/Settings.java
+++ b/src/the/bytecode/club/bytecodeviewer/Settings.java
@@ -31,9 +31,9 @@ import me.konloch.kontainer.io.DiskWriter;
public class Settings {
- public static void saveGUI() {
+ public static void saveSettings() {
try {
- DiskWriter.replaceFile(BytecodeViewer.settingsName, "", false);
+ DiskWriter.replaceFile(BytecodeViewer.settingsName, "BCV: " + BytecodeViewer.VERSION, false);
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.rbr.isSelected()), false);
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.rsy.isSelected()), false);
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.din.isSelected()), false);
@@ -206,7 +206,7 @@ public class Settings {
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel2JDGUI_E.isSelected()), false);
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel3JDGUI_E.isSelected()), false);
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.fontSpinner.getValue()), false);
- DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.deleteForiegnLibraries), false);
+ DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.deleteForeignLibraries), false);
if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionDex.getModel()))
DiskWriter.writeNewLine(BytecodeViewer.settingsName, "0", false);
else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel()))
@@ -214,15 +214,19 @@ public class Settings {
DiskWriter.writeNewLine(BytecodeViewer.settingsName, BytecodeViewer.python3, false);
DiskWriter.writeNewLine(BytecodeViewer.settingsName, BytecodeViewer.javac, false);
DiskWriter.writeNewLine(BytecodeViewer.settingsName, BytecodeViewer.java, false);
- DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.autoCompileSmali.isSelected()), false);
+ DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.compileOnSave.isSelected()), false);
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.autoCompileOnRefresh.isSelected()), false);
DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.warnForEditing), false);
+ DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.showFileInTabTitle.isSelected()), false);
+ DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.forcePureAsciiAsText.isSelected()), false);
+ DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.synchronizedViewing.isSelected()), false);
+ DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.showClassMethods.isSelected()), false);
} catch (Exception e) {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
- public static void loadGUI() { //utilizes the Disk Reader's caching system.
+ public static void loadSettings() { //utilizes the Disk Reader's caching system.
try {
BytecodeViewer.viewer.rbr.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 1, true)));
BytecodeViewer.viewer.rsy.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 2, false)));
@@ -404,7 +408,7 @@ public class Settings {
BytecodeViewer.viewer.panel2JDGUI_E.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 110, false)));
BytecodeViewer.viewer.panel3JDGUI_E.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 111, false)));
BytecodeViewer.viewer.fontSpinner.setValue(Integer.parseInt(DiskReader.loadString(BytecodeViewer.settingsName, 112, false)));
- BytecodeViewer.deleteForiegnLibraries = Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 113, false));
+ BytecodeViewer.deleteForeignLibraries = Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 113, false));
decompiler = Integer.parseInt(DiskReader.loadString(BytecodeViewer.settingsName, 114, false));
if (decompiler == 0)
BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionDex.getModel(), true);
@@ -413,9 +417,14 @@ public class Settings {
BytecodeViewer.python3 = DiskReader.loadString(BytecodeViewer.settingsName, 115, false);
BytecodeViewer.javac = DiskReader.loadString(BytecodeViewer.settingsName, 116, false);
BytecodeViewer.java = DiskReader.loadString(BytecodeViewer.settingsName, 117, false);
- BytecodeViewer.viewer.autoCompileSmali.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 118, false)));
+ BytecodeViewer.viewer.compileOnSave.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 118, false)));
BytecodeViewer.viewer.autoCompileOnRefresh.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 119, false)));
- BytecodeViewer.warnForEditing = (Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 119, false)));
+ BytecodeViewer.warnForEditing = Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 120, false));
+ BytecodeViewer.viewer.showFileInTabTitle.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 121, false)));
+ BytecodeViewer.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected();
+ BytecodeViewer.viewer.forcePureAsciiAsText.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 122, false)));
+ BytecodeViewer.viewer.synchronizedViewing.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 123, false)));
+ BytecodeViewer.viewer.showClassMethods.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 124, false)));
} catch (Exception e) {
//ignore because errors are expected, first start up and outdated settings.
//e.printStackTrace();
diff --git a/src/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java b/src/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java
index 46c16cea..64c2323a 100644
--- a/src/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java
+++ b/src/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java
@@ -11,7 +11,7 @@ import java.util.jar.JarFile;
import org.objectweb.asm.tree.ClassNode;
-import the.bytecode.club.bytecodeviewer.JarUtils;
+import the.bytecode.club.bytecodeviewer.util.JarUtils;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.EZInjection;
diff --git a/src/the/bytecode/club/bytecodeviewer/api/ExceptionUI.java b/src/the/bytecode/club/bytecodeviewer/api/ExceptionUI.java
index c210289f..5f2532a4 100644
--- a/src/the/bytecode/club/bytecodeviewer/api/ExceptionUI.java
+++ b/src/the/bytecode/club/bytecodeviewer/api/ExceptionUI.java
@@ -75,7 +75,7 @@ public class ExceptionUI extends JFrame {
this.setIconImages(Resources.iconList);
setSize(new Dimension(600, 400));
- setTitle("Bytecode Viewer " + BytecodeViewer.version
+ setTitle("Bytecode Viewer " + BytecodeViewer.VERSION
+ " - Stack Trace - Send this to " + author);
getContentPane().setLayout(new CardLayout(0, 0));
@@ -88,9 +88,9 @@ public class ExceptionUI extends JFrame {
e.printStackTrace(new PrintWriter(sw));
e.printStackTrace();
- txtrBytecodeViewerIs.setText("Bytecode Viewer Version: " + BytecodeViewer.version +
- ", Preview Copy: " + BytecodeViewer.previewCopy +
- ", Fat Jar: " + BytecodeViewer.fatJar +
+ txtrBytecodeViewerIs.setText("Bytecode Viewer Version: " + BytecodeViewer.VERSION +
+ ", Preview Copy: " + BytecodeViewer.PREVIEW_COPY +
+ ", Fat Jar: " + BytecodeViewer.FAT_JAR +
", OS: " + System.getProperty("os.name") +
", Java: " + System.getProperty("java.version") +
BytecodeViewer.nl + BytecodeViewer.nl + sw.toString());
@@ -101,7 +101,7 @@ public class ExceptionUI extends JFrame {
private void setup(String e, String author) {
this.setIconImages(Resources.iconList);
setSize(new Dimension(600, 400));
- setTitle("Bytecode Viewer " + BytecodeViewer.version
+ setTitle("Bytecode Viewer " + BytecodeViewer.VERSION
+ " - Stack Trace - Send this to " + author);
getContentPane().setLayout(new CardLayout(0, 0));
diff --git a/src/the/bytecode/club/bytecodeviewer/compilers/JavaCompiler.java b/src/the/bytecode/club/bytecodeviewer/compilers/JavaCompiler.java
index 6a2afa41..86e90d06 100644
--- a/src/the/bytecode/club/bytecodeviewer/compilers/JavaCompiler.java
+++ b/src/the/bytecode/club/bytecodeviewer/compilers/JavaCompiler.java
@@ -8,8 +8,8 @@ import java.io.InputStreamReader;
import me.konloch.kontainer.io.DiskWriter;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.JarUtils;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
+import the.bytecode.club.bytecodeviewer.util.JarUtils;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
diff --git a/src/the/bytecode/club/bytecodeviewer/compilers/KrakatauAssembler.java b/src/the/bytecode/club/bytecodeviewer/compilers/KrakatauAssembler.java
index ed315bf8..43c63dbe 100644
--- a/src/the/bytecode/club/bytecodeviewer/compilers/KrakatauAssembler.java
+++ b/src/the/bytecode/club/bytecodeviewer/compilers/KrakatauAssembler.java
@@ -7,8 +7,8 @@ import java.io.InputStreamReader;
import me.konloch.kontainer.io.DiskWriter;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.JarUtils;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
+import the.bytecode.club.bytecodeviewer.util.JarUtils;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
diff --git a/src/the/bytecode/club/bytecodeviewer/compilers/SmaliAssembler.java b/src/the/bytecode/club/bytecodeviewer/compilers/SmaliAssembler.java
index 6dc05ccc..fb028cca 100644
--- a/src/the/bytecode/club/bytecodeviewer/compilers/SmaliAssembler.java
+++ b/src/the/bytecode/club/bytecodeviewer/compilers/SmaliAssembler.java
@@ -4,10 +4,10 @@ import java.io.File;
import me.konloch.kontainer.io.DiskWriter;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.Dex2Jar;
-import the.bytecode.club.bytecodeviewer.Enjarify;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
-import the.bytecode.club.bytecodeviewer.ZipUtils;
+import the.bytecode.club.bytecodeviewer.util.Dex2Jar;
+import the.bytecode.club.bytecodeviewer.util.Enjarify;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
+import the.bytecode.club.bytecodeviewer.util.ZipUtils;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java b/src/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java
index 48b5e57d..75dd25e3 100644
--- a/src/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java
+++ b/src/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java
@@ -17,13 +17,10 @@ import java.util.zip.ZipOutputStream;
import me.konloch.kontainer.io.DiskReader;
-import org.apache.commons.lang3.ArrayUtils;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.JarUtils;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
-import the.bytecode.club.bytecodeviewer.Resources;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -55,6 +52,7 @@ public class CFRDecompiler extends Decompiler {
public String decompileClassNode(ClassNode cn, byte[] b) {
String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs;
+ String exception = "";
final File tempClass = new File(MiscUtils.getUniqueName(fileStart, ".class") + ".class");
try {
@@ -86,11 +84,27 @@ public class CFRDecompiler extends Decompiler {
} else {
org.benf.cfr.reader.Main.main(generateMainMethod(tempClass.getAbsolutePath(), fuckery));
}*/
- org.benf.cfr.reader.Main.main(generateMainMethod(tempClass.getAbsolutePath(), fuckery));
+ try
+ {
+ org.benf.cfr.reader.Main.main(generateMainMethod(tempClass.getAbsolutePath(), fuckery));
+ }
+ catch(StackOverflowError | Exception e)
+ {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ e.printStackTrace();
+
+ exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
+ }
tempClass.delete();
+ File file = new File(fuckery);
+
+ if(file.exists())
+ return findFile(file.listFiles());
+
+ return "CFR error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception;
- return findFile(new File(fuckery).listFiles());
}
@@ -121,7 +135,7 @@ public class CFRDecompiler extends Decompiler {
e.printStackTrace(new PrintWriter(sw));
e.printStackTrace();
- String exception = "Bytecode Viewer Version: " + BytecodeViewer.version + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
+ String exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
return "CFR error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception;
}
return s;
diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java b/src/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java
index f2c45de1..287ffb8b 100644
--- a/src/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java
+++ b/src/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java
@@ -34,8 +34,8 @@ public abstract class Decompiler {
public final static Decompiler fernflower = new FernFlowerDecompiler();
public final static Decompiler procyon = new ProcyonDecompiler();
public final static Decompiler cfr = new CFRDecompiler();
- public final static Decompiler krakatau = new KrakatauDecompiler();
- public final static Decompiler krakatauDA = new KrakatauDisassembler();
+ public final static KrakatauDecompiler krakatau = new KrakatauDecompiler();
+ public final static KrakatauDisassembler krakatauDA = new KrakatauDisassembler();
public final static Decompiler smali = new SmaliDisassembler();
public final static Decompiler jdgui = new JDGUIDecompiler();
diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java b/src/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java
index 3b885bc4..df4a0f33 100644
--- a/src/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java
+++ b/src/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java
@@ -12,8 +12,7 @@ import org.apache.commons.lang3.ArrayUtils;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.JarUtils;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import the.bytecode.club.bytecodeviewer.Resources;
/***************************************************************************
@@ -50,7 +49,14 @@ public class FernFlowerDecompiler extends Decompiler {
File f = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + BytecodeViewer.fs);
f.mkdir();
- org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempZip.getAbsolutePath(), BytecodeViewer.tempDirectory + "./temp/"));
+ try
+ {
+ org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempZip.getAbsolutePath(), BytecodeViewer.tempDirectory + "./temp/"));
+ }
+ catch(StackOverflowError | Exception e)
+ {
+
+ }
File tempZip2 = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + BytecodeViewer.fs + tempZip.getName());
if (tempZip2.exists())
@@ -77,11 +83,11 @@ public class FernFlowerDecompiler extends Decompiler {
e.printStackTrace(new PrintWriter(sw));
e.printStackTrace();
- exception = "Bytecode Viewer Version: " + BytecodeViewer.version + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
+ exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
}
- if (!BytecodeViewer.fatJar) {
+ if (!BytecodeViewer.FAT_JAR) {
try {
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(
new String[]{BytecodeViewer.getJavaCommand(), "-jar", Resources.findLibrary("fernflower")},
@@ -103,9 +109,13 @@ public class FernFlowerDecompiler extends Decompiler {
{
org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempClass.getAbsolutePath(), new File(BytecodeViewer.tempDirectory).getAbsolutePath()));
}
- catch(Exception e)
+ catch(StackOverflowError | Exception e)
{
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
e.printStackTrace();
+
+ exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
}
}
diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java b/src/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java
index 1ab84d09..4359327f 100644
--- a/src/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java
+++ b/src/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java
@@ -16,7 +16,7 @@ import me.konloch.kontainer.io.DiskReader;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import jd.cli.printer.text.PlainTextPrinter;
/***************************************************************************
@@ -112,7 +112,7 @@ public class JDGUIDecompiler extends Decompiler {
e.printStackTrace(new PrintWriter(sw));
e.printStackTrace();
- exception = "Bytecode Viewer Version: " + BytecodeViewer.version + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
+ exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
}
return "JD-GUI error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception;
}
diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java b/src/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java
index 363c376b..5c5659b3 100644
--- a/src/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java
+++ b/src/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java
@@ -12,9 +12,9 @@ import me.konloch.kontainer.io.DiskReader;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.JarUtils;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
-import the.bytecode.club.bytecodeviewer.ZipUtils;
+import the.bytecode.club.bytecodeviewer.util.JarUtils;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
+import the.bytecode.club.bytecodeviewer.util.ZipUtils;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -49,8 +49,8 @@ public class KrakatauDecompiler extends Decompiler {
return ";" + BytecodeViewer.library;
}
- public String decompileClassNode(ClassNode cn, byte[] b) {
-
+ public String decompileClassNode(File krakatauTempJar, File krakatauTempDir, ClassNode cn, byte[] b)
+ {
if (BytecodeViewer.python.equals("")) {
BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path.");
BytecodeViewer.viewer.pythonC();
@@ -72,7 +72,7 @@ public class KrakatauDecompiler extends Decompiler {
return "Set your paths";
}
- String s = "Bytecode Viewer Version: " + BytecodeViewer.version + BytecodeViewer.nl + BytecodeViewer.nl + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl;
+ String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl;
BytecodeViewer.sm.stopBlocking();
try {
@@ -83,9 +83,9 @@ public class KrakatauDecompiler extends Decompiler {
"-skip", //love you storyyeller <3
"-nauto",
"-path",
- BytecodeViewer.rt + ";" + BytecodeViewer.krakatauTempJar.getAbsolutePath() + quick(),
+ BytecodeViewer.rt + ";" + krakatauTempJar.getAbsolutePath() + quick(),
"-out",
- BytecodeViewer.krakatauTempDir.getAbsolutePath(),
+ krakatauTempDir.getAbsolutePath(),
cn.name + ".class"
);
@@ -117,12 +117,100 @@ public class KrakatauDecompiler extends Decompiler {
s = log;
//if the motherfucker failed this'll fail, aka wont set.
- s = DiskReader.loadAsString(BytecodeViewer.krakatauTempDir.getAbsolutePath() + BytecodeViewer.fs + cn.name + ".java");
+ s = DiskReader.loadAsString(krakatauTempDir.getAbsolutePath() + BytecodeViewer.fs + cn.name + ".java");
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
e.printStackTrace();
- s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.version + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
+ s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
+ } finally {
+ BytecodeViewer.sm.setBlocking();
+ }
+
+ return s;
+ }
+
+ @Override
+ public String decompileClassNode(ClassNode cn, byte[] b)
+ {
+ if (BytecodeViewer.python.equals("")) {
+ BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path.");
+ BytecodeViewer.viewer.pythonC();
+ }
+ if (BytecodeViewer.rt.equals("")) {
+ BytecodeViewer.showMessage("You need to set your JRE RT Library.\r\n(C:\\Program Files (x86)\\Java\\jre7\\lib\\rt.jar)");
+ BytecodeViewer.viewer.rtC();
+ }
+
+ if (BytecodeViewer.python.equals("")) {
+ BytecodeViewer.showMessage("You need to set Python!");
+ return "Set your paths";
+ }
+
+ if (BytecodeViewer.rt.equals("")) {
+ BytecodeViewer.showMessage("You need to set RT.jar!");
+ return "Set your paths";
+ }
+
+ String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl;
+
+ final File tempDirectory = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs);
+ tempDirectory.mkdir();
+ final File tempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar");
+ JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath());
+
+ BytecodeViewer.sm.stopBlocking();
+
+ try {
+ ProcessBuilder pb = new ProcessBuilder(
+ BytecodeViewer.python,
+ "-O", //love you storyyeller <3
+ BytecodeViewer.krakatauWorkingDirectory + BytecodeViewer.fs + "decompile.py",
+ "-skip", //love you storyyeller <3
+ "-nauto",
+ "-path",
+ BytecodeViewer.rt + ";" + tempJar.getAbsolutePath() + quick(),
+ "-out",
+ tempDirectory.getAbsolutePath(),
+ cn.name + ".class"
+ );
+
+ Process process = pb.start();
+ BytecodeViewer.createdProcesses.add(process);
+
+ //Read out dir output
+ InputStream is = process.getInputStream();
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader br = new BufferedReader(isr);
+ String log = "Process:" + BytecodeViewer.nl + BytecodeViewer.nl;
+ String line;
+ while ((line = br.readLine()) != null) {
+ log += BytecodeViewer.nl + line;
+ }
+ br.close();
+
+ log += BytecodeViewer.nl + BytecodeViewer.nl + "Error:" + BytecodeViewer.nl + BytecodeViewer.nl;
+ is = process.getErrorStream();
+ isr = new InputStreamReader(is);
+ br = new BufferedReader(isr);
+ while ((line = br.readLine()) != null) {
+ log += BytecodeViewer.nl + line;
+ }
+ br.close();
+
+ int exitValue = process.waitFor();
+ log += BytecodeViewer.nl + BytecodeViewer.nl + "Exit Value is " + exitValue;
+ s = log;
+
+ //if the motherfucker failed this'll fail, aka wont set.
+ s = DiskReader.loadAsString(tempDirectory.getAbsolutePath() + BytecodeViewer.fs + cn.name + ".java");
+ tempDirectory.delete();
+ tempJar.delete();
+ } catch (Exception e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ e.printStackTrace();
+ s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
} finally {
BytecodeViewer.sm.setBlocking();
}
diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java b/src/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java
index 6f612fc3..8057a07e 100644
--- a/src/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java
+++ b/src/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java
@@ -12,9 +12,9 @@ import me.konloch.kontainer.io.DiskReader;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.JarUtils;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
-import the.bytecode.club.bytecodeviewer.ZipUtils;
+import the.bytecode.club.bytecodeviewer.util.JarUtils;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
+import the.bytecode.club.bytecodeviewer.util.ZipUtils;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -42,7 +42,7 @@ import the.bytecode.club.bytecodeviewer.ZipUtils;
public class KrakatauDisassembler extends Decompiler {
- public String decompileClassNode(ClassNode cn, byte[] b) {
+ public String decompileClassNode(File krakatauTempJar, File krakatauTempDir, ClassNode cn, byte[] b) {
if (BytecodeViewer.python.equals("")) {
BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path.");
BytecodeViewer.viewer.pythonC();
@@ -53,7 +53,7 @@ public class KrakatauDisassembler extends Decompiler {
return "Set your paths";
}
- String s = "Bytecode Viewer Version: " + BytecodeViewer.version + BytecodeViewer.nl + BytecodeViewer.nl + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl;
+ String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl;
BytecodeViewer.sm.stopBlocking();
try {
@@ -62,9 +62,9 @@ public class KrakatauDisassembler extends Decompiler {
"-O", //love you storyyeller <3
BytecodeViewer.krakatauWorkingDirectory + BytecodeViewer.fs + "disassemble.py",
"-path",
- BytecodeViewer.krakatauTempJar.getAbsolutePath(),
+ krakatauTempJar.getAbsolutePath(),
"-out",
- BytecodeViewer.krakatauTempDir.getAbsolutePath(),
+ krakatauTempDir.getAbsolutePath(),
cn.name + ".class"
);
@@ -96,12 +96,84 @@ public class KrakatauDisassembler extends Decompiler {
s = log;
//if the motherfucker failed this'll fail, aka wont set.
- s = DiskReader.loadAsString(BytecodeViewer.krakatauTempDir.getAbsolutePath() + BytecodeViewer.fs + cn.name + ".j");
+ s = DiskReader.loadAsString(krakatauTempDir.getAbsolutePath() + BytecodeViewer.fs + cn.name + ".j");
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
e.printStackTrace();
- s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.version + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
+ s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
+ } finally {
+ BytecodeViewer.sm.setBlocking();
+ }
+ return s;
+ }
+
+ @Override
+ public String decompileClassNode(ClassNode cn, byte[] b) {
+ if (BytecodeViewer.python.equals("")) {
+ BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path.");
+ BytecodeViewer.viewer.pythonC();
+ }
+
+ if (BytecodeViewer.python.equals("")) {
+ BytecodeViewer.showMessage("You need to set Python!");
+ return "Set your paths";
+ }
+
+ String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl;
+
+ final File tempDirectory = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs);
+ tempDirectory.mkdir();
+ final File tempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar");
+ JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath());
+
+ BytecodeViewer.sm.stopBlocking();
+ try {
+ ProcessBuilder pb = new ProcessBuilder(
+ BytecodeViewer.python,
+ "-O", //love you storyyeller <3
+ BytecodeViewer.krakatauWorkingDirectory + BytecodeViewer.fs + "disassemble.py",
+ "-path",
+ tempJar.getAbsolutePath(),
+ "-out",
+ tempDirectory.getAbsolutePath(),
+ cn.name + ".class"
+ );
+
+ Process process = pb.start();
+ BytecodeViewer.createdProcesses.add(process);
+
+ //Read out dir output
+ InputStream is = process.getInputStream();
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader br = new BufferedReader(isr);
+ String log = "Process:" + BytecodeViewer.nl + BytecodeViewer.nl;
+ String line;
+ while ((line = br.readLine()) != null) {
+ log += BytecodeViewer.nl + line;
+ }
+ br.close();
+
+ log += BytecodeViewer.nl + BytecodeViewer.nl + "Error:" + BytecodeViewer.nl + BytecodeViewer.nl;
+ is = process.getErrorStream();
+ isr = new InputStreamReader(is);
+ br = new BufferedReader(isr);
+ while ((line = br.readLine()) != null) {
+ log += BytecodeViewer.nl + line;
+ }
+ br.close();
+
+ int exitValue = process.waitFor();
+ log += BytecodeViewer.nl + BytecodeViewer.nl + "Exit Value is " + exitValue;
+ s = log;
+
+ //if the motherfucker failed this'll fail, aka wont set.
+ s = DiskReader.loadAsString(tempDirectory.getAbsolutePath() + BytecodeViewer.fs + cn.name + ".j");
+ } catch (Exception e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ e.printStackTrace();
+ s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
} finally {
BytecodeViewer.sm.setBlocking();
}
diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java b/src/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java
index ad6dec49..ce9136d2 100644
--- a/src/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java
+++ b/src/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java
@@ -35,8 +35,7 @@ import com.strobel.assembler.metadata.TypeDefinition;
import com.strobel.assembler.metadata.TypeReference;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.JarUtils;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -134,17 +133,16 @@ public class ProcyonDecompiler extends Decompiler {
throw new Exception("Unable to resolve type.");
}
StringWriter stringwriter = new StringWriter();
- settings.getLanguage().decompileType(resolvedType,
- new PlainTextOutput(stringwriter), decompilationOptions);
+ settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(stringwriter), decompilationOptions);
String decompiledSource = stringwriter.toString();
return decompiledSource;
- } catch (Exception e) {
+ } catch (StackOverflowError | Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
e.printStackTrace();
- exception = "Bytecode Viewer Version: " + BytecodeViewer.version + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
+ exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
}
return "Procyon error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception;
}
@@ -153,7 +151,7 @@ public class ProcyonDecompiler extends Decompiler {
public void decompileToZip(String sourceJar, String zipName) {
try {
doSaveJarDecompiled(new File(sourceJar), new File(zipName));
- } catch (Exception e) {
+ } catch (StackOverflowError | Exception e) {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java b/src/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java
index 5412bf92..96136837 100644
--- a/src/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java
+++ b/src/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java
@@ -9,9 +9,9 @@ import me.konloch.kontainer.io.DiskReader;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.Dex2Jar;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
-import the.bytecode.club.bytecodeviewer.ZipUtils;
+import the.bytecode.club.bytecodeviewer.util.Dex2Jar;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
+import the.bytecode.club.bytecodeviewer.util.ZipUtils;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
diff --git a/src/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPrinter.java b/src/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPrinter.java
index d7c92b23..8e1210df 100644
--- a/src/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPrinter.java
+++ b/src/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPrinter.java
@@ -255,36 +255,38 @@ public class InstructionPrinter {
}
}
- protected String printIincInsnNode(IincInsnNode iin) {
+ protected String printIincInsnNode(IincInsnNode iin)
+ {
return nameOpcode(iin.getOpcode()) + " " + iin.var + " " + iin.incr;
}
- protected String printTableSwitchInsnNode(TableSwitchInsnNode tin) {
+ protected String printTableSwitchInsnNode(TableSwitchInsnNode tin)
+ {
String line = nameOpcode(tin.getOpcode()) + " \n";
List> labels = tin.labels;
int count = 0;
- for (int i = tin.min; i < tin.max + 1; i++) {
- line += " val: " + i + " -> " + "L"
- + resolveLabel((LabelNode) labels.get(count++)) + "\n";
+ for (int i = tin.min; i < tin.max + 1; i++)
+ {
+ line += " val: " + i + " -> " + "L" + resolveLabel((LabelNode) labels.get(count++)) + "\n";
}
- line += " default" + " -> L" + resolveLabel(tin.dflt)
- + "";
+ line += " default" + " -> L" + resolveLabel(tin.dflt) + "";
return line;
}
- protected String printLookupSwitchInsnNode(LookupSwitchInsnNode lin) {
+ protected String printLookupSwitchInsnNode(LookupSwitchInsnNode lin)
+ {
String line = nameOpcode(lin.getOpcode()) + ": \n";
List> keys = lin.keys;
List> labels = lin.labels;
- for (int i = 0; i < keys.size(); i++) {
+ for (int i = 0; i < keys.size(); i++)
+ {
int key = (Integer) keys.get(i);
LabelNode label = (LabelNode) labels.get(i);
- line += " val: " + key + " -> " + "L"
- + resolveLabel(label) + "\n";
+ line += " val: " + key + " -> " + "L" + resolveLabel(label) + "\n";
}
- line += " default" + " -> L" + resolveLabel(lin.dflt)
- + "";
+
+ line += " default" + " -> L" + resolveLabel(lin.dflt) + "";
return line;
}
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java b/src/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java
index 5a447cc3..e7a04c9a 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java
@@ -61,10 +61,10 @@ public class AboutWindow extends JFrame {
public void setVisible(boolean b) {
super.setVisible(b);
textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue()));
- textArea.setText("Bytecode Viewer " + BytecodeViewer.version + " is an open source program developed and maintained by Konloch (konloch@gmail.com) 100% free and open sourced licensed under GPL v3 CopyLeft\r\n\r\n" +
+ textArea.setText("Bytecode Viewer " + BytecodeViewer.VERSION + " is an open source program developed and maintained by Konloch (konloch@gmail.com) 100% free and open sourced licensed under GPL v3 CopyLeft\r\n\r\n" +
"Settings:" + BytecodeViewer.nl +
- " Preview Copy: " + BytecodeViewer.previewCopy + BytecodeViewer.nl +
- " Fat Jar: " + BytecodeViewer.fatJar + BytecodeViewer.nl +
+ " Preview Copy: " + BytecodeViewer.PREVIEW_COPY + BytecodeViewer.nl +
+ " Fat Jar: " + BytecodeViewer.FAT_JAR + BytecodeViewer.nl +
" Java: " + BytecodeViewer.java + BytecodeViewer.nl +
" Javac: " + BytecodeViewer.javac + BytecodeViewer.nl +
" BCV Dir: " + BytecodeViewer.getBCVDirectory() + BytecodeViewer.nl +
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java b/src/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java
index 6a7bbf3d..ac9edd01 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java
@@ -1,10 +1,6 @@
package the.bytecode.club.bytecodeviewer.gui;
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.Font;
+import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
@@ -13,28 +9,14 @@ import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
+import java.io.File;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JSplitPane;
-import javax.swing.JTextField;
-import javax.swing.SwingUtilities;
-import javax.swing.text.AbstractDocument;
-import javax.swing.text.BoxView;
-import javax.swing.text.ComponentView;
-import javax.swing.text.DefaultHighlighter;
-import javax.swing.text.Element;
-import javax.swing.text.Highlighter;
-import javax.swing.text.IconView;
-import javax.swing.text.JTextComponent;
-import javax.swing.text.LabelView;
-import javax.swing.text.StyleConstants;
-import javax.swing.text.StyledEditorKit;
-import javax.swing.text.View;
-import javax.swing.text.ViewFactory;
+import javax.swing.*;
+import javax.swing.text.*;
import javax.swing.text.html.ParagraphView;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
@@ -47,8 +29,13 @@ import org.objectweb.asm.tree.ClassNode;
import com.jhe.hexed.JHexEditor;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
import the.bytecode.club.bytecodeviewer.Resources;
+import the.bytecode.club.bytecodeviewer.Settings;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
+import the.bytecode.club.bytecodeviewer.util.MethodParser;
+
+import static the.bytecode.club.bytecodeviewer.util.MethodParser.*;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -75,169 +62,8 @@ import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
* @author WaterWolf
*/
-public class ClassViewer extends Viewer {
-
- public void setPanes() {
- if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1None.getModel()))
- pane1 = 0;
- else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Proc.getModel()))
- pane1 = 1;
- else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1CFR.getModel()))
- pane1 = 2;
- else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Fern.getModel()))
- pane1 = 3;
- else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Bytecode.getModel()))
- pane1 = 4;
- else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Hexcode.getModel()))
- pane1 = 5;
- else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Smali.getModel()))
- pane1 = 6;
- else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Krakatau.getModel()))
- pane1 = 7;
- else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1KrakatauBytecode.getModel()))
- pane1 = 8;
- else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1JDGUI.getModel()))
- pane1 = 9;
-
- if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2None.getModel()))
- pane2 = 0;
- else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Proc.getModel()))
- pane2 = 1;
- else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2CFR.getModel()))
- pane2 = 2;
- else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Fern.getModel()))
- pane2 = 3;
- else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Bytecode.getModel()))
- pane2 = 4;
- else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Hexcode.getModel()))
- pane2 = 5;
- else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Smali.getModel()))
- pane2 = 6;
- else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Krakatau.getModel()))
- pane2 = 7;
- else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2KrakatauBytecode.getModel()))
- pane2 = 8;
- else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2JDGUI.getModel()))
- pane2 = 9;
-
- if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3None.getModel()))
- pane3 = 0;
- else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Proc.getModel()))
- pane3 = 1;
- else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3CFR.getModel()))
- pane3 = 2;
- else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Fern.getModel()))
- pane3 = 3;
- else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Bytecode.getModel()))
- pane3 = 4;
- else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Hexcode.getModel()))
- pane3 = 5;
- else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Smali.getModel()))
- pane3 = 6;
- else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Krakatau.getModel()))
- pane3 = 7;
- else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3KrakatauBytecode.getModel()))
- pane3 = 8;
- else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3JDGUI.getModel()))
- pane3 = 9;
- }
-
- public boolean isPanel1Editable() {
- setPanes();
-
- if (pane1 == 1 && BytecodeViewer.viewer.panel1Proc_E.isSelected())
- return true;
- if (pane1 == 2 && BytecodeViewer.viewer.panel1CFR_E.isSelected())
- return true;
- if (pane1 == 3 && BytecodeViewer.viewer.panel1Fern_E.isSelected())
- return true;
- if (pane1 == 6 && BytecodeViewer.viewer.panel1Smali_E.isSelected())
- return true;
- if (pane1 == 9 && BytecodeViewer.viewer.panel1JDGUI_E.isSelected())
- return true;
- if ((pane1 == 7 || pane1 == 8) && BytecodeViewer.viewer.panel1Krakatau_E.isSelected())
- return true;
-
-
- return false;
- }
-
- public boolean isPanel2Editable() {
- setPanes();
-
- if (pane2 == 1 && BytecodeViewer.viewer.panel2Proc_E.isSelected())
- return true;
- if (pane2 == 2 && BytecodeViewer.viewer.panel2CFR_E.isSelected())
- return true;
- if (pane2 == 3 && BytecodeViewer.viewer.panel2Fern_E.isSelected())
- return true;
- if (pane2 == 6 && BytecodeViewer.viewer.panel2Smali_E.isSelected())
- return true;
- if (pane2 == 9 && BytecodeViewer.viewer.panel2JDGUI_E.isSelected())
- return true;
- if ((pane2 == 7 || pane2 == 8) && BytecodeViewer.viewer.panel2Krakatau_E.isSelected())
- return true;
-
-
- return false;
- }
-
- public boolean isPanel3Editable() {
- setPanes();
-
- if (pane3 == 1 && BytecodeViewer.viewer.panel3Proc_E.isSelected())
- return true;
- if (pane3 == 2 && BytecodeViewer.viewer.panel3CFR_E.isSelected())
- return true;
- if (pane3 == 3 && BytecodeViewer.viewer.panel3Fern_E.isSelected())
- return true;
- if (pane3 == 6 && BytecodeViewer.viewer.panel3Smali_E.isSelected())
- return true;
- if (pane3 == 9 && BytecodeViewer.viewer.panel3JDGUI_E.isSelected())
- return true;
- if ((pane3 == 7 || pane3 == 8) && BytecodeViewer.viewer.panel3Krakatau_E.isSelected())
- return true;
-
-
- return false;
- }
-
- /**
- * Whoever wrote this function, THANK YOU!
- *
- * @param splitter
- * @param proportion
- * @return
- */
- public static JSplitPane setDividerLocation(final JSplitPane splitter,
- final double proportion) {
- if (splitter.isShowing()) {
- if (splitter.getWidth() > 0 && splitter.getHeight() > 0) {
- splitter.setDividerLocation(proportion);
- } else {
- splitter.addComponentListener(new ComponentAdapter() {
- @Override
- public void componentResized(ComponentEvent ce) {
- splitter.removeComponentListener(this);
- setDividerLocation(splitter, proportion);
- }
- });
- }
- } else {
- splitter.addHierarchyListener(new HierarchyListener() {
- @Override
- public void hierarchyChanged(HierarchyEvent e) {
- if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0
- && splitter.isShowing()) {
- splitter.removeHierarchyListener(this);
- setDividerLocation(splitter, proportion);
- }
- }
- });
- }
- return splitter;
- }
-
+public class ClassViewer extends Viewer
+{
private static final long serialVersionUID = -8650495368920680024L;
ArrayList lnData = new ArrayList();
String name;
@@ -255,6 +81,8 @@ public class ClassViewer extends Viewer {
int pane1 = -1;
int pane2 = -1;
int pane3 = -1;
+ public List methods = Arrays.asList(new MethodParser(), new MethodParser(), new MethodParser());
+ public List activeLines = Arrays.asList(0, 0, 0);
public RSyntaxTextArea smali1 = null;
public RSyntaxTextArea smali2 = null;
public RSyntaxTextArea smali3 = null;
@@ -264,14 +92,18 @@ public class ClassViewer extends Viewer {
public RSyntaxTextArea java1 = null;
public RSyntaxTextArea java2 = null;
public RSyntaxTextArea java3 = null;
+ public File[] tempFiles;
+ public ClassViewer THIS = this;
/**
* This was really interesting to write.
*
* @author Konloch
*/
- public void search(int pane, String search, boolean next) {
- try {
+ public void search(int pane, String search, boolean next)
+ {
+ try
+ {
Component[] com = null;
if (pane == 0) // bytecode
com = panel1.getComponents();
@@ -283,41 +115,54 @@ public class ClassViewer extends Viewer {
if (com == null) // someone fucked up, lets prevent a nullpointer.
return;
- for (Component c : com) {
- if (c instanceof RTextScrollPane) {
+ for (Component c : com)
+ {
+ if (c instanceof RTextScrollPane)
+ {
RSyntaxTextArea area = (RSyntaxTextArea) ((RTextScrollPane) c)
.getViewport().getComponent(0);
- if (search.isEmpty()) {
+ if (search.isEmpty())
+ {
highlight(pane, area, "");
return;
}
int startLine = area.getDocument().getDefaultRootElement()
.getElementIndex(area.getCaretPosition()) + 1;
+
int currentLine = 1;
boolean canSearch = false;
String[] test = null;
+
if (area.getText().split("\n").length >= 2)
test = area.getText().split("\n");
else
test = area.getText().split("\r");
+
int lastGoodLine = -1;
int firstPos = -1;
boolean found = false;
- if (next) {
- for (String s : test) {
- if (pane == 0 && !check1.isSelected() || pane == 1
- && !check2.isSelected()) {
+ if (next)
+ {
+ for (String s : test)
+ {
+ if (pane == 0 && !check1.isSelected() ||
+ pane == 1 && !check2.isSelected())
+ {
s = s.toLowerCase();
search = search.toLowerCase();
}
- if (currentLine == startLine) {
+ if (currentLine == startLine)
+ {
canSearch = true;
- } else if (s.contains(search)) {
- if (canSearch) {
+ }
+ else if (s.contains(search))
+ {
+ if (canSearch)
+ {
area.setCaretPosition(area.getDocument()
.getDefaultRootElement()
.getElement(currentLine - 1)
@@ -338,9 +183,12 @@ public class ClassViewer extends Viewer {
.getDefaultRootElement()
.getElement(firstPos - 1).getStartOffset());
}
- } else {
+ }
+ else
+ {
canSearch = true;
- for (String s : test) {
+ for (String s : test)
+ {
if (pane == 0 && !check1.isSelected() || pane == 1
&& !check2.isSelected() || pane == 2
&& !check3.isSelected()) {
@@ -348,7 +196,8 @@ public class ClassViewer extends Viewer {
search = search.toLowerCase();
}
- if (s.contains(search)) {
+ if (s.contains(search))
+ {
if (lastGoodLine != -1 && canSearch)
area.setCaretPosition(area.getDocument()
.getDefaultRootElement()
@@ -366,8 +215,8 @@ public class ClassViewer extends Viewer {
if (lastGoodLine != -1
&& area.getDocument()
.getDefaultRootElement()
- .getElementIndex(
- area.getCaretPosition()) + 1 == startLine) {
+ .getElementIndex(area.getCaretPosition()) + 1 == startLine)
+ {
area.setCaretPosition(area.getDocument()
.getDefaultRootElement()
.getElement(lastGoodLine - 1)
@@ -377,7 +226,9 @@ public class ClassViewer extends Viewer {
highlight(pane, area, search);
}
}
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
@@ -420,8 +271,10 @@ public class ClassViewer extends Viewer {
final JTextField field1 = new JTextField();
final JTextField field2 = new JTextField();
final JTextField field3 = new JTextField();
+ public TabbedPane tabbedPane;
- public ClassViewer(final String name, final ClassNode cn) {
+ public ClassViewer(final FileContainer container, final String name, final ClassNode cn) {
+ this.container = container;
JButton byteSearchNext = new JButton();
JButton byteSearchPrev = new JButton();
JPanel byteButtonPane = new JPanel(new BorderLayout());
@@ -551,7 +404,6 @@ public class ClassViewer extends Viewer {
hex.setMaximumSize(new Dimension(0, Integer.MAX_VALUE));
hex.setSize(0, Integer.MAX_VALUE);
- BytecodeViewer.viewer.setIcon(true);
startPaneUpdater(null);
this.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
@@ -590,7 +442,7 @@ public class ClassViewer extends Viewer {
PaneUpdaterThread t3;
public void startPaneUpdater(final JButton button) {
- this.cn = BytecodeViewer.getClassNode(cn.name); //update the classnode
+ this.cn = BytecodeViewer.getClassNode(container, cn.name); //update the classnode
setPanes();
panel1.removeAll();
@@ -630,17 +482,23 @@ public class ClassViewer extends Viewer {
}
final byte[] b = cw.toByteArray();
- Thread t1 = new PaneUpdaterThread() {
+ t1 = new PaneUpdaterThread() {
@Override
public void doShit() {
try {
+ paneId = 0;
+ viewer = THIS;
+ decompiler = pane1;
+
+ BytecodeViewer.viewer.setIcon(true);
if (pane1 == 1) { // procyon
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.procyon.decompileClassNode(cn, b));
+
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel1Editable());
panelArea.addKeyListener(new KeyListener() {
@@ -674,11 +532,11 @@ public class ClassViewer extends Viewer {
}
if (pane1 == 2) {// cfr
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.cfr.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel1Editable());
@@ -719,11 +577,11 @@ public class ClassViewer extends Viewer {
}
if (pane1 == 3) {// fern
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.fernflower.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel1Editable());
@@ -764,11 +622,11 @@ public class ClassViewer extends Viewer {
}
if (pane1 == 4) {// bytecode
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.bytecode.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(false);
@@ -822,12 +680,11 @@ public class ClassViewer extends Viewer {
}
if (pane1 == 6) {//smali bytecode
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(
- panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.smali.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel1Editable());
@@ -867,13 +724,12 @@ public class ClassViewer extends Viewer {
}
if (pane1 == 7) {// krakatau
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(
- panelArea);
- panelArea.setText(Decompiler.krakatau.decompileClassNode(cn, b));
+ scrollPane = new RTextScrollPane(panelArea);
+ panelArea.setText(Decompiler.krakatau.decompileClassNode(tempFiles[0], tempFiles[1], cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel1Editable());
panelArea.addKeyListener(new KeyListener()
@@ -914,12 +770,12 @@ public class ClassViewer extends Viewer {
if (pane1 == 8) {// kraktau bytecode
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
- panelArea.setText(Decompiler.krakatauDA.decompileClassNode(cn, b));
+ scrollPane = new RTextScrollPane(panelArea);
+ panelArea.setText(Decompiler.krakatauDA.decompileClassNode(tempFiles[0], tempFiles[1], cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel1Editable());
krakatau1 = panelArea;
@@ -958,13 +814,11 @@ public class ClassViewer extends Viewer {
}
if (pane1 == 9) {// JD-GUI
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
- panelArea
- .setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
+ panelArea = new RSyntaxTextArea();
+ panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(
- panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.jdgui.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel1Editable());
@@ -1017,16 +871,21 @@ public class ClassViewer extends Viewer {
};
- Thread t2 = new PaneUpdaterThread() {
+ t2 = new PaneUpdaterThread() {
@Override
public void doShit() {
try {
+ paneId = 1;
+ viewer = THIS;
+ decompiler = pane2;
+
+ BytecodeViewer.viewer.setIcon(true);
if (pane2 == 1) {
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.procyon.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel2Editable());
@@ -1060,12 +919,11 @@ public class ClassViewer extends Viewer {
}
if (pane2 == 2) {
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
- panelArea
- .setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
+ panelArea = new RSyntaxTextArea();
+ panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.cfr.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel2Editable());
@@ -1099,12 +957,11 @@ public class ClassViewer extends Viewer {
}
if (pane2 == 3) {
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
- panelArea
- .setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
+ panelArea = new RSyntaxTextArea();
+ panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.fernflower.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel2Editable());
@@ -1138,11 +995,11 @@ public class ClassViewer extends Viewer {
}
if (pane2 == 4) {
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.bytecode.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(false);
@@ -1188,11 +1045,11 @@ public class ClassViewer extends Viewer {
}
if (pane2 == 6) {
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.smali.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel2Editable());
@@ -1226,14 +1083,12 @@ public class ClassViewer extends Viewer {
}
if (pane2 == 7) {// krakatau
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
- panelArea
- .setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
+ panelArea = new RSyntaxTextArea();
+ panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(
- panelArea);
- panelArea.setText(Decompiler.krakatau.decompileClassNode(cn, b));
+ scrollPane = new RTextScrollPane(panelArea);
+ panelArea.setText(Decompiler.krakatau.decompileClassNode(tempFiles[0], tempFiles[1], cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel2Editable());
panelArea.addKeyListener(new KeyListener() {
@@ -1266,14 +1121,12 @@ public class ClassViewer extends Viewer {
}
if (pane2 == 8) {// kraktau bytecode
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
- panelArea
- .setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
+ panelArea = new RSyntaxTextArea();
+ panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(
- panelArea);
- panelArea.setText(Decompiler.krakatauDA.decompileClassNode(cn, b));
+ scrollPane = new RTextScrollPane(panelArea);
+ panelArea.setText(Decompiler.krakatauDA.decompileClassNode(tempFiles[0], tempFiles[1], cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel2Editable());
krakatau2 = panelArea;
@@ -1306,13 +1159,11 @@ public class ClassViewer extends Viewer {
}
if (pane2 == 9) {// JD-GUI
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
- panelArea
- .setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
+ panelArea = new RSyntaxTextArea();
+ panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(
- panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.jdgui.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel2Editable());
@@ -1358,17 +1209,21 @@ public class ClassViewer extends Viewer {
};
- Thread t3 = new PaneUpdaterThread() {
+ t3 = new PaneUpdaterThread() {
@Override
public void doShit() {
try {
+ paneId = 2;
+ viewer = THIS;
+ decompiler = pane3;
+
+ BytecodeViewer.viewer.setIcon(true);
if (pane3 == 1) {
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
- panelArea
- .setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
+ panelArea = new RSyntaxTextArea();
+ panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.procyon.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel3Editable());
@@ -1402,12 +1257,12 @@ public class ClassViewer extends Viewer {
}
if (pane3 == 2) {
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea
.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.cfr.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel3Editable());
@@ -1441,12 +1296,12 @@ public class ClassViewer extends Viewer {
}
if (pane3 == 3) {
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea
.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.fernflower.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel3Editable());
@@ -1480,11 +1335,11 @@ public class ClassViewer extends Viewer {
}
if (pane3 == 4) {
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.bytecode.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(false);
@@ -1530,11 +1385,11 @@ public class ClassViewer extends Viewer {
}
if (pane3 == 6) {
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.smali.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel3Editable());
@@ -1568,12 +1423,12 @@ public class ClassViewer extends Viewer {
}
if (pane3 == 7) {// krakatau
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
+ panelArea = new RSyntaxTextArea();
panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(panelArea);
- panelArea.setText(Decompiler.krakatau.decompileClassNode(cn, b));
+ scrollPane = new RTextScrollPane(panelArea);
+ panelArea.setText(Decompiler.krakatau.decompileClassNode(tempFiles[0], tempFiles[1], cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel3Editable());
panelArea.addKeyListener(new KeyListener() {
@@ -1605,14 +1460,12 @@ public class ClassViewer extends Viewer {
}
if (pane3 == 8) {// kraktau bytecode
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
- panelArea
- .setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
+ panelArea = new RSyntaxTextArea();
+ panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(
- panelArea);
- panelArea.setText(Decompiler.krakatauDA.decompileClassNode(cn, b));
+ scrollPane = new RTextScrollPane(panelArea);
+ panelArea.setText(Decompiler.krakatauDA.decompileClassNode(tempFiles[0], tempFiles[1], cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel3Editable());
krakatau3 = panelArea;
@@ -1645,13 +1498,11 @@ public class ClassViewer extends Viewer {
}
if (pane3 == 9) {// JD-GUI
- RSyntaxTextArea panelArea = new RSyntaxTextArea();
- panelArea
- .setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
+ panelArea = new RSyntaxTextArea();
+ panelArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
panelArea.setCodeFoldingEnabled(true);
panelArea.setAntiAliasingEnabled(true);
- final RTextScrollPane scrollPane = new RTextScrollPane(
- panelArea);
+ scrollPane = new RTextScrollPane(panelArea);
panelArea.setText(Decompiler.jdgui.decompileClassNode(cn, b));
panelArea.setCaretPosition(0);
panelArea.setEditable(isPanel3Editable());
@@ -1700,6 +1551,7 @@ public class ClassViewer extends Viewer {
@Override
public void run()
{
+ BytecodeViewer.viewer.setIcon(true);
while(BytecodeViewer.currentlyDumping)
{
//wait until it's not dumping
@@ -1712,7 +1564,9 @@ public class ClassViewer extends Viewer {
e.printStackTrace();
}
}
- BytecodeViewer.dumpTempFile();
+ tempFiles = BytecodeViewer.dumpTempFile(container);
+
+ BytecodeViewer.viewer.setIcon(false);
if (pane1 > 0)
t1.start();
@@ -1729,9 +1583,10 @@ public class ClassViewer extends Viewer {
if(!BytecodeViewer.warnForEditing)
{
BytecodeViewer.warnForEditing = true;
- if(!BytecodeViewer.viewer.autoCompileOnRefresh.isSelected() && !BytecodeViewer.viewer.autoCompileSmali.isSelected())
+ if(!BytecodeViewer.viewer.autoCompileOnRefresh.isSelected() && !BytecodeViewer.viewer.compileOnSave.isSelected())
{
- BytecodeViewer.showMessage("Make sure to File>Compile (Ctrl + T) whenever you want to test or export your changes.\nYou can set compile automatically on refresh or on save in the settings menu.");
+ BytecodeViewer.showMessage("Make sure to compile (File>Compile or Ctrl + T) whenever you want to test or export your changes.\nYou can set compile automatically on refresh or on save in the settings menu.");
+ Settings.saveSettings();
}
}
}
@@ -1784,7 +1639,7 @@ public class ClassViewer extends Viewer {
}
public String constructPattern() {
- final StringBuffer pattern = new StringBuffer();
+ final StringBuilder pattern = new StringBuilder();
pattern.append(name + " *\\(");
final org.objectweb.asm.Type[] types = org.objectweb.asm.Type
.getArgumentTypes(desc);
@@ -1843,4 +1698,255 @@ public class ClassViewer extends Viewer {
return super.getPreferredSpan(axis);
}
}
+
+
+ public void setPanes() {
+ if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1None.getModel()))
+ pane1 = 0;
+ else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Proc.getModel()))
+ pane1 = 1;
+ else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1CFR.getModel()))
+ pane1 = 2;
+ else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Fern.getModel()))
+ pane1 = 3;
+ else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Bytecode.getModel()))
+ pane1 = 4;
+ else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Hexcode.getModel()))
+ pane1 = 5;
+ else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Smali.getModel()))
+ pane1 = 6;
+ else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Krakatau.getModel()))
+ pane1 = 7;
+ else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1KrakatauBytecode.getModel()))
+ pane1 = 8;
+ else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1JDGUI.getModel()))
+ pane1 = 9;
+
+ if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2None.getModel()))
+ pane2 = 0;
+ else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Proc.getModel()))
+ pane2 = 1;
+ else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2CFR.getModel()))
+ pane2 = 2;
+ else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Fern.getModel()))
+ pane2 = 3;
+ else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Bytecode.getModel()))
+ pane2 = 4;
+ else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Hexcode.getModel()))
+ pane2 = 5;
+ else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Smali.getModel()))
+ pane2 = 6;
+ else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2Krakatau.getModel()))
+ pane2 = 7;
+ else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2KrakatauBytecode.getModel()))
+ pane2 = 8;
+ else if (BytecodeViewer.viewer.panelGroup2.isSelected(BytecodeViewer.viewer.panel2JDGUI.getModel()))
+ pane2 = 9;
+
+ if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3None.getModel()))
+ pane3 = 0;
+ else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Proc.getModel()))
+ pane3 = 1;
+ else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3CFR.getModel()))
+ pane3 = 2;
+ else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Fern.getModel()))
+ pane3 = 3;
+ else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Bytecode.getModel()))
+ pane3 = 4;
+ else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Hexcode.getModel()))
+ pane3 = 5;
+ else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Smali.getModel()))
+ pane3 = 6;
+ else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3Krakatau.getModel()))
+ pane3 = 7;
+ else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3KrakatauBytecode.getModel()))
+ pane3 = 8;
+ else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3JDGUI.getModel()))
+ pane3 = 9;
+ }
+
+ public boolean isPanel1Editable()
+ {
+ setPanes();
+
+ if (pane1 == 1 && BytecodeViewer.viewer.panel1Proc_E.isSelected())
+ return true;
+ if (pane1 == 2 && BytecodeViewer.viewer.panel1CFR_E.isSelected())
+ return true;
+ if (pane1 == 3 && BytecodeViewer.viewer.panel1Fern_E.isSelected())
+ return true;
+ if (pane1 == 6 && BytecodeViewer.viewer.panel1Smali_E.isSelected())
+ return true;
+ if (pane1 == 9 && BytecodeViewer.viewer.panel1JDGUI_E.isSelected())
+ return true;
+ if ((pane1 == 7 || pane1 == 8) && BytecodeViewer.viewer.panel1Krakatau_E.isSelected())
+ return true;
+
+
+ return false;
+ }
+
+ public boolean isPanel2Editable() {
+ setPanes();
+
+ if (pane2 == 1 && BytecodeViewer.viewer.panel2Proc_E.isSelected())
+ return true;
+ if (pane2 == 2 && BytecodeViewer.viewer.panel2CFR_E.isSelected())
+ return true;
+ if (pane2 == 3 && BytecodeViewer.viewer.panel2Fern_E.isSelected())
+ return true;
+ if (pane2 == 6 && BytecodeViewer.viewer.panel2Smali_E.isSelected())
+ return true;
+ if (pane2 == 9 && BytecodeViewer.viewer.panel2JDGUI_E.isSelected())
+ return true;
+ if ((pane2 == 7 || pane2 == 8) && BytecodeViewer.viewer.panel2Krakatau_E.isSelected())
+ return true;
+
+
+ return false;
+ }
+
+ public boolean isPanel3Editable() {
+ setPanes();
+
+ if (pane3 == 1 && BytecodeViewer.viewer.panel3Proc_E.isSelected())
+ return true;
+ if (pane3 == 2 && BytecodeViewer.viewer.panel3CFR_E.isSelected())
+ return true;
+ if (pane3 == 3 && BytecodeViewer.viewer.panel3Fern_E.isSelected())
+ return true;
+ if (pane3 == 6 && BytecodeViewer.viewer.panel3Smali_E.isSelected())
+ return true;
+ if (pane3 == 9 && BytecodeViewer.viewer.panel3JDGUI_E.isSelected())
+ return true;
+ if ((pane3 == 7 || pane3 == 8) && BytecodeViewer.viewer.panel3Krakatau_E.isSelected())
+ return true;
+
+
+ return false;
+ }
+
+ /**
+ * Whoever wrote this function, THANK YOU!
+ *
+ * @param splitter
+ * @param proportion
+ * @return
+ */
+ public static JSplitPane setDividerLocation(final JSplitPane splitter,
+ final double proportion) {
+ if (splitter.isShowing()) {
+ if (splitter.getWidth() > 0 && splitter.getHeight() > 0) {
+ splitter.setDividerLocation(proportion);
+ } else {
+ splitter.addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentResized(ComponentEvent ce) {
+ splitter.removeComponentListener(this);
+ setDividerLocation(splitter, proportion);
+ }
+ });
+ }
+ } else {
+ splitter.addHierarchyListener(new HierarchyListener() {
+ @Override
+ public void hierarchyChanged(HierarchyEvent e) {
+ if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0
+ && splitter.isShowing()) {
+ splitter.removeHierarchyListener(this);
+ setDividerLocation(splitter, proportion);
+ }
+ }
+ });
+ }
+ return splitter;
+ }
+
+
+
+
+
+ public static void selectMethod(RSyntaxTextArea area, int methodLine) {
+ if (methodLine != area.getCaretLineNumber()) {
+ setCaretLine(area, methodLine);
+ setViewLine(area, methodLine);
+ }
+ }
+
+ public static void selectMethod(ClassViewer classViewer, int paneId, Method method) {
+ RSyntaxTextArea area = null;
+ switch(paneId)
+ {
+ case 0:
+ area = classViewer.t1.panelArea;
+ break;
+ case 1:
+ area = classViewer.t2.panelArea;
+ break;
+ case 2:
+ area = classViewer.t3.panelArea;
+ break;
+ }
+
+ if (area != null)
+ {
+ MethodParser methods = classViewer.methods.get(paneId);
+ if (methods != null) {
+ int methodLine = methods.findMethod(method);
+ if (methodLine != -1) {
+ selectMethod(area, methodLine);
+ }
+ }
+ }
+ }
+
+ public static String getLineText(RSyntaxTextArea area, int line) {
+ try {
+ if (line < area.getLineCount()) {
+ int start = area.getLineStartOffset(line);
+ int end = area.getLineEndOffset(line);
+ return area.getText(start, end - start).trim();
+ }
+ } catch (BadLocationException ignored) {
+ }
+ return "";
+ }
+
+ public static int getMaxViewLine(RSyntaxTextArea area) {
+ Container parent = area.getParent();
+ if (parent instanceof JViewport) {
+ JViewport viewport = (JViewport) parent;
+ int y = viewport.getViewSize().height - viewport.getExtentSize().height;
+ int lineHeight = area.getLineHeight();
+ return y >= lineHeight ? y / lineHeight : 0;
+ }
+ return 0;
+ }
+
+ public static int getViewLine(RSyntaxTextArea area) {
+ Container parent = area.getParent();
+ if (parent instanceof JViewport) {
+ JViewport viewport = (JViewport) parent;
+ Point point = viewport.getViewPosition();
+ int lineHeight = area.getLineHeight();
+ return point.y >= lineHeight ? point.y / lineHeight : 0;
+ }
+ return 0;
+ }
+
+ public static void setViewLine(RSyntaxTextArea area, int line) {
+ Container parent = area.getParent();
+ if (parent instanceof JViewport) {
+ JViewport viewport = (JViewport) parent;
+ int maxLine = ClassViewer.getMaxViewLine(area);
+ line = line < maxLine ? line : maxLine;
+ viewport.setViewPosition(new Point(0, line * area.getLineHeight()));
+ }
+ }
+
+ public static void setCaretLine(RSyntaxTextArea area, int line) {
+ try {
+ area.setCaretPosition(area.getLineStartOffset(line));
+ } catch (BadLocationException ignored) {}
+ }
}
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/DelayTabbedPaneThread.java b/src/the/bytecode/club/bytecodeviewer/gui/DelayTabbedPaneThread.java
new file mode 100644
index 00000000..288fa7ca
--- /dev/null
+++ b/src/the/bytecode/club/bytecodeviewer/gui/DelayTabbedPaneThread.java
@@ -0,0 +1,49 @@
+package the.bytecode.club.bytecodeviewer.gui;
+
+import the.bytecode.club.bytecodeviewer.BytecodeViewer;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author Konloch
+ */
+public class DelayTabbedPaneThread extends Thread
+{
+ public boolean stopped = false;
+ private TabbedPane pane;
+
+ public DelayTabbedPaneThread(TabbedPane pane)
+ {
+ this.pane = pane;
+ }
+
+ @Override
+ public void run()
+ {
+ try
+ {
+ sleep(200);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ if(!stopped)
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ if(stopped)
+ return;
+
+ pane.label.setOpaque(true);
+ pane.label.setBackground(Color.MAGENTA);
+ pane.label.updateUI();
+ }
+ });
+ }
+ }
+}
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/ExportJar.java b/src/the/bytecode/club/bytecodeviewer/gui/ExportJar.java
index 7a8e05c9..5ded38eb 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/ExportJar.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/ExportJar.java
@@ -5,7 +5,7 @@ import java.awt.Dimension;
import javax.swing.JButton;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.JarUtils;
+import the.bytecode.club.bytecodeviewer.util.JarUtils;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/FileNavigationPane.java b/src/the/bytecode/club/bytecodeviewer/gui/FileNavigationPane.java
index 4d0f1558..e0b40d26 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/FileNavigationPane.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/FileNavigationPane.java
@@ -42,6 +42,9 @@ import javax.swing.tree.TreePath;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.*;
+import the.bytecode.club.bytecodeviewer.util.FileChangeNotifier;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
+import the.bytecode.club.bytecodeviewer.util.FileDrop;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -158,7 +161,7 @@ public class FileNavigationPane extends VisibleComponent implements
if (((String) (node.getUserObject())).toLowerCase().contains(path[path.length - 1].toLowerCase())) {
TreeNode pathArray[] = node.getPath();
int k = 0;
- StringBuffer fullPath = new StringBuffer();
+ StringBuilder fullPath = new StringBuilder();
while (pathArray != null
&& k < pathArray.length) {
MyTreeNode n = (MyTreeNode) pathArray[k];
@@ -212,8 +215,9 @@ public class FileNavigationPane extends VisibleComponent implements
@Override
public void actionPerformed(ActionEvent e) {
final TreeNode root = (TreeNode) tree.getModel().getRoot();
- expandAll(tree, new TreePath(root), false);
- tree.expandPath(new TreePath(root));
+ final TreePath path = new TreePath(root);
+ expandAll(tree, path, false);
+ tree.expandPath(path);
}
});
@@ -254,12 +258,16 @@ public class FileNavigationPane extends VisibleComponent implements
openPath(tree.getSelectionPath());
}
}
- else if((int)e.getKeyChar() != 0 && (int)e.getKeyChar() != 65535)
+ else if((int)e.getKeyChar() != 0 && (int)e.getKeyChar() != 65535 && !e.isControlDown() && !e.isAltDown())
{
quickSearch.grabFocus();
quickSearch.setText("" + e.getKeyChar());
cancel = true;
}
+ else if(e.isControlDown() && (int)e.getKeyChar() == 6) //ctrl + f
+ {
+ quickSearch.grabFocus();
+ }
else
{
cancel = true;
@@ -307,12 +315,12 @@ public class FileNavigationPane extends VisibleComponent implements
new FileDrop(this, this);
}
- public void openClassFileToWorkSpace(final String name, final ClassNode node) {
- fcn.openClassFile(name, node);
+ public void openClassFileToWorkSpace(final FileContainer container, final String name, final ClassNode node) {
+ fcn.openClassFile(container, name, node);
}
- public void openFileToWorkSpace(String name, byte[] contents) {
- fcn.openFile(name, contents);
+ public void openFileToWorkSpace(final FileContainer container, String name, byte[] contents) {
+ fcn.openFile(container, name, contents);
}
@Override
@@ -545,10 +553,12 @@ public class FileNavigationPane extends VisibleComponent implements
tree.updateUI();
}
- public void openPath(TreePath path) {
+ public void openPath(TreePath path)
+ {
if (path == null)
return;
- final StringBuffer nameBuffer = new StringBuffer();
+
+ final StringBuilder nameBuffer = new StringBuilder();
for (int i = 2; i < path.getPathCount(); i++) {
nameBuffer.append(path.getPathComponent(i));
if (i < path.getPathCount() - 1) {
@@ -556,14 +566,25 @@ public class FileNavigationPane extends VisibleComponent implements
}
}
+ String cheapHax = path.getPathComponent(1).toString();
+ FileContainer container = null;
+
+ for(FileContainer c : BytecodeViewer.files)
+ {
+ if(c.name.equals(cheapHax))
+ container = c;
+ }
+
String name = nameBuffer.toString();
- if (name.endsWith(".class")) {
- final ClassNode cn = BytecodeViewer.getClassNode(name.substring(0, name.length() - ".class".length()));
+ if (name.endsWith(".class"))
+ {
+
+ final ClassNode cn = BytecodeViewer.getClassNode(container, name.substring(0, name.length() - ".class".length()));
if (cn != null) {
- openClassFileToWorkSpace(nameBuffer.toString(), cn);
+ openClassFileToWorkSpace(container, nameBuffer.toString(), cn);
}
} else {
- openFileToWorkSpace(nameBuffer.toString(), BytecodeViewer.getFileContents(nameBuffer.toString()));
+ openFileToWorkSpace(container, nameBuffer.toString(), BytecodeViewer.getFileContents(nameBuffer.toString()));
}
}
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/FileViewer.java b/src/the/bytecode/club/bytecodeviewer/gui/FileViewer.java
index 0735a4ce..9ac8b638 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/FileViewer.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/FileViewer.java
@@ -34,6 +34,7 @@ import org.imgscalr.Scalr;
import com.jhe.hexed.JHexEditor;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
import the.bytecode.club.bytecodeviewer.Resources;
/***************************************************************************
@@ -73,6 +74,7 @@ public class FileViewer extends Viewer {
final JTextField field = new JTextField();
public BufferedImage image;
boolean canRefresh = false;
+ public TabbedPane tabbedPane;
public void setContents() {
String name = this.name.toLowerCase();
@@ -126,7 +128,9 @@ public class FileViewer extends Viewer {
} catch (Exception e) {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
- } else {
+ }
+ else if(BytecodeViewer.viewer.forcePureAsciiAsText.isSelected())
+ {
JHexEditor hex = new JHexEditor(contents);
panel2.add(hex);
return;
@@ -209,9 +213,10 @@ public class FileViewer extends Viewer {
return asciiEncoder.canEncode(v);
}
- public FileViewer(final String name, final byte[] contents) {
+ public FileViewer(final FileContainer container, final String name, final byte[] contents) {
this.name = name;
this.contents = contents;
+ this.container = container;
this.setName(name);
this.setLayout(new BorderLayout());
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java b/src/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java
index f3661657..62c73610 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java
@@ -6,11 +6,7 @@ import java.awt.Dimension;
import java.awt.Frame;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
+import java.awt.event.*;
import java.io.File;
import java.util.ArrayList;
@@ -35,19 +31,14 @@ import me.konloch.kontainer.io.DiskWriter;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
-import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.Dex2Jar;
-import the.bytecode.club.bytecodeviewer.FileChangeNotifier;
-import the.bytecode.club.bytecodeviewer.FileContainer;
-import the.bytecode.club.bytecodeviewer.JarUtils;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
-import the.bytecode.club.bytecodeviewer.Resources;
+import the.bytecode.club.bytecodeviewer.*;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameClasses;
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameFields;
import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameMethods;
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.*;
+import the.bytecode.club.bytecodeviewer.util.*;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
@@ -71,163 +62,12 @@ import javax.swing.SpinnerNumberModel;
***************************************************************************/
/**
- * The main file for the GUI.n
+ * The main file for the GUI
*
* @author Konloch
*/
-public class MainViewerGUI extends JFrame implements FileChangeNotifier {
-
- public void pythonC() {
- JFileChooser fc = new JFileChooser();
- fc.setFileFilter(new FileFilter() {
- @Override
- public boolean accept(File f) {
- return true;
- }
-
- @Override
- public String getDescription() {
- return "Python (Or PyPy for speed) 2.7 Executable";
- }
- });
- fc.setFileHidingEnabled(false);
- fc.setAcceptAllFileFilterUsed(false);
- int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
-
- if (returnVal == JFileChooser.APPROVE_OPTION)
- try {
- BytecodeViewer.python = fc.getSelectedFile().getAbsolutePath();
- } catch (Exception e1) {
- new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
- }
- }
-
- public void javac() {
- JFileChooser fc = new JFileChooser();
- fc.setFileFilter(new FileFilter() {
- @Override
- public boolean accept(File f) {
- return true;
- }
-
- @Override
- public String getDescription() {
- return "Javac Executable (Requires JDK 'C:/programfiles/Java/JDK_xx/bin/javac.exe)";
- }
- });
- fc.setFileHidingEnabled(false);
- fc.setAcceptAllFileFilterUsed(false);
- int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
-
- if (returnVal == JFileChooser.APPROVE_OPTION)
- try {
- BytecodeViewer.javac = fc.getSelectedFile().getAbsolutePath();
- } catch (Exception e1) {
- new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
- }
- }
-
- public void java() {
- JFileChooser fc = new JFileChooser();
- fc.setFileFilter(new FileFilter() {
- @Override
- public boolean accept(File f) {
- return true;
- }
-
- @Override
- public String getDescription() {
- return "Java Executable (Inside Of JRE/JDK 'C:/programfiles/Java/JDK_xx/bin/java.exe')";
- }
- });
- fc.setFileHidingEnabled(false);
- fc.setAcceptAllFileFilterUsed(false);
- int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
-
- if (returnVal == JFileChooser.APPROVE_OPTION)
- try {
- BytecodeViewer.java = fc.getSelectedFile().getAbsolutePath();
- } catch (Exception e1) {
- new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
- }
- }
-
- public void pythonC3() {
- JFileChooser fc = new JFileChooser();
- fc.setFileFilter(new FileFilter() {
- @Override
- public boolean accept(File f) {
- return true;
- }
-
- @Override
- public String getDescription() {
- return "Python (Or PyPy for speed) 3.x Executable";
- }
- });
- fc.setFileHidingEnabled(false);
- fc.setAcceptAllFileFilterUsed(false);
- int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
-
- if (returnVal == JFileChooser.APPROVE_OPTION)
- try {
- BytecodeViewer.python3 = fc.getSelectedFile().getAbsolutePath();
- } catch (Exception e1) {
- new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
- }
- }
-
- public void library() {
- JFileChooser fc = new JFileChooser();
- fc.setFileFilter(new FileFilter() {
- @Override
- public boolean accept(File f) {
- return f.isDirectory();
- }
-
- @Override
- public String getDescription() {
- return "Optional Library Folder";
- }
- });
- fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- fc.setFileHidingEnabled(false);
- fc.setAcceptAllFileFilterUsed(false);
- int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
-
- if (returnVal == JFileChooser.APPROVE_OPTION)
- try {
- BytecodeViewer.library = fc.getSelectedFile().getAbsolutePath();
- } catch (Exception e1) {
- new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
- }
- }
-
-
- public void rtC() {
- JFileChooser fc = new JFileChooser();
- fc.setFileFilter(new FileFilter() {
- @Override
- public boolean accept(File f) {
- return true;
- }
-
- @Override
- public String getDescription() {
- return "JRE RT Library";
- }
- });
- fc.setFileHidingEnabled(false);
- fc.setAcceptAllFileFilterUsed(false);
- int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
-
- if (returnVal == JFileChooser.APPROVE_OPTION)
- try {
- BytecodeViewer.rt = fc.getSelectedFile().getAbsolutePath();
- } catch (Exception e1) {
- new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
- }
- }
+public class MainViewerGUI extends JFrame implements FileChangeNotifier
+{
public static final long serialVersionUID = 1851409230530948543L;
public JCheckBoxMenuItem debugHelpers = new JCheckBoxMenuItem("Debug Helpers");
@@ -235,210 +75,124 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
public JSplitPane sp2;
static ArrayList rfComps = new ArrayList();
public JCheckBoxMenuItem rbr = new JCheckBoxMenuItem("Hide bridge methods");
- public JCheckBoxMenuItem rsy = new JCheckBoxMenuItem(
- "Hide synthetic class members");
- public JCheckBoxMenuItem din = new JCheckBoxMenuItem(
- "Decompile inner classes");
- public JCheckBoxMenuItem dc4 = new JCheckBoxMenuItem(
- "Collapse 1.4 class references");
+ public JCheckBoxMenuItem rsy = new JCheckBoxMenuItem("Hide synthetic class members");
+ public JCheckBoxMenuItem din = new JCheckBoxMenuItem("Decompile inner classes");
+ public JCheckBoxMenuItem dc4 = new JCheckBoxMenuItem("Collapse 1.4 class references");
public JCheckBoxMenuItem das = new JCheckBoxMenuItem("Decompile assertions");
- public JCheckBoxMenuItem hes = new JCheckBoxMenuItem(
- "Hide empty super invocation");
- public JCheckBoxMenuItem hdc = new JCheckBoxMenuItem(
- "Hide empty default constructor");
- public JCheckBoxMenuItem dgs = new JCheckBoxMenuItem(
- "Decompile generic signatures");
- public JCheckBoxMenuItem ner = new JCheckBoxMenuItem(
- "Assume return not throwing exceptions");
- public JCheckBoxMenuItem den = new JCheckBoxMenuItem(
- "Decompile enumerations");
- public JCheckBoxMenuItem rgn = new JCheckBoxMenuItem(
- "Remove getClass() invocation");
- public JCheckBoxMenuItem bto = new JCheckBoxMenuItem(
- "Interpret int 1 as boolean true");
- public JCheckBoxMenuItem nns = new JCheckBoxMenuItem(
- "Allow for not set synthetic attribute");
- public JCheckBoxMenuItem uto = new JCheckBoxMenuItem(
- "Consider nameless types as java.lang.Object");
- public JCheckBoxMenuItem udv = new JCheckBoxMenuItem(
- "Reconstruct variable names from debug info");
- public JCheckBoxMenuItem rer = new JCheckBoxMenuItem(
- "Remove empty exception ranges");
- public JCheckBoxMenuItem fdi = new JCheckBoxMenuItem(
- "Deinline finally structures");
- public JCheckBoxMenuItem asc = new JCheckBoxMenuItem(
- "Allow only ASCII characters in strings");
+ public JCheckBoxMenuItem hes = new JCheckBoxMenuItem("Hide empty super invocation");
+ public JCheckBoxMenuItem hdc = new JCheckBoxMenuItem("Hide empty default constructor");
+ public JCheckBoxMenuItem dgs = new JCheckBoxMenuItem("Decompile generic signatures");
+ public JCheckBoxMenuItem ner = new JCheckBoxMenuItem("Assume return not throwing exceptions");
+ public JCheckBoxMenuItem den = new JCheckBoxMenuItem("Decompile enumerations");
+ public JCheckBoxMenuItem rgn = new JCheckBoxMenuItem("Remove getClass() invocation");
+ public JCheckBoxMenuItem bto = new JCheckBoxMenuItem("Interpret int 1 as boolean true");
+ public JCheckBoxMenuItem nns = new JCheckBoxMenuItem("Allow for not set synthetic attribute");
+ public JCheckBoxMenuItem uto = new JCheckBoxMenuItem("Consider nameless types as java.lang.Object");
+ public JCheckBoxMenuItem udv = new JCheckBoxMenuItem("Reconstruct variable names from debug info");
+ public JCheckBoxMenuItem rer = new JCheckBoxMenuItem("Remove empty exception ranges");
+ public JCheckBoxMenuItem fdi = new JCheckBoxMenuItem("Deinline finally structures");
+ public JCheckBoxMenuItem asc = new JCheckBoxMenuItem("Allow only ASCII characters in strings");
public final JMenuItem mntmNewWorkspace = new JMenuItem("New Workspace");
public JMenu mnRecentFiles = new JMenu("Recent Files");
- public final JMenuItem mntmNewMenuItem = new JMenuItem(
- "Decompile & Save All Classes..");
+ public final JMenuItem mntmNewMenuItem = new JMenuItem("Decompile & Save All Classes..");
public final JMenuItem mntmAbout = new JMenuItem("About");
public final JSeparator separator_3 = new JSeparator();
public final JMenu mnNewMenu_1 = new JMenu("Plugins");
- public final JMenuItem mntmStartExternalPlugin = new JMenuItem(
- "Open Plugin..");
+ public final JMenuItem mntmStartExternalPlugin = new JMenuItem("Open Plugin..");
public final JSeparator separator_4 = new JSeparator();
public JMenu mnRecentPlugins = new JMenu("Recent Plugins");
public final JSeparator separator_5 = new JSeparator();
- public final JMenuItem mntmStartZkmString = new JMenuItem(
- "ZKM String Decrypter");
- public final JMenuItem mntmNewMenuItem_1 = new JMenuItem(
- "Malicious Code Scanner");
- public final JMenuItem mntmNewMenuItem_2 = new JMenuItem(
- "Allatori String Decrypter");
- public final JMenuItem mntmShowAllStrings = new JMenuItem(
- "Show All Strings");
- public final JMenuItem mntmShowMainMethods = new JMenuItem(
- "Show Main Methods");
+ public final JMenuItem mntmStartZkmString = new JMenuItem("ZKM String Decrypter");
+ public final JMenuItem mntmNewMenuItem_1 = new JMenuItem("Malicious Code Scanner");
+ public final JMenuItem mntmNewMenuItem_2 = new JMenuItem("Allatori String Decrypter");
+ public final JMenuItem mntmShowAllStrings = new JMenuItem("Show All Strings");
+ public final JMenuItem mntmShowMainMethods = new JMenuItem("Show Main Methods");
public final JMenuItem mntmNewMenuItem_3 = new JMenuItem("Save As Runnable Jar..");
public JMenuBar menuBar = new JMenuBar();
- public final JMenuItem mntmReplaceStrings = new JMenuItem(
- "Replace Strings");
- public final JMenuItem mntmStackFramesRemover = new JMenuItem(
- "StackFrames Remover");
+ public final JMenuItem mntmReplaceStrings = new JMenuItem("Replace Strings");
+ public final JMenuItem mntmStackFramesRemover = new JMenuItem("StackFrames Remover");
public final JMenuItem[] waitIcons;
public final JMenu mnNewMenu_3 = new JMenu("CFR");
public final JMenu mnNewMenu_4 = new JMenu("Procyon");
- public final JCheckBoxMenuItem decodeenumswitch = new JCheckBoxMenuItem(
- "Decode Enum Switch");
- public final JCheckBoxMenuItem sugarenums = new JCheckBoxMenuItem(
- "SugarEnums");
- public final JCheckBoxMenuItem decodestringswitch = new JCheckBoxMenuItem(
- "Decode String Switch");
- public final JCheckBoxMenuItem arrayiter = new JCheckBoxMenuItem(
- "Arrayiter");
- public final JCheckBoxMenuItem collectioniter = new JCheckBoxMenuItem(
- "Collectioniter");
- public final JCheckBoxMenuItem innerclasses = new JCheckBoxMenuItem(
- "Inner Classes");
- public final JCheckBoxMenuItem removeboilerplate = new JCheckBoxMenuItem(
- "Remove Boiler Plate");
- public final JCheckBoxMenuItem removeinnerclasssynthetics = new JCheckBoxMenuItem(
- "Remove Inner Class Synthetics");
- public final JCheckBoxMenuItem decodelambdas = new JCheckBoxMenuItem(
- "Decode Lambdas");
- public final JCheckBoxMenuItem hidebridgemethods = new JCheckBoxMenuItem(
- "Hide Bridge Methods");
- public final JCheckBoxMenuItem liftconstructorinit = new JCheckBoxMenuItem(
- "Lift Constructor Init");
- public final JCheckBoxMenuItem removedeadmethods = new JCheckBoxMenuItem(
- "Remove Dead Methods");
- public final JCheckBoxMenuItem removebadgenerics = new JCheckBoxMenuItem(
- "Remove Bad Generics");
- public final JCheckBoxMenuItem sugarasserts = new JCheckBoxMenuItem(
- "Sugar Asserts");
- public final JCheckBoxMenuItem sugarboxing = new JCheckBoxMenuItem(
- "Sugar Boxing");
- public final JCheckBoxMenuItem showversion = new JCheckBoxMenuItem(
- "Show Version");
- public final JCheckBoxMenuItem decodefinally = new JCheckBoxMenuItem(
- "Decode Finally");
- public final JCheckBoxMenuItem tidymonitors = new JCheckBoxMenuItem(
- "Tidy Monitors");
+ public final JCheckBoxMenuItem decodeenumswitch = new JCheckBoxMenuItem("Decode Enum Switch");
+ public final JCheckBoxMenuItem sugarenums = new JCheckBoxMenuItem("SugarEnums");
+ public final JCheckBoxMenuItem decodestringswitch = new JCheckBoxMenuItem("Decode String Switch");
+ public final JCheckBoxMenuItem arrayiter = new JCheckBoxMenuItem("Arrayiter");
+ public final JCheckBoxMenuItem collectioniter = new JCheckBoxMenuItem("Collectioniter");
+ public final JCheckBoxMenuItem innerclasses = new JCheckBoxMenuItem("Inner Classes");
+ public final JCheckBoxMenuItem removeboilerplate = new JCheckBoxMenuItem("Remove Boiler Plate");
+ public final JCheckBoxMenuItem removeinnerclasssynthetics = new JCheckBoxMenuItem("Remove Inner Class Synthetics");
+ public final JCheckBoxMenuItem decodelambdas = new JCheckBoxMenuItem("Decode Lambdas");
+ public final JCheckBoxMenuItem hidebridgemethods = new JCheckBoxMenuItem("Hide Bridge Methods");
+ public final JCheckBoxMenuItem liftconstructorinit = new JCheckBoxMenuItem("Lift Constructor Init");
+ public final JCheckBoxMenuItem removedeadmethods = new JCheckBoxMenuItem("Remove Dead Methods");
+ public final JCheckBoxMenuItem removebadgenerics = new JCheckBoxMenuItem("Remove Bad Generics");
+ public final JCheckBoxMenuItem sugarasserts = new JCheckBoxMenuItem("Sugar Asserts");
+ public final JCheckBoxMenuItem sugarboxing = new JCheckBoxMenuItem("Sugar Boxing");
+ public final JCheckBoxMenuItem showversion = new JCheckBoxMenuItem("Show Version");
+ public final JCheckBoxMenuItem decodefinally = new JCheckBoxMenuItem("Decode Finally");
+ public final JCheckBoxMenuItem tidymonitors = new JCheckBoxMenuItem("Tidy Monitors");
public final JCheckBoxMenuItem lenient = new JCheckBoxMenuItem("Lenient");
- public final JCheckBoxMenuItem dumpclasspath = new JCheckBoxMenuItem(
- "Dump Classpath");
+ public final JCheckBoxMenuItem dumpclasspath = new JCheckBoxMenuItem("Dump Classpath");
public final JCheckBoxMenuItem comments = new JCheckBoxMenuItem("Comments");
- public final JCheckBoxMenuItem forcetopsort = new JCheckBoxMenuItem(
- "Force Top Sort");
- public final JCheckBoxMenuItem forcetopsortaggress = new JCheckBoxMenuItem(
- "Force Top Sort Aggress");
- public final JCheckBoxMenuItem stringbuffer = new JCheckBoxMenuItem(
- "String Buffer");
- public final JCheckBoxMenuItem stringbuilder = new JCheckBoxMenuItem(
- "String Builder");
+ public final JCheckBoxMenuItem forcetopsort = new JCheckBoxMenuItem("Force Top Sort");
+ public final JCheckBoxMenuItem forcetopsortaggress = new JCheckBoxMenuItem("Force Top Sort Aggress");
+ public final JCheckBoxMenuItem stringbuffer = new JCheckBoxMenuItem("String Buffer");
+ public final JCheckBoxMenuItem stringbuilder = new JCheckBoxMenuItem("String Builder");
public final JCheckBoxMenuItem silent = new JCheckBoxMenuItem("Silent");
public final JCheckBoxMenuItem recover = new JCheckBoxMenuItem("Recover");
public final JCheckBoxMenuItem eclipse = new JCheckBoxMenuItem("Eclipse");
public final JCheckBoxMenuItem override = new JCheckBoxMenuItem("Override");
- public final JCheckBoxMenuItem showinferrable = new JCheckBoxMenuItem(
- "Show Inferrable");
+ public final JCheckBoxMenuItem showinferrable = new JCheckBoxMenuItem("Show Inferrable");
public final JCheckBoxMenuItem aexagg = new JCheckBoxMenuItem("Aexagg");
- public final JCheckBoxMenuItem forcecondpropagate = new JCheckBoxMenuItem(
- "Force Cond Propagate");
+ public final JCheckBoxMenuItem forcecondpropagate = new JCheckBoxMenuItem("Force Cond Propagate");
public final JCheckBoxMenuItem hideutf = new JCheckBoxMenuItem("Hide UTF");
- public final JCheckBoxMenuItem hidelongstrings = new JCheckBoxMenuItem(
- "Hide Long Strings");
- public final JCheckBoxMenuItem commentmonitor = new JCheckBoxMenuItem(
- "Comment Monitors");
- public final JCheckBoxMenuItem allowcorrecting = new JCheckBoxMenuItem(
- "Allow Correcting");
- public final JCheckBoxMenuItem labelledblocks = new JCheckBoxMenuItem(
- "Labelled Blocks");
- public final JCheckBoxMenuItem j14classobj = new JCheckBoxMenuItem(
- "J14ClassOBJ");
- public final JCheckBoxMenuItem hidelangimports = new JCheckBoxMenuItem(
- "Hide Lang Imports");
- public final JCheckBoxMenuItem recoverytypeclash = new JCheckBoxMenuItem(
- "Recover Type Clash");
- public final JCheckBoxMenuItem recoverytypehints = new JCheckBoxMenuItem(
- "Recover Type Hints");
- public final JCheckBoxMenuItem forceturningifs = new JCheckBoxMenuItem(
- "Force Returning IFs");
- public final JCheckBoxMenuItem forloopaggcapture = new JCheckBoxMenuItem(
- "For Loop AGG Capture");
- public final JCheckBoxMenuItem forceexceptionprune = new JCheckBoxMenuItem(
- "Force Exception Prune");
- public final JCheckBoxMenuItem chckbxmntmShowDebugLine = new JCheckBoxMenuItem(
- "Show Debug Line Numbers");
- public final JCheckBoxMenuItem chckbxmntmSimplifyMemberReferences = new JCheckBoxMenuItem(
- "Simplify Member References");
- public final JCheckBoxMenuItem mnMergeVariables = new JCheckBoxMenuItem(
- "Merge Variables");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_1 = new JCheckBoxMenuItem(
- "Unicode Output Enabled");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_2 = new JCheckBoxMenuItem(
- "Retain Pointless Switches");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_3 = new JCheckBoxMenuItem(
- "Include Line Numbers In Bytecode");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_4 = new JCheckBoxMenuItem(
- "Include Error Diagnostics");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_5 = new JCheckBoxMenuItem(
- "Retain Redundant Casts");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_6 = new JCheckBoxMenuItem(
- "Always Generate Exception Variable For Catch Blocks");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_7 = new JCheckBoxMenuItem(
- "Show Synthetic Members");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_8 = new JCheckBoxMenuItem(
- "Force Explicit Type Arguments");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_9 = new JCheckBoxMenuItem(
- "Force Explicit Imports");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_10 = new JCheckBoxMenuItem(
- "Flatten Switch Blocks");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_11 = new JCheckBoxMenuItem(
- "Exclude Nested Types");
- public final JCheckBoxMenuItem chckbxmntmAppendBrackets = new JCheckBoxMenuItem(
- "Append Brackets To Labels");
- public final JCheckBoxMenuItem chckbxmntmNewCheckItem_12 = new JCheckBoxMenuItem(
- "Update Check");
+ public final JCheckBoxMenuItem hidelongstrings = new JCheckBoxMenuItem("Hide Long Strings");
+ public final JCheckBoxMenuItem commentmonitor = new JCheckBoxMenuItem("Comment Monitors");
+ public final JCheckBoxMenuItem allowcorrecting = new JCheckBoxMenuItem("Allow Correcting");
+ public final JCheckBoxMenuItem labelledblocks = new JCheckBoxMenuItem("Labelled Blocks");
+ public final JCheckBoxMenuItem j14classobj = new JCheckBoxMenuItem("J14ClassOBJ");
+ public final JCheckBoxMenuItem hidelangimports = new JCheckBoxMenuItem("Hide Lang Imports");
+ public final JCheckBoxMenuItem recoverytypeclash = new JCheckBoxMenuItem("Recover Type Clash");
+ public final JCheckBoxMenuItem recoverytypehints = new JCheckBoxMenuItem("Recover Type Hints");
+ public final JCheckBoxMenuItem forceturningifs = new JCheckBoxMenuItem("Force Returning IFs");
+ public final JCheckBoxMenuItem forloopaggcapture = new JCheckBoxMenuItem("For Loop AGG Capture");
+ public final JCheckBoxMenuItem forceexceptionprune = new JCheckBoxMenuItem("Force Exception Prune");
+ public final JCheckBoxMenuItem chckbxmntmShowDebugLine = new JCheckBoxMenuItem("Show Debug Line Numbers");
+ public final JCheckBoxMenuItem chckbxmntmSimplifyMemberReferences = new JCheckBoxMenuItem("Simplify Member References");
+ public final JCheckBoxMenuItem mnMergeVariables = new JCheckBoxMenuItem("Merge Variables");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_1 = new JCheckBoxMenuItem("Unicode Output Enabled");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_2 = new JCheckBoxMenuItem("Retain Pointless Switches");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_3 = new JCheckBoxMenuItem("Include Line Numbers In Bytecode");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_4 = new JCheckBoxMenuItem("Include Error Diagnostics");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_5 = new JCheckBoxMenuItem("Retain Redundant Casts");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_6 = new JCheckBoxMenuItem("Always Generate Exception Variable For Catch Blocks");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_7 = new JCheckBoxMenuItem("Show Synthetic Members");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_8 = new JCheckBoxMenuItem("Force Explicit Type Arguments");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_9 = new JCheckBoxMenuItem("Force Explicit Imports");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_10 = new JCheckBoxMenuItem("Flatten Switch Blocks");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_11 = new JCheckBoxMenuItem("Exclude Nested Types");
+ public final JCheckBoxMenuItem chckbxmntmAppendBrackets = new JCheckBoxMenuItem("Append Brackets To Labels");
+ public final JCheckBoxMenuItem chckbxmntmNewCheckItem_12 = new JCheckBoxMenuItem("Update Check");
public final JMenu mnNewMenu_5 = new JMenu("Obfuscate");
public final JMenuItem mntmNewMenuItem_6 = new JMenuItem("Rename Fields");
public final JMenuItem mntmNewMenuItem_7 = new JMenuItem("Rename Methods");
- public final JMenuItem mntmNewMenuItem_8 = new JMenuItem(
- "Move All Classes Into Root Package");
+ public final JMenuItem mntmNewMenuItem_8 = new JMenuItem("Move All Classes Into Root Package");
public final JMenuItem mntmNewMenuItem_9 = new JMenuItem("Control Flow");
public final JMenuItem mntmNewMenuItem_10 = new JMenuItem("Junk Code");
public final ButtonGroup obfuscatorGroup = new ButtonGroup();
- public final JRadioButtonMenuItem strongObf = new JRadioButtonMenuItem(
- "Strong Obfuscation");
- public final JRadioButtonMenuItem lightObf = new JRadioButtonMenuItem(
- "Light Obfuscation");
+ public final JRadioButtonMenuItem strongObf = new JRadioButtonMenuItem("Strong Obfuscation");
+ public final JRadioButtonMenuItem lightObf = new JRadioButtonMenuItem("Light Obfuscation");
public final JMenuItem mntmNewMenuItem_11 = new JMenuItem("Rename Classes");
public final JSeparator separator_2 = new JSeparator();
public final JMenu mnNewMenu_6 = new JMenu("View");
public final JMenu mnNewMenu_7 = new JMenu("Pane 1");
- public final JRadioButtonMenuItem panel1None = new JRadioButtonMenuItem(
- "None");
- public final JRadioButtonMenuItem panel1Hexcode = new JRadioButtonMenuItem(
- "Hexcode");
- public final JRadioButtonMenuItem panel1Bytecode = new JRadioButtonMenuItem(
- "Bytecode");
- public final JRadioButtonMenuItem panel1Fern = new JRadioButtonMenuItem(
- "Java");
- public final JRadioButtonMenuItem panel1CFR = new JRadioButtonMenuItem(
- "Java");
- public final JRadioButtonMenuItem panel1Proc = new JRadioButtonMenuItem(
- "Java");
+ public final JRadioButtonMenuItem panel1None = new JRadioButtonMenuItem("None");
+ public final JRadioButtonMenuItem panel1Hexcode = new JRadioButtonMenuItem("Hexcode");
+ public final JRadioButtonMenuItem panel1Bytecode = new JRadioButtonMenuItem("Bytecode");
+ public final JRadioButtonMenuItem panel1Fern = new JRadioButtonMenuItem("Java");
+ public final JRadioButtonMenuItem panel1CFR = new JRadioButtonMenuItem("Java");
+ public final JRadioButtonMenuItem panel1Proc = new JRadioButtonMenuItem("Java");
public final JMenuItem mntmNewMenuItem_12 = new JMenuItem("Decompile & Save Opened Class..");
public WorkPane workPane = new WorkPane(this);
public final JMenu mnSettings = new JMenu("Settings");
@@ -447,11 +201,14 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
public AboutWindow aboutWindow = new AboutWindow();
public FileNavigationPane cn = new FileNavigationPane(this);
+ public SearchingPane s;
public boolean isMaximized = false;
- public void removed(boolean busy) {
- if (busy) {
+ public void removed(boolean busy)
+ {
+ if (busy)
+ {
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
for (Component c : this.getComponents())
c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
@@ -459,16 +216,20 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
sp1.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
sp2.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
- for (VisibleComponent c : rfComps) {
+ for (VisibleComponent c : rfComps)
+ {
c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
- if (c instanceof WorkPane) {
+ if (c instanceof WorkPane)
+ {
WorkPane w = (WorkPane) c;
for (Component c2 : w.tabs.getComponents())
c2.setCursor(Cursor
.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
}
- } else {
+ }
+ else
+ {
this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
for (Component c : this.getComponents())
c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
@@ -476,9 +237,11 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
sp1.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
sp2.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
- for (VisibleComponent c : rfComps) {
+ for (VisibleComponent c : rfComps)
+ {
c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
- if (c instanceof WorkPane) {
+ if (c instanceof WorkPane)
+ {
WorkPane w = (WorkPane) c;
for (Component c2 : w.tabs.getComponents())
c2.setCursor(Cursor
@@ -488,9 +251,11 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
}
}
- public class Test implements KeyEventDispatcher {
+ public class Test implements KeyEventDispatcher
+ {
@Override
- public boolean dispatchKeyEvent(KeyEvent e) {
+ public boolean dispatchKeyEvent(KeyEvent e)
+ {
BytecodeViewer.checkHotKey(e);
return false;
}
@@ -501,8 +266,10 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
public final JSeparator separator_7 = new JSeparator();
public final JSeparator separator_8 = new JSeparator();
public final JRadioButtonMenuItem panel1Smali = new JRadioButtonMenuItem("Smali/DEX");
- public final JCheckBoxMenuItem autoCompileSmali = new JCheckBoxMenuItem("Compile On Save");
- public final JMenuItem mntmNewMenuItem_13 = new JMenuItem("Compile");
+ public final JCheckBoxMenuItem compileOnSave = new JCheckBoxMenuItem("Compile On Save");
+ public final JCheckBoxMenuItem showFileInTabTitle = new JCheckBoxMenuItem("Show File In Tab Title");
+ public final JCheckBoxMenuItem forcePureAsciiAsText = new JCheckBoxMenuItem("Force Pure Ascii As Text");
+ public final JMenuItem compileButton = new JMenuItem("Compile");
public final JCheckBoxMenuItem autoCompileOnRefresh = new JCheckBoxMenuItem("Compile On Refresh");
public final JMenuItem mntmSetPythonDirectory = new JMenuItem("Set Python 2.7 Executable");
public final JSeparator separator_13 = new JSeparator();
@@ -514,6 +281,8 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
public final JMenuItem mntmRun = new JMenuItem("Run");
public final JSeparator separator_18 = new JSeparator();
public final JCheckBoxMenuItem decodeAPKResources = new JCheckBoxMenuItem("Decode APK Resources");
+ public final JCheckBoxMenuItem synchronizedViewing = new JCheckBoxMenuItem("Synchronized Viewing");
+ public final JCheckBoxMenuItem showClassMethods = new JCheckBoxMenuItem("Show Class Methods");
public final JMenu mnProcyon = new JMenu("Procyon");
public final JCheckBoxMenuItem panel1Proc_E = new JCheckBoxMenuItem("Editable");
public final JSeparator separator_14 = new JSeparator();
@@ -586,18 +355,25 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
public final JRadioButtonMenuItem panel3Bytecode = new JRadioButtonMenuItem("Bytecode");
public final JRadioButtonMenuItem panel3Hexcode = new JRadioButtonMenuItem("Hexcode");
- public synchronized void setIcon(final boolean busy) {
- SwingUtilities.invokeLater(new Runnable() {
+ public synchronized void setIcon(final boolean busy)
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
@Override
- public void run() {
- if (busy) {
- for(int i = 0; i < 10; i++)
+ public void run()
+ {
+ if (busy)
+ {
+ for (int i = 0; i < 10; i++)
{
- if(waitIcons[i].getIcon() == null)
+ if (waitIcons[i].getIcon() == null)
{
- try {
+ try
+ {
waitIcons[i].setIcon(Resources.busyIcon);
- } catch (NullPointerException e) {
+ }
+ catch (NullPointerException e)
+ {
waitIcons[i].setIcon(Resources.busyB64Icon);
}
waitIcons[i].updateUI();
@@ -607,10 +383,9 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
}
else
{
-
- for(int i = 0; i < 10; i++)
+ for (int i = 0; i < 10; i++)
{
- if(waitIcons[i].getIcon() != null)
+ if (waitIcons[i].getIcon() != null)
{
waitIcons[i].setIcon(null);
waitIcons[i].updateUI();
@@ -639,9 +414,10 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
private final JSeparator separator_35 = new JSeparator();
public final JCheckBoxMenuItem panel1JDGUI_E = new JCheckBoxMenuItem("Editable");
private final JMenu mnFontSize = new JMenu("Font Size");
+ private final JMenu visualSettings = new JMenu("Visual Settings");
public final JSpinner fontSpinner = new JSpinner();
private final JSeparator separator_36 = new JSeparator();
- private final JCheckBoxMenuItem chckbxmntmDeleteForiegnoutdatedLibs = new JCheckBoxMenuItem("Delete Foriegn/Outdated Libs");
+ private final JCheckBoxMenuItem chckbxmntmDeleteForeignOutdatedLibs = new JCheckBoxMenuItem("Delete Foreign/Outdated Libs");
private final JSeparator separator_37 = new JSeparator();
private final JSeparator separator_38 = new JSeparator();
private final JMenu mnApkConversion = new JMenu("APK Conversion");
@@ -654,37 +430,50 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
private final JSeparator separator_40 = new JSeparator();
private final JMenuItem mntmSetJavacExecutable = new JMenuItem("Set Javac Executable");
- public void calledAfterLoad() {
- chckbxmntmDeleteForiegnoutdatedLibs.setSelected(BytecodeViewer.deleteForiegnLibraries);
+ public void calledAfterLoad()
+ {
+ chckbxmntmDeleteForeignOutdatedLibs.setSelected(BytecodeViewer.deleteForeignLibraries);
}
- public MainViewerGUI() {
+ public MainViewerGUI()
+ {
mnNewMenu_5.setVisible(false);
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new Test());
- this.addWindowStateListener(new WindowAdapter() {
+ this.addWindowStateListener(new WindowAdapter()
+ {
@Override
- public void windowStateChanged(WindowEvent evt) {
+ public void windowStateChanged(WindowEvent evt)
+ {
int oldState = evt.getOldState();
int newState = evt.getNewState();
- if ((oldState & Frame.ICONIFIED) == 0 && (newState & Frame.ICONIFIED) != 0) {
+ if ((oldState & Frame.ICONIFIED) == 0 && (newState & Frame.ICONIFIED) != 0)
+ {
//System.out.println("Frame was iconized");
- } else if ((oldState & Frame.ICONIFIED) != 0 && (newState & Frame.ICONIFIED) == 0) {
+ }
+ else if ((oldState & Frame.ICONIFIED) != 0 && (newState & Frame.ICONIFIED) == 0)
+ {
//System.out.println("Frame was deiconized");
}
- if ((oldState & Frame.MAXIMIZED_BOTH) == 0 && (newState & Frame.MAXIMIZED_BOTH) != 0) {
+ if ((oldState & Frame.MAXIMIZED_BOTH) == 0 && (newState & Frame.MAXIMIZED_BOTH) != 0)
+ {
isMaximized = true;
- } else if ((oldState & Frame.MAXIMIZED_BOTH) != 0 && (newState & Frame.MAXIMIZED_BOTH) == 0) {
+ }
+ else if ((oldState & Frame.MAXIMIZED_BOTH) != 0 && (newState & Frame.MAXIMIZED_BOTH) == 0)
+ {
isMaximized = false;
}
}
});
this.setIconImages(Resources.iconList);
- ActionListener listener = new ActionListener() {
+ ActionListener listener = new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
- if (refreshOnChange.isSelected()) {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ if (refreshOnChange.isSelected())
+ {
if (workPane.getCurrentViewer() == null)
return;
@@ -708,28 +497,37 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
JMenu mnNewMenu = new JMenu("File");
menuBar.add(mnNewMenu);
- mntmNewWorkspace.addActionListener(new ActionListener() {
+ mntmNewWorkspace.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
+ public void actionPerformed(ActionEvent arg0)
+ {
BytecodeViewer.resetWorkSpace(true);
}
});
JMenuItem mntmLoadJar = new JMenuItem("Add..");
- mntmLoadJar.addActionListener(new ActionListener() {
+ mntmLoadJar.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent e) {
+ public void actionPerformed(ActionEvent e)
+ {
JFileChooser fc = new JFileChooser();
- try {
+ try
+ {
File f = new File(BytecodeViewer.lastDirectory);
if (f.exists())
fc.setSelectedFile(f);
- } catch (Exception e2) {
+ }
+ catch (Exception e2)
+ {
}
- fc.setFileFilter(new FileFilter() {
+ fc.setFileFilter(new FileFilter()
+ {
@Override
- public boolean accept(File f) {
+ public boolean accept(File f)
+ {
if (f.isDirectory())
return true;
@@ -744,7 +542,8 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
}
@Override
- public String getDescription() {
+ public String getDescription()
+ {
return "APKs, DEX, Class Files or Zip/Jar Archives";
}
});
@@ -752,14 +551,18 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
- if (returnVal == JFileChooser.APPROVE_OPTION) {
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ {
BytecodeViewer.lastDirectory = fc.getSelectedFile().getAbsolutePath();
- try {
+ try
+ {
BytecodeViewer.viewer.setIcon(true);
BytecodeViewer.openFiles(new File[]{fc
.getSelectedFile()}, true);
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e1) {
+ }
+ catch (Exception e1)
+ {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
}
}
@@ -773,38 +576,48 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
JMenuItem mntmSave = new JMenuItem("Save As Zip..");
mntmSave.setActionCommand("");
- mntmSave.addActionListener(new ActionListener() {
+ mntmSave.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
- if (BytecodeViewer.getLoadedClasses().isEmpty()) {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ if (BytecodeViewer.getLoadedClasses().isEmpty())
+ {
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
return;
}
- Thread t = new Thread() {
- public void run() {
- if (autoCompileSmali.isSelected() && !BytecodeViewer.compile(false))
+ Thread t = new Thread()
+ {
+ public void run()
+ {
+ if (compileOnSave.isSelected() && !BytecodeViewer.compile(false))
return;
JFileChooser fc = new JFileChooser();
- fc.setFileFilter(new FileFilter() {
+ fc.setFileFilter(new FileFilter()
+ {
@Override
- public boolean accept(File f) {
+ public boolean accept(File f)
+ {
return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("zip");
}
@Override
- public String getDescription() {
+ public String getDescription()
+ {
return "Zip Archives";
}
});
fc.setFileHidingEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
- if (returnVal == JFileChooser.APPROVE_OPTION) {
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ {
File file = fc.getSelectedFile();
if (!file.getAbsolutePath().endsWith(".zip"))
file = new File(file.getAbsolutePath() + ".zip");
- if (file.exists()) {
+ if (file.exists())
+ {
JOptionPane pane = new JOptionPane(
"Are you sure you wish to overwrite this existing file?");
Object[] options = new String[]{"Yes", "No"};
@@ -818,9 +631,12 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
if (options[k].equals(obj))
result = k;
- if (result == 0) {
+ if (result == 0)
+ {
file.delete();
- } else {
+ }
+ else
+ {
return;
}
}
@@ -828,9 +644,11 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
final File file2 = file;
BytecodeViewer.viewer.setIcon(true);
- Thread t = new Thread() {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
+ public void run()
+ {
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(),
file2.getAbsolutePath());
BytecodeViewer.viewer.setIcon(false);
@@ -845,8 +663,10 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
});
mnNewMenu.add(separator_39);
- mntmReloadResources.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent arg0) {
+ mntmReloadResources.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent arg0)
+ {
JOptionPane pane = new JOptionPane("Are you sure you wish to reload the resources?");
Object[] options = new String[]{"Yes", "No"};
pane.setOptions(options);
@@ -858,13 +678,16 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
if (options[k].equals(obj))
result = k;
- if (result == 0) {
+ if (result == 0)
+ {
+ LazyNameUtil.reset();
ArrayList reopen = new ArrayList();
for (FileContainer container : BytecodeViewer.files)
{
File newFile = new File(container.file.getParent() + BytecodeViewer.fs + container.name);
- if(!container.file.getAbsolutePath().equals(newFile.getAbsolutePath())) //APKs & dex get renamed
+ if (!container.file.getAbsolutePath().equals(newFile.getAbsolutePath()) &&
+ (container.file.getAbsolutePath().endsWith(".apk") || container.file.getAbsolutePath().endsWith(".dex"))) //APKs & dex get renamed
{
container.file.renameTo(newFile);
container.file = newFile;
@@ -874,7 +697,10 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
BytecodeViewer.files.clear();
- BytecodeViewer.openFiles(reopen.toArray(new File[reopen.size()]), false);
+ for (File f : reopen)
+ {
+ BytecodeViewer.openFiles(new File[]{f}, false);
+ }
//refresh panes
}
@@ -884,39 +710,49 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnNewMenu.add(mntmReloadResources);
mnNewMenu.add(separator_3);
- mntmNewMenuItem_3.addActionListener(new ActionListener() {
+ mntmNewMenuItem_3.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent e) {
- if (BytecodeViewer.getLoadedClasses().isEmpty()) {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (BytecodeViewer.getLoadedClasses().isEmpty())
+ {
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
return;
}
- Thread t = new Thread() {
- public void run() {
- if (autoCompileSmali.isSelected() && !BytecodeViewer.compile(false))
+ Thread t = new Thread()
+ {
+ public void run()
+ {
+ if (compileOnSave.isSelected() && !BytecodeViewer.compile(false))
return;
JFileChooser fc = new JFileChooser();
- fc.setFileFilter(new FileFilter() {
+ fc.setFileFilter(new FileFilter()
+ {
@Override
- public boolean accept(File f) {
+ public boolean accept(File f)
+ {
return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("zip");
}
@Override
- public String getDescription() {
+ public String getDescription()
+ {
return "Zip Archives";
}
});
fc.setFileHidingEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
- if (returnVal == JFileChooser.APPROVE_OPTION) {
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ {
File file = fc.getSelectedFile();
String path = file.getAbsolutePath();
if (!path.endsWith(".jar"))
path = path + ".jar";
- if (new File(path).exists()) {
+ if (new File(path).exists())
+ {
JOptionPane pane = new JOptionPane(
"Are you sure you wish to overwrite this existing file?");
Object[] options = new String[]{"Yes", "No"};
@@ -930,9 +766,12 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
if (options[k].equals(obj))
result = k;
- if (result == 0) {
+ if (result == 0)
+ {
file.delete();
- } else {
+ }
+ else
+ {
return;
}
}
@@ -944,21 +783,28 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
t.start();
}
});
- mntmNewMenuItem_13.addActionListener(new ActionListener() {
+ compileButton.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
- Thread t = new Thread() {
- public void run() {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ Thread t = new Thread()
+ {
+ public void run()
+ {
BytecodeViewer.compile(true);
}
};
t.start();
}
});
- mntmRun.addActionListener(new ActionListener() {
+ mntmRun.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent e) {
- if (BytecodeViewer.getLoadedClasses().isEmpty()) {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (BytecodeViewer.getLoadedClasses().isEmpty())
+ {
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
return;
}
@@ -968,39 +814,48 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnNewMenu.add(mntmRun);
- mnNewMenu.add(mntmNewMenuItem_13);
+ mnNewMenu.add(compileButton);
mnNewMenu.add(separator_18);
mnNewMenu.add(mntmNewMenuItem_3);
- mntmSaveAsApk.addActionListener(new ActionListener() {
+ mntmSaveAsApk.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
- if (BytecodeViewer.getLoadedClasses().isEmpty()) {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ if (BytecodeViewer.getLoadedClasses().isEmpty())
+ {
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
return;
}
- Thread t = new Thread() {
- public void run() {
- if (autoCompileSmali.isSelected() && !BytecodeViewer.compile(false))
+ Thread t = new Thread()
+ {
+ public void run()
+ {
+ if (compileOnSave.isSelected() && !BytecodeViewer.compile(false))
return;
JFileChooser fc = new JFileChooser();
- fc.setFileFilter(new FileFilter() {
+ fc.setFileFilter(new FileFilter()
+ {
@Override
- public boolean accept(File f) {
+ public boolean accept(File f)
+ {
return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("dex");
}
@Override
- public String getDescription() {
+ public String getDescription()
+ {
return "Android DEX Files";
}
});
fc.setFileHidingEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
- if (returnVal == JFileChooser.APPROVE_OPTION) {
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ {
final File file = fc.getSelectedFile();
String output = file.getAbsolutePath();
if (!output.endsWith(".dex"))
@@ -1008,7 +863,8 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
final File file2 = new File(output);
- if (file2.exists()) {
+ if (file2.exists())
+ {
JOptionPane pane = new JOptionPane(
"Are you sure you wish to overwrite this existing file?");
Object[] options = new String[]{"Yes", "No"};
@@ -1022,23 +878,30 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
if (options[k].equals(obj))
result = k;
- if (result == 0) {
+ if (result == 0)
+ {
file.delete();
- } else {
+ }
+ else
+ {
return;
}
}
- Thread t = new Thread() {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
+ public void run()
+ {
BytecodeViewer.viewer.setIcon(true);
final String input = BytecodeViewer.tempDirectory + BytecodeViewer.fs + BytecodeViewer.getRandomizedName() + ".jar";
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
- Thread t = new Thread() {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
+ public void run()
+ {
Dex2Jar.saveAsDex(new File(input), file2);
BytecodeViewer.viewer.setIcon(false);
@@ -1057,39 +920,49 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnNewMenu.add(mntmSaveAsApk);
mnNewMenu.add(mntmSave);
- mntmNewMenuItem.addActionListener(new ActionListener() {
+ mntmNewMenuItem.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
- if (BytecodeViewer.getLoadedClasses().isEmpty()) {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ if (BytecodeViewer.getLoadedClasses().isEmpty())
+ {
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
return;
}
- Thread t = new Thread() {
- public void run() {
- if (autoCompileSmali.isSelected() && !BytecodeViewer.compile(false))
+ Thread t = new Thread()
+ {
+ public void run()
+ {
+ if (compileOnSave.isSelected() && !BytecodeViewer.compile(false))
return;
JFileChooser fc = new JFileChooser();
- fc.setFileFilter(new FileFilter() {
+ fc.setFileFilter(new FileFilter()
+ {
@Override
- public boolean accept(File f) {
+ public boolean accept(File f)
+ {
return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("zip");
}
@Override
- public String getDescription() {
+ public String getDescription()
+ {
return "Zip Archives";
}
});
fc.setFileHidingEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
- if (returnVal == JFileChooser.APPROVE_OPTION) {
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ {
File file = fc.getSelectedFile();
if (!file.getAbsolutePath().endsWith(".zip"))
file = new File(file.getAbsolutePath() + ".zip");
- if (file.exists()) {
+ if (file.exists())
+ {
JOptionPane pane = new JOptionPane(
"Are you sure you wish to overwrite this existing file?");
Object[] options = new String[]{"Yes", "No"};
@@ -1103,9 +976,12 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
if (options[k].equals(obj))
result = k;
- if (result == 0) {
+ if (result == 0)
+ {
file.delete();
- } else {
+ }
+ else
+ {
return;
}
}
@@ -1131,7 +1007,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
BytecodeViewer.viewer.setIcon(true);
- File tempZip = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp_"+BytecodeViewer.getRandomizedName()+".jar");
+ File tempZip = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp_" + BytecodeViewer.getRandomizedName() + ".jar");
if (tempZip.exists())
tempZip.delete();
@@ -1139,94 +1015,132 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
if (result == 0)
{
- Thread t = new Thread() {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
Decompiler.procyon.decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-proycon.zip"));
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
};
t.start();
- Thread t2 = new Thread() {
+ Thread t2 = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
BytecodeViewer.viewer.setIcon(true);
Decompiler.cfr.decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-CFR.zip"));
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
};
t2.start();
- Thread t3 = new Thread() {
+ Thread t3 = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
BytecodeViewer.viewer.setIcon(true);
Decompiler.fernflower.decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-fernflower.zip"));
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
};
t3.start();
- Thread t4 = new Thread() {
+ Thread t4 = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
BytecodeViewer.viewer.setIcon(true);
Decompiler.krakatau.decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-kraktau.zip"));
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
};
t4.start();
}
- if (result == 1) {
- Thread t = new Thread() {
+ if (result == 1)
+ {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
Decompiler.procyon.decompileToZip(tempZip.getAbsolutePath(), path);
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
};
t.start();
}
- if (result == 2) {
- Thread t = new Thread() {
+ if (result == 2)
+ {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
Decompiler.cfr.decompileToZip(tempZip.getAbsolutePath(), path);
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
};
t.start();
}
- if (result == 3) {
- Thread t = new Thread() {
+ if (result == 3)
+ {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
Decompiler.fernflower.decompileToZip(tempZip.getAbsolutePath(), path);
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
@@ -1234,14 +1148,20 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
t.start();
}
- if (result == 4) {
- Thread t = new Thread() {
+ if (result == 4)
+ {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
Decompiler.krakatau.decompileToZip(tempZip.getAbsolutePath(), path);
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
@@ -1249,7 +1169,8 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
t.start();
}
- if (result == 5) {
+ if (result == 5)
+ {
BytecodeViewer.viewer.setIcon(false);
}
}
@@ -1258,47 +1179,57 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
t.start();
}
});
- mntmNewMenuItem_12.addActionListener(new ActionListener() {
+ mntmNewMenuItem_12.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
- if (workPane.getCurrentViewer() == null) {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ if (workPane.getCurrentViewer() == null)
+ {
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
return;
}
- Thread t = new Thread() {
- public void run() {
- if (autoCompileSmali.isSelected() && !BytecodeViewer.compile(false))
+ Thread t = new Thread()
+ {
+ public void run()
+ {
+ if (compileOnSave.isSelected() && !BytecodeViewer.compile(false))
return;
final String s = workPane.getCurrentViewer().cn.name;
- if(s == null)
+ if (s == null)
return;
JFileChooser fc = new JFileChooser();
- fc.setFileFilter(new FileFilter() {
+ fc.setFileFilter(new FileFilter()
+ {
@Override
- public boolean accept(File f) {
+ public boolean accept(File f)
+ {
return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("java");
}
@Override
- public String getDescription() {
+ public String getDescription()
+ {
return "Java Source Files";
}
});
fc.setFileHidingEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
- if (returnVal == JFileChooser.APPROVE_OPTION) {
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ {
File file = fc.getSelectedFile();
BytecodeViewer.viewer.setIcon(true);
final String path = MiscUtils.append(file, ".java"); // cheap hax cause
// string is final
- if (new File(path).exists()) {
+ if (new File(path).exists())
+ {
JOptionPane pane = new JOptionPane(
"Are you sure you wish to overwrite this existing file?");
Object[] options = new String[]{"Yes", "No"};
@@ -1312,9 +1243,12 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
if (options[k].equals(obj))
result = k;
- if (result == 0) {
+ if (result == 0)
+ {
file.delete();
- } else {
+ }
+ else
+ {
return;
}
}
@@ -1333,21 +1267,31 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
if (options[k].equals(obj))
result = k;
- if (result == 0) {
- Thread t = new Thread() {
+ if (result == 0)
+ {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
ClassNode cn = BytecodeViewer.getClassNode(s);
final ClassWriter cw = new ClassWriter(0);
- try {
+ try
+ {
cn.accept(cw);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
e.printStackTrace();
- try {
+ try
+ {
Thread.sleep(200);
cn.accept(cw);
- } catch (InterruptedException e1) {
+ }
+ catch (InterruptedException e1)
+ {
}
}
@@ -1355,7 +1299,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
{
DiskWriter.replaceFile(MiscUtils.append(file, "-proycon.java"), Decompiler.procyon.decompileClassNode(cn, cw.toByteArray()), false);
}
- catch(Exception e)
+ catch (Exception e)
{
e.printStackTrace();
}
@@ -1364,7 +1308,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
{
DiskWriter.replaceFile(MiscUtils.append(file, "-CFR.java"), Decompiler.cfr.decompileClassNode(cn, cw.toByteArray()), false);
}
- catch(Exception e)
+ catch (Exception e)
{
e.printStackTrace();
}
@@ -1373,7 +1317,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
{
DiskWriter.replaceFile(MiscUtils.append(file, "-fernflower.java"), Decompiler.fernflower.decompileClassNode(cn, cw.toByteArray()), false);
}
- catch(Exception e)
+ catch (Exception e)
{
e.printStackTrace();
}
@@ -1382,13 +1326,15 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
{
DiskWriter.replaceFile(MiscUtils.append(file, "-kraktau.java"), Decompiler.krakatau.decompileClassNode(cn, cw.toByteArray()), false);
}
- catch(Exception e)
+ catch (Exception e)
{
e.printStackTrace();
}
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
BytecodeViewer.viewer.setIcon(false);
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
@@ -1396,27 +1342,39 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
};
t.start();
}
- if (result == 1) {
- Thread t = new Thread() {
+ if (result == 1)
+ {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
ClassNode cn = BytecodeViewer.getClassNode(s);
final ClassWriter cw = new ClassWriter(0);
- try {
+ try
+ {
cn.accept(cw);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
e.printStackTrace();
- try {
+ try
+ {
Thread.sleep(200);
cn.accept(cw);
- } catch (InterruptedException e1) {
+ }
+ catch (InterruptedException e1)
+ {
}
}
String contents = Decompiler.procyon.decompileClassNode(cn, cw.toByteArray());
DiskWriter.replaceFile(path, contents, false);
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
BytecodeViewer.viewer.setIcon(false);
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(
e);
@@ -1425,27 +1383,39 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
};
t.start();
}
- if (result == 2) {
- Thread t = new Thread() {
+ if (result == 2)
+ {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
ClassNode cn = BytecodeViewer.getClassNode(s);
final ClassWriter cw = new ClassWriter(0);
- try {
+ try
+ {
cn.accept(cw);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
e.printStackTrace();
- try {
+ try
+ {
Thread.sleep(200);
cn.accept(cw);
- } catch (InterruptedException e1) {
+ }
+ catch (InterruptedException e1)
+ {
}
}
String contents = Decompiler.cfr.decompileClassNode(cn, cw.toByteArray());
DiskWriter.replaceFile(path, contents, false);
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
BytecodeViewer.viewer.setIcon(false);
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(
e);
@@ -1454,28 +1424,40 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
};
t.start();
}
- if (result == 3) {
- Thread t = new Thread() {
+ if (result == 3)
+ {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
ClassNode cn = BytecodeViewer.getClassNode(s);
final ClassWriter cw = new ClassWriter(0);
- try {
+ try
+ {
cn.accept(cw);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
e.printStackTrace();
- try {
+ try
+ {
Thread.sleep(200);
- if(cn != null)
+ if (cn != null)
cn.accept(cw);
- } catch (InterruptedException e1) {
+ }
+ catch (InterruptedException e1)
+ {
}
}
String contents = Decompiler.fernflower.decompileClassNode(cn, cw.toByteArray());
DiskWriter.replaceFile(path, contents, false);
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
BytecodeViewer.viewer.setIcon(false);
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(
e);
@@ -1484,27 +1466,44 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
};
t.start();
}
- if (result == 4) {
- Thread t = new Thread() {
+ if (result == 4)
+ {
+ Thread t = new Thread()
+ {
@Override
- public void run() {
- try {
+ public void run()
+ {
+ try
+ {
ClassNode cn = BytecodeViewer.getClassNode(s);
final ClassWriter cw = new ClassWriter(0);
- try {
+ try
+ {
cn.accept(cw);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
e.printStackTrace();
- try {
+ try
+ {
Thread.sleep(200);
cn.accept(cw);
- } catch (InterruptedException e1) {
}
+ catch (InterruptedException e1)
+ {
+ }
+ }
+
+ if (LazyNameUtil.SAME_NAME_JAR_WORKSPACE)
+ {
+
}
String contents = Decompiler.krakatau.decompileClassNode(cn, cw.toByteArray());
DiskWriter.replaceFile(path, contents, false);
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
BytecodeViewer.viewer.setIcon(false);
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(
e);
@@ -1513,7 +1512,8 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
};
t.start();
}
- if (result == 5) {
+ if (result == 5)
+ {
BytecodeViewer.viewer.setIcon(false);
}
}
@@ -1534,9 +1534,11 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
JSeparator separator_1 = new JSeparator();
mnNewMenu.add(separator_1);
- mntmAbout.addActionListener(new ActionListener() {
+ mntmAbout.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
+ public void actionPerformed(ActionEvent arg0)
+ {
aboutWindow.setVisible(true);
}
});
@@ -1544,9 +1546,11 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnNewMenu.add(mntmAbout);
JMenuItem mntmExit = new JMenuItem("Exit");
- mntmExit.addActionListener(new ActionListener() {
+ mntmExit.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
+ public void actionPerformed(ActionEvent arg0)
+ {
JOptionPane pane = new JOptionPane(
"Are you sure you want to exit?");
Object[] options = new String[]{"Yes", "No"};
@@ -1560,7 +1564,8 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
if (options[k].equals(obj))
result = k;
- if (result == 0) {
+ if (result == 0)
+ {
System.exit(0);
}
}
@@ -1763,10 +1768,17 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnPane_1.add(panel3Hexcode);
- menuBar.add(mnSettings);
- autoCompileSmali.setSelected(false);
+ compileOnSave.setSelected(false);
+
+ menuBar.add(mnSettings);
+
+
+ mnSettings.add(visualSettings);
+ mnSettings.add(separator_13);
+ mnSettings.add(compileOnSave);
+ compileOnSave.setSelected(false);
+
- mnSettings.add(autoCompileSmali);
autoCompileOnRefresh.setSelected(false);
mnSettings.add(autoCompileOnRefresh);
@@ -1775,7 +1787,6 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnSettings.add(separator_38);
decodeAPKResources.setSelected(true);
- //decodeAPKResources.setEnabled(false);
mnSettings.add(decodeAPKResources);
@@ -1786,37 +1797,58 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnApkConversion.add(apkConversionEnjarify);
mnSettings.add(separator_37);
+
chckbxmntmNewCheckItem_12.setSelected(true);
mnSettings.add(chckbxmntmNewCheckItem_12);
- chckbxmntmDeleteForiegnoutdatedLibs.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent arg0) {
- if (!chckbxmntmDeleteForiegnoutdatedLibs.isSelected()) {
+ chckbxmntmDeleteForeignOutdatedLibs.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ if (!chckbxmntmDeleteForeignOutdatedLibs.isSelected())
+ {
BytecodeViewer.showMessage("WARNING: With this being toggled off outdated libraries will NOT be removed. It's also a security issue. ONLY TURN IT OFF IF YOU KNOW WHAT YOU'RE DOING.");
}
- BytecodeViewer.deleteForiegnLibraries = chckbxmntmDeleteForiegnoutdatedLibs.isSelected();
+ BytecodeViewer.deleteForeignLibraries = chckbxmntmDeleteForeignOutdatedLibs.isSelected();
+ }
+ });
+ mnSettings.add(forcePureAsciiAsText);
+ forcePureAsciiAsText.setSelected(true);
+ forcePureAsciiAsText.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ Settings.saveSettings();
}
});
- chckbxmntmDeleteForiegnoutdatedLibs.setSelected(true);
-
- mnSettings.add(chckbxmntmDeleteForiegnoutdatedLibs);
-
mnSettings.add(separator_36);
- mntmSetPythonDirectory.addActionListener(new ActionListener() {
+
+ /*chckbxmntmDeleteForeinoutdatedLibs.setSelected(true);
+ mnSettings.add(chckbxmntmDeleteForeinoutdatedLibs);
+
+ mnSettings.add(separator_36);*/
+
+ mntmSetPythonDirectory.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
+ public void actionPerformed(ActionEvent arg0)
+ {
pythonC();
}
});
mnSettings.add(mntmSetPythonDirectory);
- mntmSetJreRt.addActionListener(new ActionListener() {
+ mntmSetJreRt.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
+ public void actionPerformed(ActionEvent arg0)
+ {
rtC();
}
});
- mntmSetPythonx.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent arg0) {
+ mntmSetPythonx.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent arg0)
+ {
pythonC3();
}
});
@@ -1824,16 +1856,20 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnSettings.add(mntmSetPythonx);
mnSettings.add(mntmSetJreRt);
- mntmSetOpitonalLibrary.addActionListener(new ActionListener() {
+ mntmSetOpitonalLibrary.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
+ public void actionPerformed(ActionEvent arg0)
+ {
library();
}
});
mnSettings.add(mntmSetOpitonalLibrary);
- mntmSetJavacExecutable.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent arg0) {
+ mntmSetJavacExecutable.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent arg0)
+ {
javac();
}
});
@@ -2056,10 +2092,13 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnBytecodeDecompilerSettings.add(chckbxmntmAppendBrackets);
menuBar.add(mnNewMenu_5);
- mntmNewMenuItem_6.addActionListener(new ActionListener() {
+ mntmNewMenuItem_6.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
- if (BytecodeViewer.runningObfuscation) {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ if (BytecodeViewer.runningObfuscation)
+ {
BytecodeViewer.showMessage("You're currently running an obfuscation task, wait for this to finish.");
return;
}
@@ -2079,10 +2118,13 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnNewMenu_5.add(mntmNewMenuItem_8);
mnNewMenu_5.add(mntmNewMenuItem_6);
- mntmNewMenuItem_7.addActionListener(new ActionListener() {
+ mntmNewMenuItem_7.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
- if (BytecodeViewer.runningObfuscation) {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ if (BytecodeViewer.runningObfuscation)
+ {
BytecodeViewer.showMessage("You're currently running an obfuscation task, wait for this to finish.");
return;
}
@@ -2093,10 +2135,13 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
});
mnNewMenu_5.add(mntmNewMenuItem_7);
- mntmNewMenuItem_11.addActionListener(new ActionListener() {
+ mntmNewMenuItem_11.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
- if (BytecodeViewer.runningObfuscation) {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ if (BytecodeViewer.runningObfuscation)
+ {
BytecodeViewer.showMessage("You're currently running an obfuscation task, wait for this to finish.");
return;
}
@@ -2119,10 +2164,13 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnNewMenu_1.add(separator_4);
mnNewMenu_1.add(mnRecentPlugins);
mnNewMenu_1.add(separator_5);
- mntmCodeSequenceDiagram.addActionListener(new ActionListener() {
+ mntmCodeSequenceDiagram.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
- if (BytecodeViewer.getLoadedClasses().isEmpty()) {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ if (BytecodeViewer.getLoadedClasses().isEmpty())
+ {
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
return;
}
@@ -2134,10 +2182,13 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnNewMenu_1.add(mntmNewMenuItem_1);
mnNewMenu_1.add(mntmShowMainMethods);
mnNewMenu_1.add(mntmShowAllStrings);
- mntmReplaceStrings.addActionListener(new ActionListener() {
+ mntmReplaceStrings.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
- if (BytecodeViewer.getLoadedClasses().isEmpty()) {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ if (BytecodeViewer.getLoadedClasses().isEmpty())
+ {
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
return;
}
@@ -2148,16 +2199,20 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnNewMenu_1.add(mntmReplaceStrings);
mnNewMenu_1.add(mntmNewMenuItem_2);
mnNewMenu_1.add(mntmStartZkmString);
- mntmZstringarrayDecrypter.addActionListener(new ActionListener() {
+ mntmZstringarrayDecrypter.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
+ public void actionPerformed(ActionEvent arg0)
+ {
PluginManager.runPlugin(new ZStringArrayDecrypter());
}
});
- mntmStackFramesRemover.addActionListener(new ActionListener() {
+ mntmStackFramesRemover.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent e) {
+ public void actionPerformed(ActionEvent e)
+ {
PluginManager.runPlugin(new StackFramesRemover());
}
});
@@ -2166,16 +2221,19 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
mnNewMenu_1.add(mntmStackFramesRemover);
waitIcons = new JMenuItem[10];
- for(int i = 0; i < 10; i++)
+ for (int i = 0; i < 10; i++)
{
waitIcons[i] = new JMenuItem("");
waitIcons[i].setMaximumSize(new Dimension(20, 50));
+ waitIcons[i].setEnabled(false);
menuBar.add(waitIcons[i]);
}
- mntmStartExternalPlugin.addActionListener(new ActionListener() {
+ mntmStartExternalPlugin.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent arg0) {
+ public void actionPerformed(ActionEvent arg0)
+ {
JFileChooser fc = new JFileChooser();
fc.setFileFilter(PluginManager.fileFilter());
fc.setFileHidingEnabled(false);
@@ -2183,56 +2241,70 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
if (returnVal == JFileChooser.APPROVE_OPTION)
- try {
+ try
+ {
BytecodeViewer.viewer.setIcon(true);
BytecodeViewer.startPlugin(fc.getSelectedFile());
BytecodeViewer.viewer.setIcon(false);
- } catch (Exception e1) {
+ }
+ catch (Exception e1)
+ {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
}
}
});
- mntmStartZkmString.addActionListener(new ActionListener() {
+ mntmStartZkmString.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent e) {
+ public void actionPerformed(ActionEvent e)
+ {
PluginManager.runPlugin(new ZKMStringDecrypter());
}
});
- mntmNewMenuItem_2.addActionListener(new ActionListener() {
+ mntmNewMenuItem_2.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent e) {
+ public void actionPerformed(ActionEvent e)
+ {
PluginManager.runPlugin(new AllatoriStringDecrypter());
}
});
- mntmNewMenuItem_1.addActionListener(new ActionListener() {
+ mntmNewMenuItem_1.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent e) {
- if (BytecodeViewer.getLoadedClasses().isEmpty()) {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (BytecodeViewer.getLoadedClasses().isEmpty())
+ {
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
return;
}
new MaliciousCodeScannerOptions().setVisible(true);
}
});
- mntmShowAllStrings.addActionListener(new ActionListener() {
+ mntmShowAllStrings.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent e) {
+ public void actionPerformed(ActionEvent e)
+ {
PluginManager.runPlugin(new ShowAllStrings());
}
});
- mntmShowMainMethods.addActionListener(new ActionListener() {
+ mntmShowMainMethods.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(ActionEvent e) {
+ public void actionPerformed(ActionEvent e)
+ {
PluginManager.runPlugin(new ShowMainMethods());
}
});
setSize(new Dimension(800, 400));
- if (BytecodeViewer.previewCopy)
- setTitle("Bytecode Viewer " + BytecodeViewer.version + " Preview - https://bytecodeviewer.com | https://the.bytecode.club - @Konloch");
+ if (BytecodeViewer.PREVIEW_COPY)
+ setTitle("Bytecode Viewer " + BytecodeViewer.VERSION + " Preview - https://bytecodeviewer.com | https://the.bytecode.club - @Konloch");
else
- setTitle("Bytecode Viewer " + BytecodeViewer.version + " - https://bytecodeviewer.com | https://the.bytecode.club - @Konloch");
+ setTitle("Bytecode Viewer " + BytecodeViewer.VERSION + " - https://bytecodeviewer.com | https://the.bytecode.club - @Konloch");
getContentPane().setLayout(
new BoxLayout(getContentPane(), BoxLayout.X_AXIS));
@@ -2240,7 +2312,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
// scrollPane.setViewportView(tree);
cn.setMinimumSize(new Dimension(200, 50));
// panel.add(cn);
- SearchingPane s = new SearchingPane(this);
+ s = new SearchingPane(this);
s.setPreferredSize(new Dimension(200, 50));
s.setMinimumSize(new Dimension(200, 50));
s.setMaximumSize(new Dimension(200, 2147483647));
@@ -2295,16 +2367,31 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
panelGroup3.add(panel3Smali);
panelGroup3.add(panel3Bytecode);
panelGroup3.add(panel3Hexcode);
- mnNewMenu_6.add(separator_13);
+
fontSpinner.setPreferredSize(new Dimension(42, 20));
fontSpinner.setSize(new Dimension(42, 20));
fontSpinner.setModel(new SpinnerNumberModel(new Integer(12), new Integer(1), null, new Integer(1)));
- mnNewMenu_6.add(mnFontSize);
mnFontSize.add(fontSpinner);
+ visualSettings.add(mnFontSize);
+ visualSettings.add(showFileInTabTitle);
+ showFileInTabTitle.setSelected(false);
+ showFileInTabTitle.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent arg0)
+ {
+ BytecodeViewer.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected();
+ Settings.saveSettings();
+ }
+ });
- panelGroup1.setSelected(panel1JDGUI.getModel(), true);
+ visualSettings.add(synchronizedViewing);
+ showClassMethods.setSelected(true);
+ visualSettings.add(showClassMethods);
+
+
+ panelGroup1.setSelected(panel1Fern.getModel(), true);
panelGroup2.setSelected(panel2Bytecode.getModel(), true);
panelGroup3.setSelected(panel3None.getModel(), true);
@@ -2313,25 +2400,225 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
@Override
- public void openClassFile(final String name, final ClassNode cn) {
- for (final VisibleComponent vc : rfComps) {
- vc.openClassFile(name, cn);
+ public void openClassFile(final FileContainer container, final String name, final ClassNode cn)
+ {
+ for (final VisibleComponent vc : rfComps)
+ {
+ vc.openClassFile(container, name, cn);
}
}
@Override
- public void openFile(final String name, byte[] content) {
- for (final VisibleComponent vc : rfComps) {
- vc.openFile(name, content);
+ public void openFile(final FileContainer container, final String name, byte[] content)
+ {
+ for (final VisibleComponent vc : rfComps)
+ {
+ vc.openFile(container, name, content);
}
}
@SuppressWarnings("unchecked")
- public static T getComponent(final Class clazz) {
- for (final VisibleComponent vc : rfComps) {
+ public static T getComponent(final Class clazz)
+ {
+ for (final VisibleComponent vc : rfComps)
+ {
if (vc.getClass() == clazz)
return (T) vc;
}
return null;
}
+
+ public void pythonC()
+ {
+ JFileChooser fc = new JFileChooser();
+ fc.setFileFilter(new FileFilter()
+ {
+ @Override
+ public boolean accept(File f)
+ {
+ return true;
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "Python (Or PyPy for speed) 2.7 Executable";
+ }
+ });
+ fc.setFileHidingEnabled(false);
+ fc.setAcceptAllFileFilterUsed(false);
+ int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
+
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ try
+ {
+ BytecodeViewer.python = fc.getSelectedFile().getAbsolutePath();
+ }
+ catch (Exception e1)
+ {
+ new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
+ }
+ }
+
+ public void javac()
+ {
+ JFileChooser fc = new JFileChooser();
+ fc.setFileFilter(new FileFilter()
+ {
+ @Override
+ public boolean accept(File f)
+ {
+ return true;
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "Javac Executable (Requires JDK 'C:/programfiles/Java/JDK_xx/bin/javac.exe)";
+ }
+ });
+ fc.setFileHidingEnabled(false);
+ fc.setAcceptAllFileFilterUsed(false);
+ int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
+
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ try
+ {
+ BytecodeViewer.javac = fc.getSelectedFile().getAbsolutePath();
+ }
+ catch (Exception e1)
+ {
+ new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
+ }
+ }
+
+ public void java()
+ {
+ JFileChooser fc = new JFileChooser();
+ fc.setFileFilter(new FileFilter()
+ {
+ @Override
+ public boolean accept(File f)
+ {
+ return true;
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "Java Executable (Inside Of JRE/JDK 'C:/programfiles/Java/JDK_xx/bin/java.exe')";
+ }
+ });
+ fc.setFileHidingEnabled(false);
+ fc.setAcceptAllFileFilterUsed(false);
+ int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
+
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ try
+ {
+ BytecodeViewer.java = fc.getSelectedFile().getAbsolutePath();
+ }
+ catch (Exception e1)
+ {
+ new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
+ }
+ }
+
+ public void pythonC3()
+ {
+ JFileChooser fc = new JFileChooser();
+ fc.setFileFilter(new FileFilter()
+ {
+ @Override
+ public boolean accept(File f)
+ {
+ return true;
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "Python (Or PyPy for speed) 3.x Executable";
+ }
+ });
+ fc.setFileHidingEnabled(false);
+ fc.setAcceptAllFileFilterUsed(false);
+ int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
+
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ try
+ {
+ BytecodeViewer.python3 = fc.getSelectedFile().getAbsolutePath();
+ }
+ catch (Exception e1)
+ {
+ new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
+ }
+ }
+
+ public void library()
+ {
+ JFileChooser fc = new JFileChooser();
+ fc.setFileFilter(new FileFilter()
+ {
+ @Override
+ public boolean accept(File f)
+ {
+ return f.isDirectory();
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "Optional Library Folder";
+ }
+ });
+ fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ fc.setFileHidingEnabled(false);
+ fc.setAcceptAllFileFilterUsed(false);
+ int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
+
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ try
+ {
+ BytecodeViewer.library = fc.getSelectedFile().getAbsolutePath();
+ }
+ catch (Exception e1)
+ {
+ new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
+ }
+ }
+
+
+ public void rtC()
+ {
+ JFileChooser fc = new JFileChooser();
+ fc.setFileFilter(new FileFilter()
+ {
+ @Override
+ public boolean accept(File f)
+ {
+ return true;
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "JRE RT Library";
+ }
+ });
+ fc.setFileHidingEnabled(false);
+ fc.setAcceptAllFileFilterUsed(false);
+ int returnVal = fc.showOpenDialog(BytecodeViewer.viewer);
+
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ try
+ {
+ BytecodeViewer.rt = fc.getSelectedFile().getAbsolutePath();
+ }
+ catch (Exception e1)
+ {
+ new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1);
+ }
+ }
}
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java b/src/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java
index 6de4ac41..a5461fb0 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java
@@ -18,18 +18,230 @@ package the.bytecode.club.bytecodeviewer.gui;
* along with this program. If not, see . *
***************************************************************************/
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
+import org.fife.ui.rtextarea.RTextScrollPane;
+import the.bytecode.club.bytecodeviewer.BytecodeViewer;
+import the.bytecode.club.bytecodeviewer.util.MethodParser;
+
+import javax.swing.*;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.regex.Matcher;
+
+import static the.bytecode.club.bytecodeviewer.gui.TabbedPane.BLANK;
+
/**
* Allows us to run a background thread
*
* @author Konloch
+ * @author DreamSworK
*/
-public abstract class PaneUpdaterThread extends Thread {
+public abstract class PaneUpdaterThread extends Thread
+{
+ public ClassViewer viewer;
+ public RSyntaxTextArea panelArea;
+ public RTextScrollPane scrollPane;
+ public JComboBox methodsList;
+ public int decompiler;
+ public int paneId;
public abstract void doShit();
@Override
public void run() {
doShit();
+ synchronizePane();
+ }
+
+ public final CaretListener caretListener = new CaretListener()
+ {
+ @Override
+ public void caretUpdate(CaretEvent e)
+ {
+ MethodParser methods = viewer.methods.get(paneId);
+ if (methods != null)
+ {
+ int methodLine = methods.findActiveMethod(panelArea.getCaretLineNumber());
+ if (methodLine != -1)
+ {
+ if (BytecodeViewer.viewer.showClassMethods.isSelected())
+ {
+ if (methodsList != null)
+ {
+ if (methodLine != (int) methodsList.getSelectedItem())
+ {
+ methodsList.setSelectedItem(methodLine);
+ }
+ }
+ }
+ if (BytecodeViewer.viewer.synchronizedViewing.isSelected())
+ {
+ int panes = 2;
+ if(viewer.panel3 != null)
+ panes = 3;
+
+ for (int i = 0; i < panes; i++)
+ {
+ if (i != paneId)
+ {
+ ClassViewer.selectMethod(viewer, i, methods.getMethod(methodLine));
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ public final ChangeListener viewportListener = new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ int panes = 2;
+ if(viewer.panel3 != null)
+ panes = 3;
+
+ if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) {
+ if (panelArea.isShowing() && (panelArea.hasFocus() || panelArea.getMousePosition() != null)) {
+ int caretLine = panelArea.getCaretLineNumber();
+ int maxViewLine = ClassViewer.getMaxViewLine(panelArea);
+ int activeViewLine = ClassViewer.getViewLine(panelArea);
+ int activeLine = (activeViewLine == maxViewLine && caretLine > maxViewLine) ? caretLine : activeViewLine;
+ int activeLineDelta = -1;
+ MethodParser.Method activeMethod = null;
+ MethodParser activeMethods = viewer.methods.get(paneId);
+ if (activeMethods != null) {
+ int activeMethodLine = activeMethods.findActiveMethod(activeLine);
+ if (activeMethodLine != -1) {
+ activeLineDelta = activeLine - activeMethodLine;
+ activeMethod = activeMethods.getMethod(activeMethodLine);
+ ClassViewer.selectMethod(panelArea, activeMethodLine);
+ }
+ }
+ for (int i = 0; i < panes; i++) {
+ if (i != paneId)
+ {
+ int setLine = -1;
+
+ RSyntaxTextArea area = null;
+ switch(i)
+ {
+ case 0:
+ area = viewer.t1.panelArea;
+ break;
+ case 1:
+ area = viewer.t2.panelArea;
+ break;
+ case 2:
+ area = viewer.t3.panelArea;
+ break;
+ }
+
+ if (area != null) {
+ if (activeMethod != null && activeLineDelta >= 0) {
+ MethodParser methods = viewer.methods.get(i);
+ if (methods != null) {
+ int methodLine = methods.findMethod(activeMethod);
+ if (methodLine != -1) {
+ int viewLine = ClassViewer.getViewLine(area);
+ if (activeLineDelta != viewLine - methodLine) {
+ setLine = methodLine + activeLineDelta;
+ }
+ }
+ }
+ }
+ else if (activeLine != ClassViewer.getViewLine(area)) {
+ setLine = activeLine;
+ }
+ if (setLine >= 0) {
+ ClassViewer.setViewLine(area, setLine);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ class MethodsRenderer extends JLabel implements ListCellRenderer
+ {
+ public MethodsRenderer() {
+ setOpaque(true);
+ }
+
+ public Component getListCellRendererComponent(JList> list, Object value, int index, boolean isSelected, boolean cellHasFocus)
+ {
+ MethodParser methods = viewer.methods.get(paneId);
+ MethodParser.Method method = methods.getMethod((Integer) value);
+ setText(method.toString());
+ return this;
+ }
+ }
+
+ public void synchronizePane()
+ {
+ JViewport viewport = scrollPane.getViewport();
+ viewport.addChangeListener(viewportListener);
+ panelArea.addCaretListener(caretListener);
+
+ final MethodParser methods = viewer.methods.get(paneId);
+ for (int i = 0; i < panelArea.getLineCount(); i++)
+ {
+ String lineText = ClassViewer.getLineText(panelArea, i);
+ Matcher regexMatcher = MethodParser.regex.matcher(lineText);
+ if (regexMatcher.find())
+ {
+ String methodName = regexMatcher.group("name");
+ String methodParams = regexMatcher.group("params");
+ methods.addMethod(i, methodName, methodParams);
+ }
+ }
+
+ if (BytecodeViewer.viewer.showClassMethods.isSelected())
+ {
+ if (!methods.isEmpty()) {
+ methodsList = new JComboBox<>();
+ for (Integer line : methods.getMethodsLines()) {
+ methodsList.addItem(line);
+ }
+ methodsList.setRenderer(new PaneUpdaterThread.MethodsRenderer());
+ methodsList.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ int line = (int) methodsList.getSelectedItem();
+
+ RSyntaxTextArea area = null;
+ switch(paneId)
+ {
+ case 0:
+ area = viewer.t1.panelArea;
+ break;
+ case 1:
+ area = viewer.t2.panelArea;
+ break;
+ case 2:
+ area = viewer.t3.panelArea;
+ break;
+ }
+
+ if(area != null)
+ ClassViewer.selectMethod(area, line);
+ }
+ });
+
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.add(scrollPane.getColumnHeader().getComponent(0), BorderLayout.NORTH);
+ panel.add(methodsList, BorderLayout.SOUTH);
+ methodsList.setBackground(BLANK);
+ scrollPane.getColumnHeader().removeAll();
+ scrollPane.getColumnHeader().add(panel);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/SearchingPane.java b/src/the/bytecode/club/bytecodeviewer/gui/SearchingPane.java
index 4de041df..e5f79386 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/SearchingPane.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/SearchingPane.java
@@ -26,6 +26,8 @@ import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.*;
import the.bytecode.club.bytecodeviewer.searching.*;
+import the.bytecode.club.bytecodeviewer.util.FileChangeNotifier;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -53,30 +55,35 @@ import the.bytecode.club.bytecodeviewer.searching.*;
*/
@SuppressWarnings("rawtypes")
-public class SearchingPane extends VisibleComponent {
+public class SearchingPane extends VisibleComponent
+{
private static final long serialVersionUID = -1098524689236993932L;
FileChangeNotifier fcn;
JCheckBox exact = new JCheckBox("Exact");
- DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode("Root");
+ DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode("Results");
JTree tree;
+ JComboBox typeBox;
SearchType searchType = null;
JComboBox searchRadiusBox;
public JButton search = new JButton("Search");
- BackgroundSearchThread t = new BackgroundSearchThread(true) {
+ BackgroundSearchThread t = new BackgroundSearchThread(true)
+ {
@Override
- public void doSearch() {
+ public void doSearch()
+ {
// empty
}
};
@SuppressWarnings("unchecked")
- public SearchingPane(final FileChangeNotifier fcn) {
+ public SearchingPane(final FileChangeNotifier fcn)
+ {
super("Search");
this.fcn = fcn;
@@ -90,7 +97,8 @@ public class SearchingPane extends VisibleComponent {
searchRadiusOpt.add(new JLabel("Search from "), BorderLayout.WEST);
DefaultComboBoxModel model = new DefaultComboBoxModel();
- for (final SearchRadius st : SearchRadius.values()) {
+ for (final SearchRadius st : SearchRadius.values())
+ {
model.addElement(st);
}
@@ -101,16 +109,19 @@ public class SearchingPane extends VisibleComponent {
searchOpts.add(searchRadiusOpt);
model = new DefaultComboBoxModel();
- for (final SearchType st : SearchType.values()) {
+ for (final SearchType st : SearchType.values())
+ {
model.addElement(st);
}
- final JComboBox typeBox = new JComboBox(model);
+ typeBox = new JComboBox(model);
final JPanel searchOptPanel = new JPanel();
- final ItemListener il = new ItemListener() {
+ final ItemListener il = new ItemListener()
+ {
@Override
- public void itemStateChanged(final ItemEvent arg0) {
+ public void itemStateChanged(final ItemEvent arg0)
+ {
searchOptPanel.removeAll();
searchType = (SearchType) typeBox.getSelectedItem();
searchOptPanel.add(searchType.details.getPanel());
@@ -122,7 +133,7 @@ public class SearchingPane extends VisibleComponent {
typeBox.addItemListener(il);
- typeBox.setSelectedItem(SearchType.LDC);
+ typeBox.setSelectedItem(SearchType.Strings);
il.itemStateChanged(null);
searchOpts.add(typeBox);
@@ -136,57 +147,12 @@ public class SearchingPane extends VisibleComponent {
optionPanel.add(p2, BorderLayout.CENTER);
- search.addActionListener(new ActionListener() {
+ search.addActionListener(new ActionListener()
+ {
@Override
- public void actionPerformed(final ActionEvent arg0) {
- treeRoot.removeAllChildren();
- searchType = (SearchType) typeBox.getSelectedItem();
- final SearchRadius radius = (SearchRadius) searchRadiusBox
- .getSelectedItem();
- final SearchResultNotifier srn = new SearchResultNotifier() {
- @Override
- public void notifyOfResult(String debug) {
- treeRoot.add(new DefaultMutableTreeNode(debug));
- }
- };
- if (radius == SearchRadius.All_Classes) {
- if (t.finished) {
- t = new BackgroundSearchThread() {
- @Override
- public void doSearch() {
-
- try {
- Pattern.compile(RegexInsnFinder.processRegex(RegexSearch.searchText.getText()), Pattern.MULTILINE);
- } catch (PatternSyntaxException ex) {
- BytecodeViewer.showMessage("You have an error in your regex syntax.");
- }
-
- for (ClassNode cln : BytecodeViewer.getLoadedClasses())
- searchType.details.search(cln, srn, exact.isSelected());
-
- MainViewerGUI.getComponent(SearchingPane.class).search.setEnabled(true);
- MainViewerGUI.getComponent(SearchingPane.class).search.setText("Search");
- tree.expandPath(new TreePath(tree.getModel().getRoot()));
- tree.updateUI();
- }
-
- };
- MainViewerGUI.getComponent(SearchingPane.class).search
- .setEnabled(false);
- MainViewerGUI.getComponent(SearchingPane.class).search
- .setText("Searching, please wait..");
- t.start();
- } else { // this should really never be called.
- BytecodeViewer
- .showMessage("You currently have a search performing in the background, please wait for that to finish.");
- }
- } else if (radius == SearchRadius.Current_Class) {
- final Viewer cv = MainViewerGUI.getComponent(WorkPane.class).getCurrentViewer();
- if (cv != null) {
- searchType.details.search(cv.cn, srn,
- exact.isSelected());
- }
- }
+ public void actionPerformed(final ActionEvent arg0)
+ {
+ search();
}
});
@@ -199,19 +165,28 @@ public class SearchingPane extends VisibleComponent {
getContentPane().add(new JScrollPane(optionPanel), BorderLayout.NORTH);
getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
- this.tree.addTreeSelectionListener(new TreeSelectionListener() {
+ this.tree.addTreeSelectionListener(new TreeSelectionListener()
+ {
@Override
- public void valueChanged(final TreeSelectionEvent arg0) {
- String path = arg0.getPath().toString();
+ public void valueChanged(final TreeSelectionEvent arg0)
+ {
+ if(arg0.getPath().getPathComponent(0).equals("Results"))
+ return;
- String className = path.split(", ")[1].split("\\.")[0];
- final ClassNode fN = BytecodeViewer.getClassNode(className);
- if (fN != null) {
- MainViewerGUI.getComponent(FileNavigationPane.class)
- .openClassFileToWorkSpace(className + ".class", fN);
+ String cheapHax = arg0.getPath().getPathComponent(1).toString();
+
+ String path = arg0.getPath().getPathComponent(1).toString();
+
+ String containerName = path.split(">",2)[0];
+ String className = path.split(">",2)[1].split("\\.")[0];
+ FileContainer container = BytecodeViewer.getFileContainer(containerName);
+
+ final ClassNode fN = container.getClassNode(className);
+
+ if (fN != null)
+ {
+ MainViewerGUI.getComponent(FileNavigationPane.class).openClassFileToWorkSpace(container, className + ".class", fN);
}
-
- System.out.println(className);
}
});
@@ -219,9 +194,63 @@ public class SearchingPane extends VisibleComponent {
}
+ public void search()
+ {
+ treeRoot.removeAllChildren();
+ searchType = (SearchType) typeBox.getSelectedItem();
+ final SearchRadius radius = (SearchRadius) searchRadiusBox
+ .getSelectedItem();
+ final SearchResultNotifier srn = new SearchResultNotifier() {
+ @Override
+ public void notifyOfResult(String debug) {
+ treeRoot.add(new DefaultMutableTreeNode(debug));
+ }
+ };
+ if (radius == SearchRadius.All_Classes) {
+ if (t.finished) {
+ t = new BackgroundSearchThread() {
+ @Override
+ public void doSearch() {
+
+ try {
+ Pattern.compile(RegexInsnFinder.processRegex(RegexSearch.searchText.getText()), Pattern.MULTILINE);
+ } catch (PatternSyntaxException ex) {
+ BytecodeViewer.showMessage("You have an error in your regex syntax.");
+ }
+
+ for (FileContainer container : BytecodeViewer.files)
+ for (ClassNode c : container.classes)
+ searchType.details.search(container, c, srn, exact.isSelected());
+
+ MainViewerGUI.getComponent(SearchingPane.class).search.setEnabled(true);
+ MainViewerGUI.getComponent(SearchingPane.class).search.setText("Search");
+ tree.expandPath(new TreePath(tree.getModel().getRoot()));
+ tree.updateUI();
+ }
+
+ };
+ MainViewerGUI.getComponent(SearchingPane.class).search
+ .setEnabled(false);
+ MainViewerGUI.getComponent(SearchingPane.class).search
+ .setText("Searching, please wait..");
+ t.start();
+ } else { // this should really never be called.
+ BytecodeViewer
+ .showMessage("You currently have a search performing in the background, please wait for that to finish.");
+ }
+ } else if (radius == SearchRadius.Current_Class) {
+ final Viewer cv = MainViewerGUI.getComponent(WorkPane.class).getCurrentViewer();
+ if (cv != null) {
+ searchType.details.search(cv.container, cv.cn, srn, exact.isSelected());
+ }
+ }
+ }
+
public enum SearchType {
- LDC(new LDCSearch()), Regex(new RegexSearch()), MethodCall(
- new MethodCallSearch()), FieldCall(new FieldCallSearch());
+ Strings(new LDCSearch()),
+ Regex(new RegexSearch()),
+ MethodCall(new MethodCallSearch()),
+ FieldCall(new FieldCallSearch());
public final SearchTypeDetails details;
@@ -240,6 +269,6 @@ public class SearchingPane extends VisibleComponent {
}
@Override
- public void openFile(String name, byte[] contents) {
+ public void openFile(final FileContainer container, String name, byte[] contents) {
}
}
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/SystemErrConsole.java b/src/the/bytecode/club/bytecodeviewer/gui/SystemErrConsole.java
index a78d32f8..07914466 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/SystemErrConsole.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/SystemErrConsole.java
@@ -311,7 +311,7 @@ public class SystemErrConsole extends JFrame {
}
class CustomOutputStream extends OutputStream {
- private StringBuffer sb = new StringBuffer();
+ private StringBuilder sb = new StringBuilder();
private JTextArea textArea;
public CustomOutputStream(JTextArea textArea) {
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java b/src/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java
index 0429d616..d9426eaf 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java
@@ -1,12 +1,8 @@
package the.bytecode.club.bytecodeviewer.gui;
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
+import the.bytecode.club.bytecodeviewer.BytecodeViewer;
+
+import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
@@ -42,8 +38,7 @@ import javax.swing.plaf.basic.BasicButtonUI;
***************************************************************************/
/**
- * Component to be used as tabComponent; Contains a JLabel to show the text and
- * a JButton to close the tab it belongs to
+ * Component to be used as tabComponent; Contains a JLabel to show the text and a JButton to close the tab it belongs to
*
* @author Konloch
* @author WaterWolf
@@ -51,14 +46,25 @@ import javax.swing.plaf.basic.BasicButtonUI;
public class TabbedPane extends JPanel {
private static final long serialVersionUID = -4774885688297538774L;
+ public static final Color BLANK = new Color(0,0,0,0);
private final JTabbedPane pane;
- final JButton button = new TabButton();
+ public final JLabel label;
+ private final JButton button = new TabButton();
private static long zero = System.currentTimeMillis();
+ private long startedDragging = 0;
+ private boolean dragging = false;
+ private DelayTabbedPaneThread probablyABadIdea;
+ private TabbedPane THIS = this;
+ public String tabName;
+ public String fileContainerName;
- public TabbedPane(String name, final JTabbedPane pane) {
+ public TabbedPane(String fileContainerName, String name, final JTabbedPane pane) {
// unset default FlowLayout' gaps
super(new FlowLayout(FlowLayout.LEFT, 0, 0));
+ this.tabName = name;
+ this.fileContainerName = fileContainerName;
+
if (pane == null)
throw new NullPointerException("TabbedPane is null");
@@ -66,7 +72,7 @@ public class TabbedPane extends JPanel {
setOpaque(false);
// make JLabel read titles from JTabbedPane
- final JLabel label = new JLabel() {
+ label = new JLabel() {
private static final long serialVersionUID = -5511025206527893360L;
@Override
@@ -110,7 +116,6 @@ public class TabbedPane extends JPanel {
@Override
public void actionPerformed(ActionEvent e) {
String name = e.getActionCommand().split(": ")[1];
- System.out.println(name);
boolean removedAll = false;
while (!removedAll) {
int thisID = pane.indexOfTab(name);
@@ -128,6 +133,7 @@ public class TabbedPane extends JPanel {
pop_up.add(closealltab);
pop_up.add(closetab);
+ //setComponentPopupMenu(pop_up);
button.setComponentPopupMenu(pop_up);
button.addMouseListener(new MouseListener() {
@@ -143,23 +149,94 @@ public class TabbedPane extends JPanel {
}
}
- @Override
- public void mouseEntered(MouseEvent arg0) {
- }
-
- @Override
- public void mouseExited(MouseEvent arg0) {
- }
-
- @Override
- public void mousePressed(MouseEvent arg0) {
- }
-
- @Override
- public void mouseReleased(MouseEvent e) {
- }
-
+ @Override public void mouseEntered(MouseEvent arg0) { }
+ @Override public void mouseExited(MouseEvent arg0) { }
+ @Override public void mousePressed(MouseEvent arg0) { }
+ @Override public void mouseReleased(MouseEvent e) { }
});
+ /*this.addMouseListener(new MouseListener() {
+ @Override public void mouseClicked(MouseEvent e) {}
+ @Override public void mouseEntered(MouseEvent arg0) {
+ }
+ @Override public void mouseExited(MouseEvent arg0) {
+ }
+ @Override public void mousePressed(MouseEvent e) {
+ if(e.getButton() == 1)
+ {
+ startedDragging = System.currentTimeMillis();
+ dragging = true;
+ if (probablyABadIdea != null)
+ {
+ probablyABadIdea.stopped = true;
+ }
+ probablyABadIdea = new DelayTabbedPaneThread(THIS);
+ probablyABadIdea.start();
+ repaint();
+ System.out.println(e.getX()+", "+e.getY());
+ Rectangle bounds = new Rectangle(1, 1, e.getX(), e.getY());
+ for(int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++)
+ {
+ Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i);
+ if(c != null && bounds.intersects(c.getBounds()))
+ {
+ BytecodeViewer.viewer.workPane.tabs.setSelectedIndex(i);
+ }
+ }
+ }
+ else
+ {
+ stopDragging(e.getX(), e.getY());
+ }
+ }
+ @Override public void mouseReleased(MouseEvent e) {
+ stopDragging(e.getX(), e.getY());
+ }
+ });*/
+ }
+
+ private void stopDragging(int mouseX, int mouseY)
+ {
+ if(System.currentTimeMillis()-startedDragging >= 210)
+ {
+ Rectangle bounds = new Rectangle(1, 1, mouseX, mouseY);
+ System.out.println("debug-5: " + mouseX+", " + mouseY);
+ int totalTabs = BytecodeViewer.viewer.workPane.tabs.getTabCount();
+ int index = -1;
+ for(int i = 0; i < totalTabs; i++)
+ {
+ Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i);
+ if(c != null && bounds.intersects(c.getBounds()))
+ {
+ index = i; //replace this tabs position
+ }
+ }
+
+ if(index == -1)
+ {
+ for (int i = 0; i < totalTabs; i++)
+ {
+ Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i);
+ //do some check to see if it's past the X or Y
+ if(c != null)
+ {
+ System.out.println("debug-6: " + c.getBounds());
+ }
+ }
+ }
+
+ if(index != -1)
+ {
+ BytecodeViewer.viewer.workPane.tabs.remove(this);
+ BytecodeViewer.viewer.workPane.tabs.setTabComponentAt(index, this);
+ }
+ }
+ dragging = false;
+ label.setBackground(BLANK);
+ if(probablyABadIdea != null)
+ {
+ probablyABadIdea.stopped = true;
+ }
+ label.updateUI();
}
private class TabButton extends JButton implements ActionListener {
@@ -199,7 +276,8 @@ public class TabbedPane extends JPanel {
// paint the cross
@Override
- protected void paintComponent(final Graphics g) {
+ protected void paintComponent(final Graphics g)
+ {
super.paintComponent(g);
final Graphics2D g2 = (Graphics2D) g.create();
// shift the image for pressed buttons
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/Viewer.java b/src/the/bytecode/club/bytecodeviewer/gui/Viewer.java
index 2c8a1eef..65dad216 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/Viewer.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/Viewer.java
@@ -3,6 +3,7 @@ package the.bytecode.club.bytecodeviewer.gui;
import javax.swing.JPanel;
import org.objectweb.asm.tree.ClassNode;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -26,6 +27,7 @@ public abstract class Viewer extends JPanel {
public ClassNode cn;
public String name;
+ FileContainer container;
private static final long serialVersionUID = -2965538493489119191L;
}
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/VisibleComponent.java b/src/the/bytecode/club/bytecodeviewer/gui/VisibleComponent.java
index 1a5cfbe7..883f525d 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/VisibleComponent.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/VisibleComponent.java
@@ -4,7 +4,8 @@ import javax.swing.JInternalFrame;
import org.objectweb.asm.tree.ClassNode;
-import the.bytecode.club.bytecodeviewer.FileChangeNotifier;
+import the.bytecode.club.bytecodeviewer.util.FileChangeNotifier;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -49,10 +50,10 @@ public abstract class VisibleComponent extends JInternalFrame implements
}
@Override
- public void openClassFile(final String name, final ClassNode cn) {
+ public void openClassFile(final FileContainer container, final String name, final ClassNode cn) {
}
@Override
- public void openFile(final String name, byte[] contents) {
+ public void openFile(final FileContainer container, final String name, byte[] contents) {
}
}
diff --git a/src/the/bytecode/club/bytecodeviewer/gui/WorkPane.java b/src/the/bytecode/club/bytecodeviewer/gui/WorkPane.java
index b9b8b2d8..1c5b94ed 100644
--- a/src/the/bytecode/club/bytecodeviewer/gui/WorkPane.java
+++ b/src/the/bytecode/club/bytecodeviewer/gui/WorkPane.java
@@ -1,24 +1,18 @@
package the.bytecode.club.bytecodeviewer.gui;
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.FlowLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ContainerEvent;
-import java.awt.event.ContainerListener;
+import java.awt.*;
+import java.awt.event.*;
import java.util.HashMap;
-import javax.swing.JButton;
-import javax.swing.JPanel;
-import javax.swing.JTabbedPane;
+import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.FileChangeNotifier;
+import the.bytecode.club.bytecodeviewer.util.FileChangeNotifier;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -67,6 +61,90 @@ public class WorkPane extends VisibleComponent implements ActionListener {
this.tabs = new JTabbedPane();
this.fcn = fcn;
+
+ JPopupMenu pop_up = new JPopupMenu()
+ {
+ @Override
+ public void setVisible(boolean b) {
+ super.setVisible(b);
+ }
+ };
+ JMenuItem closealltab = new JMenuItem("Close All But This");
+ JMenuItem closetab = new JMenuItem("Close Tab");
+ closetab.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ /*String name = e.getActionCommand().split(": ")[1];
+ final int i = pane.indexOfTab(name);
+ if (i != -1)
+ pane.remove(i);*/
+ }
+ });
+ closealltab.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String name = e.getActionCommand().split(": ")[1];
+ System.out.println("debug-3: "+name);
+ boolean removedAll = false;
+ while (!removedAll) {
+ int thisID = tabs.indexOfTab(name);
+ if (tabs.getTabCount() <= 1) {
+ removedAll = true;
+ return;
+ }
+ if (thisID != 0)
+ tabs.remove(0);
+ else
+ tabs.remove(1);
+ }
+ }
+ });
+ tabs.addMouseListener(new MouseListener() {
+ @Override public void mouseClicked(MouseEvent e) {}
+ @Override public void mouseEntered(MouseEvent arg0) {
+ }
+ @Override public void mouseExited(MouseEvent arg0) {
+ }
+ @Override public void mousePressed(MouseEvent e) {
+ if(e.getButton() == 3)
+ {
+ if(BytecodeViewer.BLOCK_TAB_MENU)
+ return;
+
+ Rectangle bounds = new Rectangle(1, 1, e.getX(), e.getY());
+ Point point = tabs.getMousePosition();
+ System.out.println("debug-1: " +point);
+ for(int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++)
+ {
+ Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i);
+ if(c != null && bounds.intersects(c.getBounds()))
+ {
+ pop_up.setVisible(true);
+ closealltab.setText("Close All But This: " + ((TabbedPane)c).tabName);
+ closetab.setText("Close Tab: " + ((TabbedPane)c).tabName);
+ //do something with this shit
+ //BytecodeViewer.viewer.workPane.tabs.setSelectedIndex(i);
+ }
+ else
+ {
+ pop_up.setVisible(false);
+ }
+ }
+
+ System.out.println("debug-2: " +e.getX()+", "+e.getY());
+ }
+ }
+ @Override public void mouseReleased(MouseEvent e) {
+ }
+ });
+
+ pop_up.add(closealltab);
+ pop_up.add(closetab);
+
+
+ if(!BytecodeViewer.BLOCK_TAB_MENU)
+ tabs.setComponentPopupMenu(pop_up);
+
getContentPane().setLayout(new BorderLayout());
getContentPane().add(tabs, BorderLayout.CENTER);
@@ -91,10 +169,31 @@ public class WorkPane extends VisibleComponent implements ActionListener {
public void componentRemoved(final ContainerEvent e) {
final Component c = e.getChild();
if (c instanceof ClassViewer) {
- workingOn.remove(((ClassViewer) c).name);
+ String containerName = ((ClassViewer) c).container.name+">";
+ String fileName = ((ClassViewer) c).name;
+
+ if(fileName.startsWith(containerName))
+ {
+ workingOn.remove(fileName);
+ }
+ else
+ {
+ workingOn.remove(containerName+fileName);
+ }
}
- if (c instanceof FileViewer) {
- workingOn.remove(((FileViewer) c).name);
+ if (c instanceof FileViewer)
+ {
+ String containerName = ((FileViewer) c).container.name+">";
+ String fileName = ((FileViewer) c).name;
+
+ if(fileName.startsWith(containerName))
+ {
+ workingOn.remove(fileName);
+ }
+ else
+ {
+ workingOn.remove(containerName+fileName);
+ }
}
}
@@ -112,43 +211,71 @@ public class WorkPane extends VisibleComponent implements ActionListener {
int tabCount = 0;
- public void addWorkingFile(final String name, final ClassNode cn) {
- if (!workingOn.containsKey(name)) {
- final JPanel tabComp = new ClassViewer(name, cn);
+ public void addWorkingFile(final FileContainer container, String name, final ClassNode cn) {
+ String workingName = container.name+">"+name;
+ String containerName = name;
+
+ if(BytecodeViewer.displayParentInTab)
+ containerName = container.name+">"+name;
+
+ if (!workingOn.containsKey(workingName)) {
+ final JPanel tabComp = new ClassViewer(container, containerName, cn);
tabs.add(tabComp);
final int tabCount = tabs.indexOfComponent(tabComp);
- workingOn.put(name, tabCount);
- tabs.setTabComponentAt(tabCount, new TabbedPane(name,tabs));
+ workingOn.put(workingName, tabCount);
+ TabbedPane tabbedPane = new TabbedPane(container.name, name,tabs);
+ ((ClassViewer) tabComp).tabbedPane = tabbedPane;
+ tabs.setTabComponentAt(tabCount, tabbedPane);
tabs.setSelectedIndex(tabCount);
} else {
- tabs.setSelectedIndex(workingOn.get(name));
+ tabs.setSelectedIndex(workingOn.get(workingName));
}
}
- public void addFile(final String name, byte[] contents) {
+ public void addFile(final FileContainer container, String name, byte[] contents) {
+ String workingName = container.name+">"+name;
+
+ if(BytecodeViewer.displayParentInTab)
+ name = container.name+">"+name;
+
if(contents == null) //a directory
return;
- if (!workingOn.containsKey(name)) {
- final Component tabComp = new FileViewer(name, contents);
+ if (!workingOn.containsKey(workingName)) {
+ final Component tabComp = new FileViewer(container, name, contents);
tabs.add(tabComp);
final int tabCount = tabs.indexOfComponent(tabComp);
- workingOn.put(name, tabCount);
- tabs.setTabComponentAt(tabCount, new TabbedPane(name,tabs));
+ workingOn.put(workingName, tabCount);
+
+ TabbedPane tabbedPane = new TabbedPane(null, name,tabs);
+ ((FileViewer) tabComp).tabbedPane = tabbedPane;
+ tabs.setTabComponentAt(tabCount, tabbedPane);
tabs.setSelectedIndex(tabCount);
} else {
- tabs.setSelectedIndex(workingOn.get(name));
+ try
+ {
+ tabs.setSelectedIndex(workingOn.get(workingName));
+ }
+ catch(java.lang.IndexOutOfBoundsException e)
+ {
+ //workingOn.remove(workingName);
+ e.printStackTrace();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
}
}
@Override
- public void openClassFile(final String name, final ClassNode cn) {
- addWorkingFile(name, cn);
+ public void openClassFile(final FileContainer container, final String name, final ClassNode cn) {
+ addWorkingFile(container, name, cn);
}
@Override
- public void openFile(final String name, byte[] content) {
- addFile(name, content);
+ public void openFile(final FileContainer container, final String name, byte[] content) {
+ addFile(container, name, content);
}
public Viewer getCurrentViewer() {
diff --git a/src/the/bytecode/club/bytecodeviewer/obfuscators/JavaObfuscator.java b/src/the/bytecode/club/bytecodeviewer/obfuscators/JavaObfuscator.java
index 08b6adc5..b6717834 100644
--- a/src/the/bytecode/club/bytecodeviewer/obfuscators/JavaObfuscator.java
+++ b/src/the/bytecode/club/bytecodeviewer/obfuscators/JavaObfuscator.java
@@ -3,7 +3,7 @@ package the.bytecode.club.bytecodeviewer.obfuscators;
import java.util.ArrayList;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
diff --git a/src/the/bytecode/club/bytecodeviewer/plugin/PluginManager.java b/src/the/bytecode/club/bytecodeviewer/plugin/PluginManager.java
index ccf3927f..65e0bb5e 100644
--- a/src/the/bytecode/club/bytecodeviewer/plugin/PluginManager.java
+++ b/src/the/bytecode/club/bytecodeviewer/plugin/PluginManager.java
@@ -8,7 +8,7 @@ import java.util.Set;
import javax.swing.filechooser.FileFilter;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
-import the.bytecode.club.bytecodeviewer.MiscUtils;
+import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import the.bytecode.club.bytecodeviewer.api.Plugin;
import the.bytecode.club.bytecodeviewer.plugin.strategies.CompiledJavaPluginLaunchStrategy;
import the.bytecode.club.bytecodeviewer.plugin.strategies.GroovyPluginLaunchStrategy;
diff --git a/src/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java b/src/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java
index 260c8a18..069b15ac 100644
--- a/src/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java
+++ b/src/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java
@@ -12,7 +12,7 @@ import java.util.zip.ZipInputStream;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
-import the.bytecode.club.bytecodeviewer.JarUtils;
+import the.bytecode.club.bytecodeviewer.util.JarUtils;
import the.bytecode.club.bytecodeviewer.api.Plugin;
import the.bytecode.club.bytecodeviewer.plugin.PluginLaunchStrategy;
diff --git a/src/the/bytecode/club/bytecodeviewer/searching/EnterKeyEvent.java b/src/the/bytecode/club/bytecodeviewer/searching/EnterKeyEvent.java
new file mode 100644
index 00000000..4fa46436
--- /dev/null
+++ b/src/the/bytecode/club/bytecodeviewer/searching/EnterKeyEvent.java
@@ -0,0 +1,23 @@
+package the.bytecode.club.bytecodeviewer.searching;
+
+import the.bytecode.club.bytecodeviewer.BytecodeViewer;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+public class EnterKeyEvent implements KeyListener
+{
+ public static final EnterKeyEvent SINGLETON = new EnterKeyEvent();
+
+ @Override public void keyTyped(KeyEvent e) { }
+
+ @Override public void keyPressed(KeyEvent e) {
+ if(e.getKeyCode() == KeyEvent.VK_ENTER)
+ {
+ BytecodeViewer.viewer.s.search();
+ }
+ }
+
+ @Override public void keyReleased(KeyEvent e) { }
+
+}
diff --git a/src/the/bytecode/club/bytecodeviewer/searching/FieldCallSearch.java b/src/the/bytecode/club/bytecodeviewer/searching/FieldCallSearch.java
index 6142f52d..6bda3c7a 100644
--- a/src/the/bytecode/club/bytecodeviewer/searching/FieldCallSearch.java
+++ b/src/the/bytecode/club/bytecodeviewer/searching/FieldCallSearch.java
@@ -16,6 +16,7 @@ import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodNode;
import eu.bibl.banalysis.asm.desc.OpcodeInfo;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -44,10 +45,20 @@ import eu.bibl.banalysis.asm.desc.OpcodeInfo;
public class FieldCallSearch implements SearchTypeDetails {
- JTextField mOwner = new JTextField(""), mName = new JTextField(""),
- mDesc = new JTextField("");
+ JTextField mOwner = new JTextField(""), mName = new JTextField(""), mDesc = new JTextField("");
+
JPanel myPanel = null;
+ public FieldCallSearch()
+ {
+ mOwner = new JTextField("");
+ mOwner.addKeyListener(EnterKeyEvent.SINGLETON);
+ mName = new JTextField("");
+ mName.addKeyListener(EnterKeyEvent.SINGLETON);
+ mDesc = new JTextField("");
+ mDesc.addKeyListener(EnterKeyEvent.SINGLETON);
+ }
+
@Override
public JPanel getPanel() {
if (myPanel == null) {
@@ -64,8 +75,7 @@ public class FieldCallSearch implements SearchTypeDetails {
}
@Override
- public void search(final ClassNode node, final SearchResultNotifier srn,
- boolean exact) {
+ public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, boolean exact) {
final Iterator methods = node.methods.iterator();
String owner = mOwner.getText();
if (owner.isEmpty()) {
@@ -109,7 +119,7 @@ public class FieldCallSearch implements SearchTypeDetails {
} catch (java.lang.ArrayIndexOutOfBoundsException e) {
}
- srn.notifyOfResult(node.name
+ srn.notifyOfResult(container.name+">"+node.name
+ "."
+ method.name
+ desc2
@@ -135,7 +145,7 @@ public class FieldCallSearch implements SearchTypeDetails {
} catch (java.lang.ArrayIndexOutOfBoundsException e) {
}
- srn.notifyOfResult(node.name
+ srn.notifyOfResult(container.name+">"+node.name
+ "."
+ method.name
+ desc2
diff --git a/src/the/bytecode/club/bytecodeviewer/searching/LDCSearch.java b/src/the/bytecode/club/bytecodeviewer/searching/LDCSearch.java
index 5036746b..b2a79b8e 100644
--- a/src/the/bytecode/club/bytecodeviewer/searching/LDCSearch.java
+++ b/src/the/bytecode/club/bytecodeviewer/searching/LDCSearch.java
@@ -15,6 +15,7 @@ import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodNode;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -43,9 +44,15 @@ import org.objectweb.asm.tree.MethodNode;
public class LDCSearch implements SearchTypeDetails {
- JTextField searchText = new JTextField("");
+ JTextField searchText = null;
JPanel myPanel = null;
+ public LDCSearch()
+ {
+ searchText = new JTextField("");
+ searchText.addKeyListener(EnterKeyEvent.SINGLETON);
+ }
+
@Override
public JPanel getPanel() {
if (myPanel == null) {
@@ -58,8 +65,8 @@ public class LDCSearch implements SearchTypeDetails {
}
@Override
- public void search(final ClassNode node, final SearchResultNotifier srn,
- boolean exact) {
+ public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, boolean exact)
+ {
final Iterator methods = node.methods.iterator();
final String srchText = searchText.getText();
if (srchText.isEmpty())
@@ -83,9 +90,10 @@ public class LDCSearch implements SearchTypeDetails {
} catch (java.lang.ArrayIndexOutOfBoundsException e) {
}
- if ((exact && ldcString.equals(srchText))
- || (!exact && ldcString.contains(srchText))) {
- srn.notifyOfResult(node.name + "." + method.name
+
+ if ((exact && ldcString.equals(srchText)) || (!exact && ldcString.contains(srchText)))
+ {
+ srn.notifyOfResult(container.name+">"+node.name + "." + method.name
+ desc2
+ " -> \"" + ldcString + "\" > "
+ ldcObject.cst.getClass().getCanonicalName());
@@ -105,7 +113,7 @@ public class LDCSearch implements SearchTypeDetails {
}
if (field.value instanceof String) {
- srn.notifyOfResult(node.name + "." + field.name + desc2
+ srn.notifyOfResult(container.name+">"+node.name + "." + field.name + desc2
+ " -> \"" + field.value + "\" > field");
}
}
diff --git a/src/the/bytecode/club/bytecodeviewer/searching/MethodCallSearch.java b/src/the/bytecode/club/bytecodeviewer/searching/MethodCallSearch.java
index d440f226..bd2a00d9 100644
--- a/src/the/bytecode/club/bytecodeviewer/searching/MethodCallSearch.java
+++ b/src/the/bytecode/club/bytecodeviewer/searching/MethodCallSearch.java
@@ -16,6 +16,7 @@ import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import eu.bibl.banalysis.asm.desc.OpcodeInfo;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -44,10 +45,19 @@ import eu.bibl.banalysis.asm.desc.OpcodeInfo;
public class MethodCallSearch implements SearchTypeDetails {
- JTextField mOwner = new JTextField(""), mName = new JTextField(""),
- mDesc = new JTextField("");
+ JTextField mOwner = new JTextField(""), mName = new JTextField(""), mDesc = new JTextField("");
JPanel myPanel = null;
+ public MethodCallSearch()
+ {
+ mOwner = new JTextField("");
+ mOwner.addKeyListener(EnterKeyEvent.SINGLETON);
+ mName = new JTextField("");
+ mName.addKeyListener(EnterKeyEvent.SINGLETON);
+ mDesc = new JTextField("");
+ mDesc.addKeyListener(EnterKeyEvent.SINGLETON);
+ }
+
@Override
public JPanel getPanel() {
if (myPanel == null) {
@@ -64,8 +74,7 @@ public class MethodCallSearch implements SearchTypeDetails {
}
@Override
- public void search(final ClassNode node, final SearchResultNotifier srn,
- boolean exact) {
+ public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, boolean exact) {
final Iterator methods = node.methods.iterator();
String owner = mOwner.getText();
if (owner.isEmpty()) {
@@ -110,7 +119,7 @@ public class MethodCallSearch implements SearchTypeDetails {
} catch (java.lang.ArrayIndexOutOfBoundsException e) {
}
- srn.notifyOfResult(node.name
+ srn.notifyOfResult(container.name+">"+node.name
+ "."
+ method.name
+ desc2
@@ -135,7 +144,7 @@ public class MethodCallSearch implements SearchTypeDetails {
} catch (java.lang.ArrayIndexOutOfBoundsException e) {
}
- srn.notifyOfResult(node.name
+ srn.notifyOfResult(container.name+">"+node.name
+ "."
+ method.name
+ desc2
diff --git a/src/the/bytecode/club/bytecodeviewer/searching/RegexSearch.java b/src/the/bytecode/club/bytecodeviewer/searching/RegexSearch.java
index 07888b6f..94c40eaa 100644
--- a/src/the/bytecode/club/bytecodeviewer/searching/RegexSearch.java
+++ b/src/the/bytecode/club/bytecodeviewer/searching/RegexSearch.java
@@ -10,6 +10,7 @@ import javax.swing.JTextField;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -38,14 +39,22 @@ import org.objectweb.asm.tree.MethodNode;
public class RegexSearch implements SearchTypeDetails {
- public static JTextField searchText = new JTextField("");
+ public static JTextField searchText;
JPanel myPanel = null;
+ public RegexSearch()
+ {
+ searchText = new JTextField("");
+ searchText.addKeyListener(EnterKeyEvent.SINGLETON);
+ }
+
private static RegexInsnFinder regexFinder;
@Override
- public JPanel getPanel() {
- if (myPanel == null) {
+ public JPanel getPanel()
+ {
+ if (myPanel == null)
+ {
myPanel = new JPanel(new GridLayout(1, 2));
myPanel.add(new JLabel("Search Regex: "));
myPanel.add(searchText);
@@ -55,31 +64,43 @@ public class RegexSearch implements SearchTypeDetails {
}
@Override
- public void search(final ClassNode node, final SearchResultNotifier srn,
- boolean exact) {
+ public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, boolean exact)
+ {
final Iterator methods = node.methods.iterator();
final String srchText = searchText.getText();
+
if (srchText.isEmpty())
return;
- while (methods.hasNext()) {
+
+ while (methods.hasNext())
+ {
final MethodNode method = methods.next();
- if (regexFinder == null) {
+ if (regexFinder == null)
+ {
regexFinder = new RegexInsnFinder(node, method);
- } else {
+ }
+ else
+ {
regexFinder.setMethod(node, method);
}
- if (regexFinder.find(srchText).length > 0) {
+ if (regexFinder.find(srchText).length > 0)
+ {
String desc2 = method.desc;
- try {
+ try
+ {
desc2 = Type.getType(method.desc).toString();
+
if (desc2 == null || desc2.equals("null"))
desc2 = method.desc;
- } catch (java.lang.ArrayIndexOutOfBoundsException e) {
+ }
+ catch (java.lang.ArrayIndexOutOfBoundsException e)
+ {
}
- srn.notifyOfResult(node.name + "." + method.name + desc2);
+
+ srn.notifyOfResult(container.name+">"+node.name + "." + method.name + desc2);
}
}
}
diff --git a/src/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java b/src/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java
index 81b37efd..2f65cb55 100644
--- a/src/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java
+++ b/src/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java
@@ -3,6 +3,7 @@ package the.bytecode.club.bytecodeviewer.searching;
import javax.swing.JPanel;
import org.objectweb.asm.tree.ClassNode;
+import the.bytecode.club.bytecodeviewer.util.FileContainer;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -31,5 +32,5 @@ import org.objectweb.asm.tree.ClassNode;
public interface SearchTypeDetails {
public JPanel getPanel();
- public void search(ClassNode node, SearchResultNotifier srn, boolean exact);
+ public void search(FileContainer container, ClassNode node, SearchResultNotifier srn, boolean exact);
}
diff --git a/src/the/bytecode/club/bytecodeviewer/APKTool.java b/src/the/bytecode/club/bytecodeviewer/util/APKTool.java
similarity index 96%
rename from src/the/bytecode/club/bytecodeviewer/APKTool.java
rename to src/the/bytecode/club/bytecodeviewer/util/APKTool.java
index 0ae6c2b0..2f4c1898 100644
--- a/src/the/bytecode/club/bytecodeviewer/APKTool.java
+++ b/src/the/bytecode/club/bytecodeviewer/util/APKTool.java
@@ -1,8 +1,9 @@
-package the.bytecode.club.bytecodeviewer;
+package the.bytecode.club.bytecodeviewer.util;
import java.io.File;
import org.apache.commons.io.FileUtils;
+import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
diff --git a/src/the/bytecode/club/bytecodeviewer/Dex2Jar.java b/src/the/bytecode/club/bytecodeviewer/util/Dex2Jar.java
similarity index 98%
rename from src/the/bytecode/club/bytecodeviewer/Dex2Jar.java
rename to src/the/bytecode/club/bytecodeviewer/util/Dex2Jar.java
index 73800d34..a0cac83c 100644
--- a/src/the/bytecode/club/bytecodeviewer/Dex2Jar.java
+++ b/src/the/bytecode/club/bytecodeviewer/util/Dex2Jar.java
@@ -1,4 +1,4 @@
-package the.bytecode.club.bytecodeviewer;
+package the.bytecode.club.bytecodeviewer.util;
import java.io.File;
diff --git a/src/the/bytecode/club/bytecodeviewer/Enjarify.java b/src/the/bytecode/club/bytecodeviewer/util/Enjarify.java
similarity index 96%
rename from src/the/bytecode/club/bytecodeviewer/Enjarify.java
rename to src/the/bytecode/club/bytecodeviewer/util/Enjarify.java
index 8e43c420..11eae1ed 100644
--- a/src/the/bytecode/club/bytecodeviewer/Enjarify.java
+++ b/src/the/bytecode/club/bytecodeviewer/util/Enjarify.java
@@ -1,4 +1,6 @@
-package the.bytecode.club.bytecodeviewer;
+package the.bytecode.club.bytecodeviewer.util;
+
+import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import java.io.File;
diff --git a/src/the/bytecode/club/bytecodeviewer/FileChangeNotifier.java b/src/the/bytecode/club/bytecodeviewer/util/FileChangeNotifier.java
similarity index 86%
rename from src/the/bytecode/club/bytecodeviewer/FileChangeNotifier.java
rename to src/the/bytecode/club/bytecodeviewer/util/FileChangeNotifier.java
index 3bfcb9c9..c4cc6b09 100644
--- a/src/the/bytecode/club/bytecodeviewer/FileChangeNotifier.java
+++ b/src/the/bytecode/club/bytecodeviewer/util/FileChangeNotifier.java
@@ -1,4 +1,4 @@
-package the.bytecode.club.bytecodeviewer;
+package the.bytecode.club.bytecodeviewer.util;
import org.objectweb.asm.tree.ClassNode;
@@ -27,7 +27,7 @@ import org.objectweb.asm.tree.ClassNode;
*/
public interface FileChangeNotifier {
- public void openClassFile(String name, ClassNode cn);
+ public void openClassFile(final FileContainer container, String name, ClassNode cn);
- public void openFile(String name, byte[] contents);
+ public void openFile(final FileContainer container, String name, byte[] contents);
}
\ No newline at end of file
diff --git a/src/the/bytecode/club/bytecodeviewer/FileContainer.java b/src/the/bytecode/club/bytecodeviewer/util/FileContainer.java
similarity index 84%
rename from src/the/bytecode/club/bytecodeviewer/FileContainer.java
rename to src/the/bytecode/club/bytecodeviewer/util/FileContainer.java
index 97da4e21..b7f76a4f 100644
--- a/src/the/bytecode/club/bytecodeviewer/FileContainer.java
+++ b/src/the/bytecode/club/bytecodeviewer/util/FileContainer.java
@@ -1,4 +1,4 @@
-package the.bytecode.club.bytecodeviewer;
+package the.bytecode.club.bytecodeviewer.util;
import java.io.File;
import java.util.ArrayList;
@@ -34,12 +34,12 @@ public class FileContainer {
public FileContainer(File f) {
this.file = f;
- this.name = f.getName();
+ this.name = LazyNameUtil.applyNameChanges(f.getName());
}
public FileContainer(File f, String name) {
this.file = f;
- this.name = name;
+ this.name = LazyNameUtil.applyNameChanges(name);
}
public File file;
@@ -47,4 +47,12 @@ public class FileContainer {
public HashMap files = new HashMap();
public ArrayList classes = new ArrayList();
+
+ public ClassNode getClassNode(String name) {
+ for (ClassNode c : classes)
+ if (c.name.equals(name))
+ return c;
+
+ return null;
+ }
}
diff --git a/src/the/bytecode/club/bytecodeviewer/FileDrop.java b/src/the/bytecode/club/bytecodeviewer/util/FileDrop.java
similarity index 99%
rename from src/the/bytecode/club/bytecodeviewer/FileDrop.java
rename to src/the/bytecode/club/bytecodeviewer/util/FileDrop.java
index 5d9882fa..4620a1f0 100644
--- a/src/the/bytecode/club/bytecodeviewer/FileDrop.java
+++ b/src/the/bytecode/club/bytecodeviewer/util/FileDrop.java
@@ -1,4 +1,4 @@
-package the.bytecode.club.bytecodeviewer;
+package the.bytecode.club.bytecodeviewer.util;
import java.awt.datatransfer.DataFlavor;
import java.io.BufferedReader;
diff --git a/src/the/bytecode/club/bytecodeviewer/JarUtils.java b/src/the/bytecode/club/bytecodeviewer/util/JarUtils.java
similarity index 96%
rename from src/the/bytecode/club/bytecodeviewer/JarUtils.java
rename to src/the/bytecode/club/bytecodeviewer/util/JarUtils.java
index 097e5cc6..b290c76d 100644
--- a/src/the/bytecode/club/bytecodeviewer/JarUtils.java
+++ b/src/the/bytecode/club/bytecodeviewer/util/JarUtils.java
@@ -1,4 +1,4 @@
-package the.bytecode.club.bytecodeviewer;
+package the.bytecode.club.bytecodeviewer.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -18,6 +18,7 @@ import me.konloch.kontainer.io.DiskWriter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
+import the.bytecode.club.bytecodeviewer.BytecodeViewer;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@@ -66,10 +67,7 @@ public class JarUtils {
if (!entry.isDirectory())
files.put(name, bytes);
} else {
- String cafebabe = String.format("%02X", bytes[0])
- + String.format("%02X", bytes[1])
- + String.format("%02X", bytes[2])
- + String.format("%02X", bytes[3]);
+ String cafebabe = String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format("%02X", bytes[2]) + String.format("%02X", bytes[3]);
if (cafebabe.toLowerCase().equals("cafebabe")) {
try {
final ClassNode cn = getNode(bytes);
@@ -104,10 +102,7 @@ public class JarUtils {
final String name = entry.getName();
if (name.endsWith(".class")) {
byte[] bytes = getBytes(jis);
- String cafebabe = String.format("%02X", bytes[0])
- + String.format("%02X", bytes[1])
- + String.format("%02X", bytes[2])
- + String.format("%02X", bytes[3]);
+ String cafebabe = String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format("%02X", bytes[2]) + String.format("%02X", bytes[3]);
if (cafebabe.toLowerCase().equals("cafebabe")) {
try {
final ClassNode cn = getNode(bytes);
diff --git a/src/the/bytecode/club/bytecodeviewer/util/LazyNameUtil.java b/src/the/bytecode/club/bytecodeviewer/util/LazyNameUtil.java
new file mode 100644
index 00000000..4dcbcff4
--- /dev/null
+++ b/src/the/bytecode/club/bytecodeviewer/util/LazyNameUtil.java
@@ -0,0 +1,59 @@
+package the.bytecode.club.bytecodeviewer.util;
+
+/***************************************************************************
+ * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
+ * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+import org.apache.commons.io.FilenameUtils;
+
+import java.util.HashMap;
+
+/**
+ * @author Konloch
+ */
+public class LazyNameUtil
+{
+ public static boolean SAME_NAME_JAR_WORKSPACE = false;
+
+ private static final HashMap nameMap = new HashMap<>();
+
+ public static void reset()
+ {
+ nameMap.clear();
+ }
+
+ public static String applyNameChanges(String name)
+ {
+ if(nameMap.containsKey(name))
+ {
+ if(!SAME_NAME_JAR_WORKSPACE)
+ SAME_NAME_JAR_WORKSPACE = true;
+
+ int counter = nameMap.get(name)+1;
+ nameMap.put(name, counter);
+
+ return FilenameUtils.removeExtension(name)+"#"+counter+"."+FilenameUtils.getExtension(name);
+ }
+ else
+ {
+ nameMap.put(name, 1);
+ }
+
+ return name;
+ }
+
+}
diff --git a/src/the/bytecode/club/bytecodeviewer/util/MethodParser.java b/src/the/bytecode/club/bytecodeviewer/util/MethodParser.java
new file mode 100644
index 00000000..66d3ffc0
--- /dev/null
+++ b/src/the/bytecode/club/bytecodeviewer/util/MethodParser.java
@@ -0,0 +1,147 @@
+package the.bytecode.club.bytecodeviewer.util;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+/**
+ * Methods parser.
+ *
+ * @author DreamSworK
+ *
+ */
+public class MethodParser
+{
+
+ public static class Method {
+ public String name;
+ public List params;
+
+ public Method(String name, List params) {
+ this.name = name;
+ this.params = params;
+ }
+
+ public String toString() {
+ String params = this.params.toString();
+ return this.name + "(" + params.substring(1, params.length() - 1) + ")";
+ }
+ }
+
+ public static final Pattern regex = Pattern.compile("\\s*(?:static|public|private|protected|final|abstract)[\\w\\s.<>\\[\\]]*\\s+(?[\\w.]+)\\s*\\((?[\\w\\s,.<>\\[\\]$?]*)\\)");
+
+ private TreeMap methods = new TreeMap<>();
+
+ private static String removeBrackets(String string) {
+ if (string.indexOf('<') != -1 && string.indexOf('>') != -1) {
+ return removeBrackets(string.replaceAll("<[^<>]*>", ""));
+ }
+ return string;
+ }
+
+ private static String getLastPart(String string, int character) {
+ int ch = string.lastIndexOf(character);
+ if (ch != -1) {
+ string = string.substring(ch + 1);
+ }
+ return string;
+ }
+
+ public void addMethod(int line, String name, String params) {
+ if (!name.isEmpty()) {
+ name = getLastPart(name,'.');
+ String[] args = {};
+ if (!params.isEmpty()) {
+ params = removeBrackets(params);
+ args = params.split(",");
+ for (int i = 0; i < args.length; i++) {
+ args[i] = args[i].trim();
+ if (args[i].indexOf(' ') != -1) {
+ String[] strings = args[i].split(" ");
+ args[i] = strings[strings.length - 2];
+ }
+ args[i] = getLastPart(args[i],'.');
+ args[i] = getLastPart(args[i],'$');
+ }
+ }
+ Method method = new Method(name, Arrays.asList(args));
+ methods.put(line, method);
+ }
+ }
+
+ public boolean isEmpty() {
+ return methods.isEmpty();
+ }
+
+ public Method getMethod(int line) {
+ return methods.get(line);
+ }
+
+ public Integer[] getMethodsLines() {
+ Integer[] lines = new Integer[methods.size()];
+ return methods.keySet().toArray(lines);
+ }
+
+ public String getMethodName(int line) {
+ Method method = methods.get(line);
+ if (method != null) {
+ if (!method.name.isEmpty())
+ return method.name;
+ }
+ return "";
+ }
+
+ public List getMethodParams(int line) {
+ Method method = methods.get(line);
+ if (method != null) {
+ if (!method.params.isEmpty())
+ return method.params;
+ }
+ return null;
+ }
+
+ public int findMethod(Method method) {
+ return findMethod(method.name, method.params);
+ }
+
+ public int findMethod(String name, List params) {
+ for (Map.Entry