This commit is contained in:
Konloch 2019-04-17 00:45:15 -06:00
parent e092c3bba8
commit fdb1468c7b

AI 샘플 코드 생성 중입니다

Loading...
170 changed files with 4672 additions and 26039 deletions

View File

@ -1,353 +0,0 @@
Changelog:
```
--- Beta 1.0.0 ---:
10/4/2014 - Designed a POC GUI, still needs a lot of work.
10/4/2014 - Started importing J-RET's backend.
10/5/2014 - Finished importing J-RET's backend.
10/6/2014 - Started modifying J-RET's UI.
10/6/2014 - Added several FernFlower options.
10/6/2014 - Fixed the class search function so it doesn't require exact class names.
10/6/2014 - Added save as, it'll save all of the loaded classes into one jar file (GUI Jar-Jar now).
10/6/2014 - Centered the select jar text inside of the file navigator.
10/6/2014 - Properly threaded the open jar function, now fernflower/bytecode decompiler runs in the background.
10/6/2014 - Added a hex viewer (Instead of using Re-Java's, I've decided to use a modified version of JHexEditor).
10/6/2014 - Made all of the viewer (Sourcecode, Bytecode & Hexcode toggleable).
10/7/2014 - Fixed the search function.
10/7/2014 - You can now add new files without it creating a new workspace.
10/7/2014 - Added new workspace button underneath File, this will reset the workspace.
10/7/2014 - Renamed File>Open.. to File>Add..
10/7/2014 - Added recent files.
10/7/2014 - Did some bitch work, the project has no warnings now.
10/7/2014 - Added waiting cursors to anything that will require waiting or loading.
10/8/2014 - Searching now runs in a background thread.
10/8/2014 - Added File>About.
10/8/2014 - The main GUI now starts in the middle of your screen, same with the about window.
10/8/2014 - Made the File Navigator Pane, Workspace Pane & Search Pane a little sexier.
10/9/2014 - Started on a Plugin system
10/9/2014 - Added a malicious code scanner plugin, based off of the one from J-RET, this searches for a multitude of classes/packages that can be used for malicious purposes.
10/9/2014 - Added a show all strings plugin, this grabs all the declared strings and displays them in a nice little window.
10/9/2014 - Fixed a bug with Bytecode Decompiler, where it would it display \r and \n as return carriages.
10/9/2014 - Fixed the Bytecode Decompiler>Debug Instructions option.
10/9/2014 - Save Class Files As is now renamed to Save Files As.
10/9/2014 - Save Files As now saves jar resources, not just classfiles.
10/9/2014 - Added an 'Are you sure' pane when you click on File>New Workspace.
10/9/2014 - Save Files As is no longer dependent on the File System, now if you're on windows and you have a file called AA, and one called Aa, you're fine.
10/11/2014 - Modified the FernFlower library, it no longer spits out System.out.println's while processing a method, this has sped it up quite a lot.
10/12/2014 - Fix an issue when resizing.
10/12/2014 - Modified the core slighty to no longer have a modularized decompiling system (since there are only 2 decompilers anyways).
10/12/2014 - Fixed an issue with decompiling multiple files at once.
10/12/2014 - The Plugin Console now shows the plugin's name on the title.
10/12/2014 - Debug Helpers will now debug all jump instructions by showing what instruction is on the line it's suppose to goto, example: 90. goto 120 // line 120 is PUTFIELD Animable_Sub4.anInt1593 : I
10/12/2014 - Now when you select an already opened file, it will automatically go to that opened pane.
10/14/2014 - Added the option 'exact' to the class finder.
10/14/2014 - Added the option 'exact' to the searcher, now it'll search for .contains when unselected.
10/14/2014 - Stopped the use of StringBuffer, replaced all instances with StringBuilder.
10/14/2014 - Added Labels and Try-Catch blocks to the Bytecode Decompiler.
10/14/2014 - For panes that are not selected, the corresponding decompiler will not execute.
10/14/2014 - Added plugin Show Main Methods, this will show every single public static void main(String[]).
10/14/2014 - Plugins can no longer be ran when there is no loaded classes.
10/14/2014 - The Malicious Code Scanner now has gui option pane before you run it.
10/14/2014 - Added a java/io option to the Malicious Code Scanner.
10/14/2014 - Added save Java files as.
10/15/2014 - Added save as Jar file. (Export as Jar)
10/15/2014 - Added the option to ASCII only strings in the Bytecode Decompiler.
10/15/2014 - External plugins are now fully functional, same with recent plugins.
10/16/2014 - Removed all refences of 'ClassContainer'.
10/16/2014 - Rewrote the tempfile system.
10/16/2014 - Moved the file import to BytecodeViewer.class.
10/16/2014 - Fixed a jTree updating issue.
10/16/2014 - Now if you try search with an empty string, it won't search.
10/16/2014 - Added Replace Strings plugin.
10/16/2014 - Added a loading icon that displays whenever a background task is being executed.
--- Beta 1.1.0 ---:
10/19/2014 - Fixed harcoded \\.
--- Beta 1.2.0 ---:
10/19/2014 - Started importing Procyon and CFR decompilers.
10/19/2014 - Partially finished importing Procyon and CFR, just need to finish export java files as zip.
--- Beta 1.3.0 ---:
10/22/2014 - Imported Bibl's Bytecode Decompiler from CFIDE.
10/22/2014 - Did some changes to the Bytecode Decompiler.
10/23/2014 - Added CFR settings.
10/23/2014 - Updated FernFlower to Intellij's Open Sourced version of FernFlower.
10/24/2014 - Fixed FernFlower save Java files as zip.
10/29/2014 - Added version checker.
10/29/2014 - Added Procyon settings.
10/29/2014 - When saving as jars or zips, it'll automatically append the file extension if it's not added.
10/29/2014 - All the built in plugins no longer set the cursor to busy.
10/29/2014 - Tried to fix the issue with JSyntaxPane by making it create the object in a background thread, it still freezes the UI. Changes kept for later implementation of another syntax highlighter.
10/29/2014 - Sped up start up time
--- Beta 1.3.1 ---:
10/29/2014 - Replaced JSyntaxPane with RSyntaxArea, this sadly removes the search feature inside of source/bytecode files, I'll implement a search function soon. (This also fixes the JRE 1.8 issue)
10/29/2014 - Added a new decompiler option to append brackets to labels.
10/31/2014 - Fixed an issue with the decompiler still running when the source code pane isn't toggled.
--- Beta 1.4.0 ---:
11/1/2014 - Fixed FernFlower save Java files on Unix.
11/1/2014 - FernFlower now uses the settings for save Java files.
11/1/2014 - Added Procyon save Java files (It uses the settings).
11/1/2014 - Updated CFR to cfr_0_89.
11/1/2014 - Added CFR save Java files (It uses the settings), however it relies on the file system, because of this if there is heavy name obfuscation, it could mess up for windows.
--- Beta 1.5.0 ---:
11/1/2014 - Updated and improved the search function, it now prints out more useful information.
11/1/2014 - Fixed a UI issue with the Replace All Strings plugin.
11/2/2014 - Added search function to the Class Viewer.
11/2/2014 - Updated Procyon to procyon-decompiler-0.5.27.
--- Beta 1.5.1 ---:
11/2/2014 - Fixed a CFR issue with packages.
--- Beta 1.5.2 ---:
11/3/2014 - Fixed Refresh Class.
--- Beta 1.5.3 ---:
11/3/2014 - Settings/Temp file are now in a global directory.
11/3/2014 - The GUI setttings now save.
11/3/2014 - Removed the option to disable syntax highlighting (since it's lightweight now).
11/3/2014 - About window now contains the version number and the BCV directory.
11/3/2014 - Added an option to toggle to outdated status.
--- 2.0.0 ---: //Out of beta, WOO
11/4/2014 - Officially been 1 month of development.
11/4/2014 - Replaced ""+ with String.valueOf (cheers bibl).
11/4/2014 - Changed how the temp directory was created.
11/4/2014 - Put a file.seperator to the end of tempDirectory.
11/4/2014 - Made the exit button work.
11/4/2014 - Added a GUI for all Exception Stack Trace's.
11/4/2014 - The plugin system now shows a message instead of just printing to the console when it's not going to run a plugin.
11/4/2014 - Updated the search function, it's now perfect.
11/5/2014 - Made the Show All Strings plugin instant.
11/5/2014 - Kinda added middle mouse button closes tab (only if you click the exit button).
11/5/2014 - Improved the Malicious Code Scanner, also made it instant.
11/5/2014 - Added icons to the program (cheers Fluke).
--- 2.0.1 ---:
11/7/2014 - Fixed the search function.
11/7/2014 - Removed an unused package containing some unused classes.
--- 2.1.0 ---:
11/5/2014 - Started working on the EZ-Inject plugin.
11/6/2014 - Fixed the ClassNodeDecompiler creating unnessessary objects. (thanks bibl).
11/6/2014 - Finished an alpha version of EZ-Inject.
11/6/2014 - Started working on a basic obfuscator.
11/6/2014 - The Obfuscator now sucessfully renames all field names.
11/6/2014 - Updated CFR to cfr_0_90.
11/8/2014 - Started working on the API for BCV.
11/9/2014 - Decided to make a graphical reflection kit.
11/10/2014 - Made some progress with the obfuscator, almost finished EZ-Injection.
11/14/2014 - Been doing various updates to EZ-Injection, Obfucsation, Reflection Kit and the BCV API.
11/16/2014 - Added the option to launch BCV command line as java -jar bcv.jar C:/test.jar C:/example/whatever.jar
11/17/2014 - Fixed an issue with the out of date checking UI still activating when not selected.
11/19/2014 - Added annotatitons/local variables to the methodnode decompiler (Thanks Bibl).
11/21/2014 - Decided to release it with the obfuscator/reflection kit unfinished, they're currently disabled for future use.
--- 2.1.1 ---:
12/09/2014 - Upated CFR to cfr_0_91.
--- 2.2.0 ---:
12/09/2014 - Added a text search function to the plugin console.
12/09/2014 - When you press enter in the text search bar, it will now search.
12/13/2014 - The Bytecode Decompiler now shows the method's description in a comment.
12/13/2014 - Fixed an issue with the text search function.
12/13/2014 - Search results are now clickable.
--- 2.2.1 ---:
12/13/2014 - Fixed an issue with the Bytecode Decompiler. - Thanks bibl
--- 2.3.0 ---:
12/16/2014 - Started updating the class viewer.
12/18/2014 - Finished a basic concept of the new class viewer.
12/18/2014 - Fixed an error with importing some jars.
12/18/2014 - Fixed the about window.
12/18/2014 - Finished the final concept for the new class viewer.
12/18/2014 - Threaded save Java files as zip, it now runs in a background thread.
12/18/2014 - Save Java files as zip now prompts you to select a decompiler.
12/18/2014 - Removed the cursor waiting for save Java files as zip.
12/18/2014 - Wrapped the save Java files as zip around an exception handler, it will now safely show the exception if any is thrown.
12/18/2014 - Fixed not escaping the Java strings by default for the Bytecode decompiler. - http://i.imgur.com/YrRnZA7.png
12/18/2014 - Used Eclipse's code formatting tool and formatted the code
12/19/2014 - Priav03 fixed the quick class searcher.
--- 2.4.0 ---:
12/19/2014 - Afffsdd made the Bytecode Viewer directory hidden.
12/19/2014 - Added save Java file as, for singular class file decompilation (this is threaded).
12/19/2014 - Removed unused Bytecode Decompiler debug code.
12/20/2014 - Made a new outdated pane - http://i.imgur.com/xMxkwJ9.png
12/20/2014 - Added an expand/collapse the packages in the file navigator.
12/20/2014 - Moved all of the settings to the.bytecode.club.bytecodeviewer.Settings
12/20/2014 - If the class file does not start with CAFEBABE it won't be processed.
12/20/2014 - Properly handled file not found error.
12/21/2014 - Fixed the Refresh Class causing a dupe.
--- 2.5.0 ---:
12/28/2014 - Improved the outdated version pane by including an automatic downloader - http://i.imgur.com/4MXeBGb.png - http://i.imgur.com/v50Pghe.png - http://i.imgur.com/bVZqxZ2.png - http://i.imgur.com/l8nIMzD.png
12/28/2014 - Updated CFR to cfr_0.92.jar
12/31/2014 - Adrianherrera updated the Malicious Code Scanner to detect the security manager being set to null.
**HAPPY NEW YEAR**
01/01/2015 - Added refresh class on decompiler/pane view change
01/01/2015 - Moved all of the settings into a settings pane
01/01/2015 - Added some debug code when you first start it up, it also includes how long it took to fully load up.
01/02/2015 - Cached the busy icon.
01/02/2015 - >> ADDED APK SUPPORT <<, had to downgrade to ASM 3.3, which means losing some annotation debugging for the Bytecode Decompiler.
01/03/2015 - Wrapped the search pane in a JScrollPane.
01/06/2015 - Added save as DEX and import .dex files.
--- 2.5.1 ---:
01/06/2015 - Silenced the error connecting to update server for offline mode.
01/06/2015 - Fixed a search function with Android APKs.
--- 2.5.2 ---:
01/06/2015 - Completely fixed the search function with Android APKs.
--- 2.6.0 ---:
01/06/2015 - Now saves if maximized or not.
01/07/2015 - For all save as functions, it will now append the correct extension if not added by the user.
01/07/2015 - You can no longer use use the save functions if no classes are loaded (fixes a crash issue).
01/07/2015 - Moved the Update Check to the Settings menu.
01/08/2015 - Added an extremely basic code sqeuence diagram plugin.
01/08/2015 - Updated CFR to CFR_0.93.jar
01/08/2015 - Threaded the Add files function.
01/08/2015 - Finally implemented Kontainer's HTTPRequest wrapper now that I've open sourced it.
01/08/2015 - Set the panes to be non-editable.
01/08/2015 - Sexified the view pane selection.
01/08/2015 - Started working on Smali Editing support, finished decompiler so far.
01/09/2015 - Fixed a bug with saving.
01/09/2015 - Added add entire directory.
01/09/2015 - Fixed import .DEX files.
01/10/2015 - Finished Smali Editing.
01/10/2015 - Fixed a class opening issue with synchronization.
01/11/2015 - Threaded all of the save functions.
01/11/2015 - Removed all instances of the setCursor to busy.
01/11/2015 - Added are you sure you wish to overwrite this existing file to all the other save functions.
01/11/2015 - All of the decompiling names are now randomly generated instead of a counting number.
01/11/2015 - Updated CFR to CFR_0.94.jar
01/11/2015 - Updated to the latest version of FernFlower.
01/11/2015 - Fixed an extension appending issue with save Java file.
--- 2.7.0 ---:
01/11/2015 - Improved the Refresh Class function to be used as the default compile function.
01/11/2015 - Implemented better error handling for decompiling class files.
01/15/2015 - CTRL + O will open the add file interface.
01/15/2015 - CTRL + N will open the net workspace interface.
01/15/2015 - It will now save the last directory you opened.
01/15/2015 - Some how the URL for the auto updater change log got changed, this has been fixed.
01/15/2015 - Slightly updated the change log display, it'll now show all the changes since your version.
01/16/2015 - Made EZ-Injection UI look a bit nicer.
01/27/2015 - Decided to scrap the JVM Sandbox POC and use the Security Manager.
01/27/2015 - BCV now blocks exec and won't allow any ports to be bound.
--- 2.7.1 ---:
01/27/2015 - Fixed hide file.
--- 2.8.0 ---:
02/01/2015 - Updated CFR and Proycon to latest versions.
02/01/2015 - Started working on implementing Krakatau.
02/01/2015 - Sexifixed the security manager a little bit.
02/03/2015 - Fully added Krakatau Java decompiler, just disassembly/assembly left.
02/03/2015 - Updated the about window.
02/03/2015 - Dropped JRuby and Jython support (BCV is now roughly 16mb, was 45mb).
02/04/2015 - Added Krakatau Disassembly.
02/04/2015 - Added Krakatau Assembly.
--- 2.8.1 ---:
02/04/2015 - Fixed UI bug with Krakatau/Krakatau Editable view panes.
02/05/2015 - Added CTRL + F.
--- 2.9.0 ---:
02/11/2015 - Added ZStringArray String Decrypter. (Thanks Righteous)
02/20/2015 - Moved the decompilers/disassemblers around.
02/20/2015 - Fixed a resource leak with Krakatau Decompiler/Disassembler/Assembler.
02/21/2015 - Fixed regex searching if your regex search contained a syntax error.
02/21/2015 - Added the compiler/decompiler instances to the BytecodeViewer API class.
02/21/2015 - Sped up the decompilers, each view pane runs its own decompiler thread.
02/21/2015 - Added Janino compiler, you can now compile the decompiled source code inside of BCV.
02/21/2015 - Added the editable option for almost all of the decompilers/disassemblers.
02/21/2015 - Cached the next/previous icons and added a resources class for all resources.
01/21/2015 - Renamed EZ-Injection as File-Run, however kept the plugin named EZ-Injection.
02/21/2015 - Dropped Groovy support, added .Java plugin compilation instead (now only 10mb).
02/21/2015 - Added support for reading resources, including displaying images, detecting pure ascii files and more.
02/21/2015 - Fixed an issue with loading an already selected node in the file navigation pane.
02/22/2015 - Added an error console to the Java compiler
02/22/2015 - Ensured the spawned Python/Krakatau processes are killed when closing BCV.
02/22/2015 - Made it more beginner friendly.
02/22/2015 - Fixed? The file navigation search.
02/22/2015 - Added a shit ton more comments to non-api related classes.
02/23/2015 - Added APK resources.
02/23/2015 - MORE ANDROID LOVE! Added APKTool.jar's decode. (Takes a while so it's a setting, also pumped the jar back to 16MB)
02/23/2015 - Added close all but this tab menu.
02/23/2015 - Not really code related, but added _install.bat and _uninstall.bat for the exe version of BCV.
02/23/2015 - Back to ASM5, packed dex2jar in its own obfuscated jar.
02/23/2015 - Added the annotations back to the Bytecode Decompiler. (Once again, thanks Bibl)
02/23/2015 - It once again works with Java 8 Jars.
--- 2.9.1 ---:
02/24/2015 - Fixed the third pane window not showing the search buttons.
02/24/2015 - Fixed some issues with the compiler functionality.
--- 2.9.2 ---:
02/24/2015 - Actually fixed the compiler, LOL.
--- 2.9.3 ---:
02/28/2015 - Added drag and drop for any file.
02/28/2015 - Added ctrl + w to close the current opened tab.
02/28/2015 - Updated to CFR 0_97.jar
02/28/2015 - Fixed a concurrency issue with the decompilers.
02/28/2015 - Added image resize via scroll on mouse.
02/28/2015 - Added resource refreshing.
02/28/2015 - Im Frizzy started working on Obfuscation.
03/20/2015 - Updated Dex2Jar to 2.0.
03/20/2015 - Updated CFR to 0_98.jar
--- 2.9.4 ---:
04/19/2015 - Added -O to be passed for Krakatau Decompiler/Disassembler/Assembler. (Thanks Storyyeller).
04/19/2015 - Added -skip to be passed for Krakatau Decompiler. (Thanks Storyyeller).
04/19/2015 - Changed the warning window for Python to recommend PyPy. (Thanks Storyyeller).
04/20/2015 - Happy 2015 4/20 (Shoutout to @announce420 for being 2 years old).
04/21/2015 - Started reworking the View Panes.
04/21/2015 - Finished reworking the View Panes - http://i.imgur.com/SqIw4Vj.png - Cheers to whoever's idea this was (I forget sorry <3).
04/21/2015 - Updated CFR to 0_100.jar
04/21/2015 - Added CTRL + R for run.
04/21/2015 - Added CTRL + S for save files as.
04/21/2015 - Added CTRL + T for compile.
04/21/2015 - Added Krakatau optional library.
04/21/2015 - The about pane now provides a lot more up to date information.
04/21/2015 - Changed 'View Panes' to simply 'View'.
--- 2.9.5 ---:
05/01/2015 - Added 'pingback' for statistics (to track how many people globally use BCV)
--- 2.9.6 ---:
05/05/2015 - Fixed a typo in the about window
05/28/2015 - Started importing JD-GUI Decompiler.
05/28/2015 - Compile on refresh and compile on save are now enabled by default.
05/28/2015 - Renamed the File>Save As options to be much more informative.
06/24/2015 - Fixed a logic error with the Field & Method searchers.
06/26/2015 - Updated Procyon & CFR to their latest versions.
07/02/2015 - Added JD-GUI Decompiler. - Huge thanks to the guys behind JD-GUI! <3 (FIVE DECOMPILERS NOW LOL)
--- 2.9.7 ---:
07/02/2015 - Added ajustable font size.
07/05/2015 - Started working on the new Boot Screen.
07/06/2015 - Moved the font size to be under the view menu.
07/06/2015 - Fixed a bug with plugins not being able to grab the currently viewed class.
07/07/2015 - Started adding enjarify as an optional APK converter instead of Dex2Jar.
07/07/2015 - Finished the new Boot Screen
07/09/2015 - Fixed a process leak with krakatau decompiler.
07/09/2015 - Finished adding enjarify.
07/09/2015 - Supressed syntax exceptions due to JD-GUI.
07/09/2015 - Fixed refresh on non-refreshable resources.
07/09/2015 - Fixed opening a class and the name is so big, you cannot close because the [X] does not appear.
07/09/2015 - Added support for smaller screens for the boot screen.
07/16/2015 - Removed the FileFilter classes.
07/16/2015 - Updated the decompiler class to make more sense.
07/16/2015 - Started working on BCV CLI.
07/16/2015 - Finished BCV CLI.
--- 2.9.8 ---:
07/19/2015 - Fixed enjarify.
07/20/2015 - Bibl sexified the boot loading time.
07/20/2015 - Decode APK Resources is selected by default.
07/20/2015 - Made the security manager slightly safer, it can still be targeted but not as obviously now.
07/20/2015 - Added CLI to the boot page.
07/21/2015 - Added support for offline mode in case you cannot connect to github for some reason. (kicks in after 7 seconds)
07/21/2015 - Added fatjar option back, in case anyone wants a 100% portable version.
07/21/2015 - Made it so it now shows the decompiler it's using - http://i.imgur.com/yMEzXwv.png.
07/21/2015 - Rewrote the file system, it now shows the path of the jar it's got loaded.
07/21/2015 - Now it shows if the decompiler is in editable mode or not.
07/21/2015 - Fixed Enjarify bug from new security manager.
07/22/2015 - Fixed a typo (Thanks affffsdsd)
07/22/2015 - Finally added icons to the File Navigator, credits to http://famfamfam.com/lab/icons/silk/ for the icons.
07/22/2015 - JD-GUI is now the default decompiler for GUI.
07/22/2015 - Added Set Python 3.X to the UI.
07/22/2015 - Fixed krakatau/export as jar bug introduced by file system update.
07/22/2015 - Sped up krakatau decompiler/disassembler on big files.
07/22/2015 - Made it so when you press enter on the file navigation pane it opens the class.
07/22/2015 - The Quick file search now opens the files again.
07/23/2015 - Fixed opening single files and file folders into BCV
07/24/2015 - Added File>Reload Resources.
07/26/2015 - Fixed the view pane refresh after toggling a viewer, it's now flawless.
07/26/2015 - Fixed Krakatau Disassembler.
07/26/2015 - Mibbzz is gay once again.
07/30/2015 - Removed Janino Compiler & moved to Javac, it can now compile decompiled classes again.
07/30/2015 - Affssdd fixed the File Navigator Pane's Quick Class Search.
07/30/2015 - Fixed a process leak in KrakatauDisassembler.
07/30/2015 - Started working on converting all the decompilers to launch in their own process in an effort to reduce BCV resources (only for non-fatjar version).
--- 2.9.10 ---;
1/30/2018 - Reverted back to what seemed like a stable 2.9.9 build and screwed around with it.
1/31/2018 - That build was bugged, screw this and let's start over back from 2.9.8.
1/31/2018 - Fixed CFR not showing (bug from 2.9.9)
1/31/2018 - Beefed up Bytecode decompiler.
1/31/2018 - Fomatted all the classes so GitHub doesn't show them as a mess.
1/31/2018 - Made Krakatau and Enjarify work offline (assuming you have the libraries).
1/31/2018 - Added stackframes remover.
```

View File

@ -1,3 +1,3 @@
Contribution Guide Lines/Coding Conventions:
## Contribution Guide Lines/Coding Conventions
* Packages must start with the.bytecode.club.bytecodeviewer.
* All variables must be at the start of each class.

30
CREDITS.md Normal file
View File

@ -0,0 +1,30 @@
## Code from various projects has been used, including but not limited to
* J-RET by WaterWolf
* JHexPane by Sam Koivu
* RSynaxPane by Robert Futrell
* Commons IO by Apache
* ASM by OW2
* FernFlower by Stiver
* Procyon by Mstrobel
* CFR by Lee Benfield
* CFIDE by Bibl
* Smali by JesusFreke
* Dex2Jar by pxb1988
* Krakatau by Storyyeller
* JD GUI/JD Core by The Java-Decompiler Team
* Enjarify by Storyyeller
## Contributors
* Konloch
* Bibl
* Fluke
* Righteous
* sahitya-pavurala
* priav03
* Afffsdd
* Szperak
* Zooty
* samczsun
* ItzSomebody
* DreamSworK
* If I missed you, please feel free to contact me @Konloch or konloch@gmail.com

View File

@ -1,60 +1,30 @@
# Bytecode Viewer
Bytecode Viewer is an Advanced Lightweight Java Bytecode Viewer, GUI Java Decompiler, GUI Bytecode Editor, GUI Smali, GUI Baksmali, GUI APK Editor, GUI Dex Editor, GUI APK Decompiler, GUI DEX Decompiler, GUI Procyon Java Decompiler, GUI Krakatau, GUI CFR Java Decompiler, GUI FernFlower Java Decompiler, GUI DEX2Jar, GUI Jar2DEX, GUI Jar-Jar, Hex Viewer, Code Searcher, Debugger and more.
It's written completely in Java, and it's open sourced. It's currently being maintained and developed by Konloch.
Bytecode Viewer - a lightweight user friendly Java Bytecode Viewer.
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 execute the plugin with a ClassNode ArrayList of every single class loaded in BCV, this allows the user to handle it completely using ASM.
Code from various projects has been used, including but not limited to:
* J-RET by WaterWolf
* JHexPane by Sam Koivu
* RSynaxPane by Robert Futrell
* Commons IO by Apache
* ASM by OW2
* FernFlower by Stiver
* Procyon by Mstrobel
* CFR by Lee Benfield
* CFIDE by Bibl
* Smali by JesusFreke
* Dex2Jar by pxb1..?
* Krakatau by Storyyeller
* JD GUI/JD Core by The Java-Decompiler Team
* Enjarify by Storyyeller
Contributors:
* Konloch
* Bibl
* Fluke
* Righteous
* sahitya-pavurala
* priav03
* Afffsdd
* Szperak
* Zooty
* samczsun
* ItzSomebody
* If I missed you, please feel free to contact me @Konloch or konloch@gmail.com
#### New Features
* Fixed APK & dex loading
* Fixed Java 10+ classfiles
* Better visual feedback due to the new busy icon system
* Synchronized viewing pane option & quick method selection
* Tons of bug fixes and general improvements
* Updated most libraries to their 2019 versions (still a WIP)
Website: https://bytecodeviewer.com
Source Code: https://github.com/konloch/bytecode-viewer
Bin/Archive: https://github.com/konloch/bytecode-viewer/releases
Java Docs: https://the.bytecode.club/docs/bytecode-viewer/
License (Copyleft): https://raw.githubusercontent.com/Konloch/bytecode-viewer/master/LICENSE
Report Bugs (or below): https://github.com/Konloch/bytecode-viewer/issues
Credits: https://github.com/Konloch/bytecode-viewer/blob/master/CREDITS.md
Contributing: https://github.com/Konloch/bytecode-viewer/blob/master/CONTRIBUTING.md
Report Bugs: https://github.com/Konloch/bytecode-viewer/issues
Discussion Forum: https://the.bytecode.club/forumdisplay.php?fid=69
Key Features:
#### Key Features
* Krakatau Integration for Bytecode assembly/disassembly.
* Smali/BakSmali Integration - You can now edit class files/dex files via smali!
* APK/DEX Support - Using Dex2Jar and Jar2Dex it's able to load and save APKs with ease!
* Java Decompiler - It utilizes FernFlower, Procyon and CFR for decompilation.
* Java Decompiler - It utilizes FernFlower, Procyon, CFR, and JD for decompilation.
* Bytecode Decompiler - A modified version of CFIDE's.
* Hex Viewer - Powered by JHexPane.
* Each Decompiler/Editor/Viewer is toggleable, you can also select what will display on each pane.
@ -65,7 +35,7 @@ Key Features:
* Recent Files & Recent Plugins.
* And more! Give it a try for yourself!
Command Line Input:
#### Command Line Input
```
-help Displays the help menu
-list Displays the available decompilers
@ -76,8 +46,19 @@ Command Line Input:
-nowait Doesn't wait for the user to read the CLI messages
```
Are you a Java Reverse Engineer? Do you want to learn?
## What is Bytecode Viewer?
Bytecode Viewer (BCV) is an Advanced Lightweight Java Bytecode Viewer, GUI Java Decompiler, GUI Bytecode Editor, GUI Smali, GUI Baksmali, GUI APK Editor, GUI Dex Editor, GUI APK Decompiler, GUI DEX Decompiler, GUI Procyon Java Decompiler, GUI Krakatau, GUI CFR Java Decompiler, GUI FernFlower Java Decompiler, GUI DEX2Jar, GUI Jar2DEX, GUI Jar-Jar, Hex Viewer, Code Searcher, Debugger and more.
It's written completely in Java, and it's open sourced. It's currently being maintained and developed by Konloch.
Join The Bytecode Club Today!
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 execute the plugin with a ClassNode ArrayList of every single class loaded in BCV, this allows the user to handle it completely using ASM.
https://the.bytecode.club
## How do I install BCV?
Download the latest version from https://github.com/konloch/bytecode-viewer/releases and run the Bytecode-Viewer-2.9.x.jar.
You may need to execute it via command line ```java -jar Bytecode-Viewer-2.9.x.jar``` (replace the X with the current minor version)
## How do I use BCV?
All you have to do is add a jar, class or APK file into the workspace. Then select the file you'd like to view from the workspace. BCV will automatically 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 (depending on the View panes you have selected). If you are trying to view a resource BCV will attempt to display it the best it can with code highlighting or by embedding the resources itself.
##### Are you a Java Reverse Engineer? Do you want to learn?
Join The Bytecode Club Today! - https://the.bytecode.club

BIN
libs/commons-cli-1.4.jar Normal file

Binary file not shown.

BIN
libs/commons-codec-1.12.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,11 +0,0 @@
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.

BIN
src/Krakatau-12.zip Normal file

Binary file not shown.

29
src/LICENSES/ASM.txt Normal file
View File

@ -0,0 +1,29 @@
Copyright (c) 2000-2011 INRIA, France Telecom
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. Neither the name of the copyright holders 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.

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

638
src/LICENSES/BCV.txt Normal file
View File

@ -0,0 +1,638 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
Bytecode Viewer - Java & Android Reverse Engineering Suite
Copyright (C) 2014 Kalen "Konloch" Kinloch - http://bytecodeviewer.com - http://the.bytecode.club
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 <http://www.gnu.org/licenses/>.

View File

@ -0,0 +1 @@
NONE WHAT THE FUCK BIBL > https://github.com/TheBiblMan/Byte-Engineer-2

21
src/LICENSES/CFR.txt Normal file
View File

@ -0,0 +1,21 @@
Sourced from The MIT License (MIT)
Copyright (c) 2011-2014 Lee Benfield - http://www.benf.org/other/cfr
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

676
src/LICENSES/JD.txt Normal file
View File

@ -0,0 +1,676 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
JD-GUI, a standalone graphical utility that displays Java sources from
CLASS files
Copyright (C) 2008-2015 Emmanuel Dupuy
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 <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
JD-GUI Copyright (C) 2008-2015 Emmanuel Dupuy
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

24
src/LICENSES/JGraphX.txt Normal file
View File

@ -0,0 +1,24 @@
Copyright (c) 2001-2014, JGraph Ltd
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 the JGraph 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 JGRAPH 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.

30
src/LICENSES/Janino.txt Normal file
View File

@ -0,0 +1,30 @@
Janino - An embedded Java[TM] compiler
Copyright (c) 2001-2007, Arno Unkrig
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.

View File

@ -0,0 +1,24 @@
Copyright (c) 2012, Robert Futrell
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 the author 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 <COPYRIGHT HOLDER> 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.

12
src/LICENSES/license.txt Normal file
View File

@ -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

85
src/LICENSES/smali.txt Normal file
View File

@ -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.
*******************************************************************************

View File

@ -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

BIN
src/enjarify-4.zip Normal file

Binary file not shown.

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 <code>AlreadySelectedException</code>
* with the specified detail message.
*
* @param message the detail message
*/
public AlreadySelectedException(String message) {
super(message);
}
/**
* Construct a new <code>AlreadySelectedException</code>
* 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;
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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<String> matchingOptions;
/**
* Constructs a new AmbiguousOptionException.
*
* @param option the partial option name
* @param matchingOptions the options matching the name
*/
public AmbiguousOptionException(String option, Collection<String> 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<String> 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<String> matchingOptions) {
StringBuilder buf = new StringBuilder("Ambiguous option: '");
buf.append(option);
buf.append("' (could be: ");
Iterator<String> it = matchingOptions.iterator();
while (it.hasNext()) {
buf.append("'");
buf.append(it.next());
buf.append("'");
if (it.hasNext()) {
buf.append(", ");
}
}
buf.append(")");
return buf.toString();
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 {
/**
* <p>A simple implementation of {@link Parser}'s abstract
* {@link Parser#flatten(Options, String[], boolean) flatten} method.</p>
*
* <p><b>Note:</b> <code>options</code> and <code>stopAtNonOption</code>
* are not used in this <code>flatten</code> method.</p>
*
* @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 <code>arguments</code> String array.
*/
@Override
protected String[] flatten(@SuppressWarnings("unused") Options options,
String[] arguments,
@SuppressWarnings("unused") boolean stopAtNonOption) {
// just echo the arguments
return arguments;
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
* <p>
* It allows querying of a boolean {@link #hasOption(String opt)},
* in addition to retrieving the {@link #getOptionValue(String opt)}
* for options requiring arguments.
* <p>
* 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<String> args = new LinkedList<String>();
/** the processed options */
private final List<Option> options = new ArrayList<Option>();
/**
* 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 <code>Object</code> type of this <code>Option</code>.
*
* @param opt the name of the option
* @return the type of this <code>Option</code>
* @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 <code>Option</code> 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 <code>Object</code> type of this <code>Option</code>.
*
* @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<String> values = new ArrayList<String>();
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 <code>defaultValue</code>.
*/
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 <code>defaultValue</code>.
*/
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 <tt>-Dparam1=value1
* -Dparam2=value2</tt>. The first argument of the option is the key, and
* the 2nd argument is the value. If the option has only one argument
* (<tt>-Dfoo</tt>) it is considered as a boolean flag and the value is
* <tt>"true"</tt>.
*
* @param opt name of the option
* @return The Properties mapped by the option, never <tt>null</tt>
* 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<String> 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 <code>List</code>.
*/
public List<String> getArgList() {
return args;
}
/**
* jkeyes
* - commented out until it is implemented properly
* <p>Dump state, suitable for debugging.</p>
*
* @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 <code>Iterator</code> over the processed {@link Option}
* members of this {@link CommandLine}
*/
public Iterator<Option> 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<Option> processed = options;
// reinitialise array
Option[] optionsArray = new Option[processed.size()];
// return the array
return processed.toArray(optionsArray);
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 <code>CommandLineParser</code> 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 <tt>true</tt> an unrecognized argument stops
* the parsing and the remaining arguments are added to the
* {@link CommandLine}s args list. If <tt>false</tt> 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 <tt>true</tt> an unrecognized argument stops
* the parsing and the remaining arguments are added to the
* {@link CommandLine}s args list. If <tt>false</tt> 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;
*/
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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. <tt>true</tt> to stop
* the parsing and add the remaining tokens to the args list.
* <tt>false</tt> 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 <tt>true</tt> an unrecognized argument stops
* the parsing and the remaining arguments are added to the
* {@link CommandLine}s args list. If <tt>false</tt> 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 <code>properties</code>.
*
* @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<String> 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<String> 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 <code>token</code> into its constituent parts
* using the following algorithm.
*
* <ul>
* <li>ignore the first character ("<b>-</b>")</li>
* <li>foreach remaining character check if an {@link Option}
* exists with that id.</li>
* <li>if an {@link Option} does exist then add that character
* prepended with "<b>-</b>" to the list of processed tokens.</li>
* <li>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.</li>
* <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b>
* <code>stopAtNonOption</code> <b>IS</b> set then add the special token
* "<b>--</b>" followed by the remaining characters and also
* the remaining tokens directly to the processed tokens list.</li>
* <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b>
* <code>stopAtNonOption</code> <b>IS NOT</b> set then add that
* character prepended with "<b>-</b>".</li>
* </ul>
*
* @param token The current token to be <b>burst</b>
* 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;
}
}
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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:
* <ol>
* <li>If an {@link Option} exists for the first character of
* the <code>arguments</code> entry <b>AND</b> an {@link Option}
* does not exist for the whole <code>argument</code> 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.</li>
* <li>Otherwise just add the token to the processed tokens list.</li>
* </ol>
*
* @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<String> tokens = new ArrayList<String>();
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()]);
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
*
* <p>Example:</p>
*
* <pre>
* 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);
* </pre>
*
* This produces the following output:
*
* <pre>
* usage: myapp -f &lt;FILE&gt; [-h] [-v]
* Do something useful with an input file
*
* -f,--file &lt;FILE&gt; The file to be processed
* -h,--help
* -v,--version Print the version of the application
*
* Please report issues at http://example.com/issues
* </pre>
*
* @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<Option> 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<Option> 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<Option> comparator) {
this.optionComparator = comparator;
}
/**
* Print the help for <code>options</code> 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 <code>options</code> 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 <code>options</code> 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 <code>options</code> 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 <code>options</code> 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 <code>options</code> 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 <code>options</code> 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 <code>options</code> 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<OptionGroup> processedGroups = new ArrayList<OptionGroup>();
List<Option> optList = new ArrayList<Option>(options.getOptions());
if (getOptionComparator() != null) {
Collections.sort(optList, getOptionComparator());
}
// iterate over the options
for (Iterator<Option> 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<Option> optList = new ArrayList<Option>(group.getOptions());
if (getOptionComparator() != null) {
Collections.sort(optList, getOptionComparator());
}
// for each option in the OptionGroup
for (Iterator<Option> 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 <lpad>-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<StringBuffer> prefixList = new ArrayList<StringBuffer>();
List<Option> 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<Option> 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 <code>startPos</code> for the
* text in <code>text</code> with the column width <code>width</code>.
* 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 <code>len</code>.
*
* @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 <code>Comparator</code> interface
* for comparing Options.
*/
private static class OptionComparator implements Comparator<Option>, 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());
}
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 <code>MissingArgumentException</code>
* with the specified detail message.
*
* @param message the detail message
*/
public MissingArgumentException(String message) {
super(message);
}
/**
* Construct a new <code>MissingArgumentException</code>
* 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;
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 <code>MissingSelectedException</code>
* with the specified detail message.
*
* @param message the detail message
*/
public MissingOptionException(String message) {
super(message);
}
/**
* Constructs a new <code>MissingSelectedException</code> 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();
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
* <p>
* 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.
* <p>
* <b>Note:</b> 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<String> values = new ArrayList<String>();
/** 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 <code>opt</code>.
*/
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 <code>opt</code>.
*/
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 <code>opt</code>.
*/
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.
* <p>
* <b>Note:</b> 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
* <code>null</code> if there is no value.
*
* @return the value/first value of this Option or
* <code>null</code> if there is no value.
*/
public String getValue() {
return hasNoValues() ? null : values.get(0);
}
/**
* Returns the specified value of this Option or
* <code>null</code> if there is no value.
*
* @param index The index of the value to be returned.
*
* @return the specified value of this Option or
* <code>null</code> 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
* <code>defaultValue</code> 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
* <code>defaultValue</code> 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<String> 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<String>(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: <a href="https://issues.apache.org/jira/browse/CLI-71">CLI-71</a>
*/
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 <code>Option</code> instances
* using descriptive methods.
* <p>
* Example usage:
* <pre>
* Option option = Option.builder("a")
* .required(true)
* .longOpt("arg-name")
* .build();
* </pre>
*
* @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 <code>Builder</code> with the minimum
* required parameters for an <code>Option</code> 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 <code>sep</code> as a means to
* separate argument values.
* <p>
* <b>Example:</b>
* <pre>
* 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"
* </pre>
*
* @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);
}
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
* <p>
* Details on the Builder pattern can be found at
* <a href="http://c2.com/cgi-bin/wiki?BuilderPattern">http://c2.com/cgi-bin/wiki?BuilderPattern</a>.
* <p>
* This class is NOT thread safe. See <a href="https://issues.apache.org/jira/browse/CLI-209">CLI-209</a>
*
* @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
* <code>hasArg</code> 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 <code>sep</code> as a means to
* separate argument values.
* <p>
* <b>Example:</b>
* <pre>
* 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"
* </pre>
*
* @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 '<code>=</code>' as a means to
* separate argument values.
*
* <b>Example:</b>
* <pre>
* Option opt = OptionBuilder.withValueSeparator()
* .create('D');
*
* CommandLine line = parser.parse(args);
* String propertyName = opt.getValue(0);
* String propertyValue = opt.getValue(1);
* </pre>
*
* @return the OptionBuilder instance
*/
public static OptionBuilder withValueSeparator() {
OptionBuilder.valuesep = '=';
return INSTANCE;
}
/**
* The next Option created will be required if <code>required</code>
* 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 <code>num</code> 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 <code>type</code>.
* <p>
* <b>Note:</b> 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 <code>type</code>.
*
* @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 <code>char</code>.
*
* @param opt the character representation of the Option
* @return the Option instance
* @throws IllegalArgumentException if <code>opt</code> 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 <code>longOpt</code> 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 <code>char</code>.
*
* @param opt the <code>java.lang.String</code> representation
* of the Option
* @return the Option instance
* @throws IllegalArgumentException if <code>opt</code> 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;
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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<String, Option> optionMap = new HashMap<String, Option>();
/** the name of the selected option */
private String selected;
/** specified whether this group is required */
private boolean required;
/**
* Add the specified <code>Option</code> 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
* <code>Collection</code>
*/
public Collection<String> getNames() {
// the key set is the collection of names
return optionMap.keySet();
}
/**
* @return the options in this group as a <code>Collection</code>
*/
public Collection<Option> getOptions() {
// the values are the collection of options
return optionMap.values();
}
/**
* Set the selected option of this group to <code>name</code>.
*
* @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<Option> 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();
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 <code>opt</code> is a permissible Option
* shortOpt. The rules that specify if the <code>opt</code>
* is valid are:
*
* <ul>
* <li>a single character <code>opt</code> that is either
* ' '(special case), '?', '@' or a letter</li>
* <li>a multi character <code>opt</code> that only contains
* letters.</li>
* </ul>
* <p>
* 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 <code>c</code> 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 <code>c</code> is a letter.
*/
private static boolean isValidChar(char c) {
return Character.isJavaIdentifierPart(c);
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
* <p>
* Options represents a collection of {@link Option} objects, which
* describe the possible options for a command-line.
* <p>
* 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<String, Option> shortOpts = new LinkedHashMap<String, Option>();
/** a map of the options with the long key */
private final Map<String, Option> longOpts = new LinkedHashMap<String, Option>();
/** 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<Object> requiredOpts = new ArrayList<Object>();
/** a map of the option groups */
private final Map<String, OptionGroup> optionGroups = new HashMap<String, OptionGroup>();
/**
* 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<OptionGroup> getOptionGroups() {
return new HashSet<OptionGroup>(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<Option> getOptions() {
return Collections.unmodifiableCollection(helpOptions());
}
/**
* Returns the Options for use by the HelpFormatter.
*
* @return the List of Options
*/
List<Option> helpOptions() {
return new ArrayList<Option>(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<String> getMatchingOptions(String opt) {
opt = Util.stripLeadingHyphens(opt);
List<String> matchingOpts = new ArrayList<String>();
// 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 <code>opt</code> belongs to.
* @param opt the option whose OptionGroup is being queried.
*
* @return the OptionGroup if <code>opt</code> 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();
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 <code>ParseException</code>
* with the specified detail message.
*
* @param message the detail message
*/
public ParseException(String message) {
super(message);
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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;
/**
* <code>Parser</code> 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 <code>arguments</code> 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 <code>arguments</code> based
* on the specified {@link Options}.
*
* @param options the <code>Options</code>
* @param arguments the <code>arguments</code>
* @return the <code>CommandLine</code>
* @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 <code>arguments</code>
* based on the specified {@link Options}.
*
* @param options the <code>Options</code>
* @param arguments the <code>arguments</code>
* @param stopAtNonOption if <tt>true</tt> an unrecognized argument stops
* the parsing and the remaining arguments are added to the
* {@link CommandLine}s args list. If <tt>false</tt> an unrecognized
* argument triggers a ParseException.
* @return the <code>CommandLine</code>
* @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 <tt>true</tt> an unrecognized argument stops
* the parsing and the remaining arguments are added to the
* {@link CommandLine}s args list. If <tt>false</tt> 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<String> tokenList = Arrays.asList(flatten(getOptions(), arguments, stopAtNonOption));
ListIterator<String> 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 <code>properties</code>.
*
* @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
* <code>opt</code> using the values retrieved from the
* specified iterator <code>iter</code>.
*
* @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<String> 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 <code>arg</code> using the values
* retrieved from the specified iterator <code>iter</code>.
*
* @param arg The String value representing an Option
* @param iter The iterator over the flattened command line arguments.
*
* @throws ParseException if <code>arg</code> does not represent an Option
*/
protected void processOption(String arg, ListIterator<String> 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);
}
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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;
/**
* <p>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.
* </p>
*
* <table border="1">
* <caption>Overview of PatternOptionBuilder patterns</caption>
* <tr><td>a</td><td>-a flag</td></tr>
* <tr><td>b@</td><td>-b [classname]</td></tr>
* <tr><td>c&gt;</td><td>-c [filename]</td></tr>
* <tr><td>d+</td><td>-d [classname] (creates object via empty constructor)</td></tr>
* <tr><td>e%</td><td>-e [number] (creates Double/Long instance depending on existing of a '.')</td></tr>
* <tr><td>f/</td><td>-f [url]</td></tr>
* <tr><td>g:</td><td>-g [string]</td></tr>
* </table>
*
* <p>
* For example, the following allows command line flags of '-v -p string-value -f /dir/file'.
* The exclamation mark precede a mandatory option.
* </p>
*
* <pre>
* Options options = PatternOptionBuilder.parsePattern("vp:!f/");
* </pre>
*
* <p>
* TODO: These need to break out to OptionType and also to be pluggable.
* </p>
*
* @version $Id: PatternOptionBuilder.java 1677406 2015-05-03 14:27:31Z britter $
*/
public class PatternOptionBuilder {
/** String class */
public static final Class<String> STRING_VALUE = String.class;
/** Object class */
public static final Class<Object> OBJECT_VALUE = Object.class;
/** Number class */
public static final Class<Number> NUMBER_VALUE = Number.class;
/** Date class */
public static final Class<Date> 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<FileInputStream> EXISTING_FILE_VALUE = FileInputStream.class;
/** File class */
public static final Class<File> FILE_VALUE = File.class;
/** File array class */
public static final Class<File[]> FILES_VALUE = File[].class;
/** URL class */
public static final Class<URL> URL_VALUE = URL.class;
/**
* Retrieve the class that <code>ch</code> represents.
*
* @param ch the specified character
* @return The class that <code>ch</code> 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 <code>ch</code> is a value code, i.e.
* whether it represents a class in a pattern.
*
* @param ch the specified character
* @return true if <code>ch</code> 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 <code>pattern</code>.
*
* @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;
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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<String> tokens = new ArrayList<String>();
/** 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 <code>tokens</code> entries and set <code>eatTheRest</code>
* to false.
*/
private void init() {
eatTheRest = false;
tokens.clear();
}
/**
* <p>An implementation of {@link Parser}'s abstract
* {@link Parser#flatten(Options, String[], boolean) flatten} method.</p>
*
* <p>The following are the rules used by this flatten method.</p>
* <ol>
* <li>if <code>stopAtNonOption</code> is <b>true</b> then do not
* burst anymore of <code>arguments</code> entries, just add each
* successive entry without further processing. Otherwise, ignore
* <code>stopAtNonOption</code>.</li>
* <li>if the current <code>arguments</code> entry is "<b>--</b>"
* just add the entry to the list of processed tokens</li>
* <li>if the current <code>arguments</code> entry is "<b>-</b>"
* just add the entry to the list of processed tokens</li>
* <li>if the current <code>arguments</code> entry is two characters
* in length and the first character is "<b>-</b>" 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 <code>stopAtNonOption</code>
* is true, then the remaining entries are copied to the list of
* processed tokens. Otherwise, the current entry is ignored.</li>
* <li>if the current <code>arguments</code> entry is more than two
* characters in length and the first character is "<b>-</b>" 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}.</li>
* <li>if the current <code>arguments</code> entry is not handled
* by any of the previous rules, then the entry is added to the list
* of processed tokens.</li>
* </ol>
*
* @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 <code>arguments</code> 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<String> 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<String> 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<String> 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<String> iter) {
if (eatTheRest) {
while (iter.hasNext()) {
tokens.add(iter.next());
}
}
}
/**
* Add the special token "<b>--</b>" and the current <code>value</code>
* to the processed tokens list. Then add all the remaining
* <code>argument</code> 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);
}
/**
* <p>If an {@link Option} exists for <code>token</code> then
* add the token to the processed list.</p>
*
* <p>If an {@link Option} does not exist and <code>stopAtNonOption</code>
* is set then add the remaining tokens to the processed tokens list
* directly.</p>
*
* @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 <code>token</code> into its constituent parts
* using the following algorithm.
*
* <ul>
* <li>ignore the first character ("<b>-</b>")</li>
* <li>foreach remaining character check if an {@link Option}
* exists with that id.</li>
* <li>if an {@link Option} does exist then add that character
* prepended with "<b>-</b>" to the list of processed tokens.</li>
* <li>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.</li>
* <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b>
* <code>stopAtNonOption</code> <b>IS</b> set then add the special token
* "<b>--</b>" followed by the remaining characters and also
* the remaining tokens directly to the processed tokens list.</li>
* <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b>
* <code>stopAtNonOption</code> <b>IS NOT</b> set then add that
* character prepended with "<b>-</b>".</li>
* </ul>
*
* @param token The current token to be <b>burst</b>
* @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;
}
}
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 <code>Object</code> of type <code>obj</code>
* with the value of <code>str</code>.
*
* @param str the command line value
* @param obj the type of argument
* @return The instance of <code>obj</code> initialised with
* the value of <code>str</code>.
* @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 <code>Object</code> of type <code>clazz</code>
* with the value of <code>str</code>.
*
* @param str the command line value
* @param clazz the type of argument
* @return The instance of <code>clazz</code> initialised with
* the value of <code>str</code>.
* @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 <code>str</code>
* @throws ParseException if <code>str</code> 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 <code>classname</code>.
*
* @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 <code>str</code>.
* <p>
* This method is not yet implemented and always throws an
* {@link UnsupportedOperationException}.
*
* @param str the date string
* @return The date if <code>str</code> 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 <code>str</code>.
*
* @param str the URL string
* @return The URL in <code>str</code> is well-formed
* @throws ParseException if the URL in <code>str</code> 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 <code>str</code>.
*
* @param str the File location
* @return The file represented by <code>str</code>.
*/
public static File createFile(String str) {
return new File(str);
}
/**
* Returns the File[] represented by <code>str</code>.
* <p>
* This method is not yet implemented and always throws an
* {@link UnsupportedOperationException}.
*
* @param str the paths to the files
* @return The File[] represented by <code>str</code>.
* @throws UnsupportedOperationException always
*/
public static File[] createFiles(String str) {
// to implement/port:
// return FileW.findFiles(str);
throw new UnsupportedOperationException("Not yet implemented");
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 <code>UnrecognizedArgumentException</code>
* with the specified detail message.
*
* @param message the detail message
*/
public UnrecognizedOptionException(String message) {
super(message);
}
/**
* Construct a new <code>UnrecognizedArgumentException</code>
* 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;
}
}

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 <code>str</code> 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 <code>str</code>.
* 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;
}
}

View File

@ -1,43 +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.
-->
<body>
<p>Commons CLI -- version 1.3</p>
<p>The commons-cli package aides in parsing command-line arguments.</p>
<p>Allow command-line arguments to be parsed against a descriptor of
valid options (long and short), potentially with arguments.</p>
<p>command-line arguments may be of the typical <code>String[]</code>
form, but also may be a <code>java.util.List</code>. 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:
<code>
<pre>
myApp -p &lt;port&gt; command -p &lt;printer&gt;
</pre>
</code>
<p>The homepage for the project is
<a href="http://commons.apache.org">Apache Commons/</a>
</body>

View File

@ -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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
* <p>
* 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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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.
* <p>
* From the Java documentation <a
* href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>:
* <p>
* <cite>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.</cite>
* </p>
* <p>
* <ul>
* <li><code>US-ASCII</code><br>
* Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.</li>
* <li><code>ISO-8859-1</code><br>
* ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.</li>
* <li><code>UTF-8</code><br>
* Eight-bit Unicode Transformation Format.</li>
* <li><code>UTF-16BE</code><br>
* Sixteen-bit Unicode Transformation Format, big-endian byte order.</li>
* <li><code>UTF-16LE</code><br>
* Sixteen-bit Unicode Transformation Format, little-endian byte order.</li>
* <li><code>UTF-16</code><br>
* 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.)</li>
* </ul>
* <p>
* 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].
* <p>
* <p>
* This class is immutable and thread-safe.
* </p>
*
* @version $Id$
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @since 1.4
*/
public class CharEncoding {
/**
* CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
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.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
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)
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final String UTF_16 = "UTF-16";
/**
* Sixteen-bit Unicode Transformation Format, big-endian byte order.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final String UTF_16BE = "UTF-16BE";
/**
* Sixteen-bit Unicode Transformation Format, little-endian byte order.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final String UTF_16LE = "UTF-16LE";
/**
* Eight-bit Unicode Transformation Format.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final String UTF_8 = "UTF-8";
}

View File

@ -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.
* <p>
* From the Java documentation <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard
* charsets</a>:
* <p>
* <cite>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. </cite>
* </p>
* <p>
* <ul>
* <li><code>US-ASCII</code><br>
* Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.</li>
* <li><code>ISO-8859-1</code><br>
* ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.</li>
* <li><code>UTF-8</code><br>
* Eight-bit Unicode Transformation Format.</li>
* <li><code>UTF-16BE</code><br>
* Sixteen-bit Unicode Transformation Format, big-endian byte order.</li>
* <li><code>UTF-16LE</code><br>
* Sixteen-bit Unicode Transformation Format, little-endian byte order.</li>
* <li><code>UTF-16</code><br>
* 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.)</li>
* </ul>
* <p>
* 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.
* <p>
* <p>
* This class is immutable and thread-safe.
* </p>
*
* @version $Id: CharEncoding.java 1173287 2011-09-20 18:16:19Z ggregory $
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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)
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
*
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets#UTF_8}
*/
@Deprecated
public static final Charset UTF_8 = Charset.forName(CharEncoding.UTF_8);
}

View File

@ -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.
* <p>
* 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.
* <p>
* 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;
}

View File

@ -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 <a href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always Declare Serial Version Uid</a>
*/
private static final long serialVersionUID = 1L;
/**
* Constructs a new exception with <code>null</code> 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.
* <p>
* Note that the detail message associated with <code>cause</code> 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 <code>null</code>
* 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 <code>(cause==null ?
* null : cause.toString())</code> (which typically contains the class and detail message of <code>cause</code>).
* 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 <code>null</code>
* value is permitted, and indicates that the cause is nonexistent or unknown.
* @since 1.4
*/
public DecoderException(final Throwable cause) {
super(cause);
}
}

View File

@ -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.
* <p>
* 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
* <code>byte[]</code> or <code>String</code>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;
}

View File

@ -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 <a href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always Declare Serial Version Uid</a>
*/
private static final long serialVersionUID = 1L;
/**
* Constructs a new exception with <code>null</code> 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.
* <p>
* <p>
* Note that the detail message associated with <code>cause</code> is not automatically incorporated into this
* exception's detail message.
* </p>
*
* @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 <code>null</code>
* 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 <code>(cause==null ?
* null : cause.toString())</code> (which typically contains the class and detail message of <code>cause</code>).
* 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 <code>null</code>
* value is permitted, and indicates that the cause is nonexistent or unknown.
* @since 1.4
*/
public EncoderException(final Throwable cause) {
super(cause);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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.
* <p>
* <p>This class is immutable and thread-safe.</p>
*
* @version $Id$
*/
@SuppressWarnings("rawtypes")
// TODO ought to implement Comparator<String> 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.
* <p>
* If an {@link EncoderException} is encountered, return <code>0</code>.
*
* @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<Comparable<?>> s1 = (Comparable<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;
}
}

View File

@ -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 <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a>.
* <p>
* <p>
* The class can be parameterized in the following manner with various constructors:
* </p>
* <ul>
* <li>Whether to use the "base32hex" variant instead of the default "base32"</li>
* <li>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.
* <li>Line separator: Default is CRLF ("\r\n")</li>
* </ul>
* <p>
* This class operates directly on byte streams, and not character streams.
* </p>
* <p>
* This class is thread-safe.
* </p>
*
* @version $Id$
* @see <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a>
* @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 <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
*/
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.
* <code>decodeSize = {@link #BYTES_PER_ENCODED_BLOCK} - 1 + lineSeparator.length;</code>
*/
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.
* <code>encodeSize = {@link #BYTES_PER_ENCODED_BLOCK} + lineSeparator.length;</code>
*/
private final int encodeSize;
/**
* Encode table to use.
*/
private final byte[] encodeTable;
/**
* Line separator for encoding. Not used when decoding. Only used if lineLength &gt; 0.
*/
private final byte[] lineSeparator;
/**
* Creates a Base32 codec used for decoding and encoding.
* <p>
* When encoding the line length is 0 (no chunking).
* </p>
*/
public Base32() {
this(false);
}
/**
* Creates a Base32 codec used for decoding and encoding.
* <p>
* When encoding the line length is 0 (no chunking).
* </p>
*
* @param pad byte used as padding byte.
*/
public Base32(final byte pad) {
this(false, pad);
}
/**
* Creates a Base32 codec used for decoding and encoding.
* <p>
* When encoding the line length is 0 (no chunking).
* </p>
*
* @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.
* <p>
* When encoding the line length is 0 (no chunking).
* </p>
*
* @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.
* <p>
* When encoding the line length is given in the constructor, the line separator is CRLF.
* </p>
*
* @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
* 8). If lineLength &lt;= 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.
* <p>
* When encoding the line length and line separator are given in the constructor.
* </p>
* <p>
* Line lengths that aren't multiples of 8 will still essentially end up being multiples of 8 in the encoded data.
* </p>
*
* @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
* 8). If lineLength &lt;= 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.
* <p>
* When encoding the line length and line separator are given in the constructor.
* </p>
* <p>
* Line lengths that aren't multiples of 8 will still essentially end up being multiples of 8 in the encoded data.
* </p>
*
* @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
* 8). If lineLength &lt;= 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 &gt; 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.
* <p>
* When encoding the line length and line separator are given in the constructor.
* </p>
* <p>
* Line lengths that aren't multiples of 8 will still essentially end up being multiples of 8 in the encoded data.
* </p>
*
* @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
* 8). If lineLength &lt;= 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 &gt; 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");
}
}
/**
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*
* @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
* <p>
* 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);
}
}
}
/**
* <p>
* 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).
* </p>
*
* @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;
}
}

View File

@ -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.
* <p>
* 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.
* </p>
* <p>
* 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).
* </p>
*
* @version $Id$
* @see <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a>
* @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 &lt;= 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 &lt;= 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);
}
}

View File

@ -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.
* <p>
* 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.
* </p>
* <p>
* 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).
* </p>
* <p>
* <b>Note:</b> 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.
* </p>
*
* @version $Id$
* @see <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a>
* @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 &lt;= 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 &lt;= 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);
}
}

View File

@ -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 <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
* <p>
* <p>
* This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose
* Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and Borenstein.
* </p>
* <p>
* The class can be parameterized in the following manner with various constructors:
* </p>
* <ul>
* <li>URL-safe mode: Default off.</li>
* <li>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.
* <li>Line separator: Default is CRLF ("\r\n")</li>
* </ul>
* <p>
* The URL-safe parameter is only applied to encode operations. Decoding seamlessly handles both modes.
* </p>
* <p>
* 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).
* </p>
* <p>
* This class is thread-safe.
* </p>
*
* @version $Id$
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
* @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.
* <p>
* <p>
* N.B. The next major release may break compatibility and make this field private.
* </p>
*
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
*/
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.
* <p>
* 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.
* <p>
* 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).
* <p>
* 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 &gt; 0.
*/
private final byte[] lineSeparator;
/**
* Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
* <code>decodeSize = 3 + lineSeparator.length;</code>
*/
private final int decodeSize;
/**
* Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
* <code>encodeSize = 4 + lineSeparator.length;</code>
*/
private final int encodeSize;
/**
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
* <p>
* When encoding the line length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE.
* </p>
* <p>
* <p>
* When decoding all variants are supported.
* </p>
*/
public Base64() {
this(0);
}
/**
* Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode.
* <p>
* When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE.
* </p>
* <p>
* <p>
* When decoding all variants are supported.
* </p>
*
* @param urlSafe if <code>true</code>, URL-safe encoding is used. In most cases this should be set to
* <code>false</code>.
* @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.
* <p>
* When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is
* STANDARD_ENCODE_TABLE.
* </p>
* <p>
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
* </p>
* <p>
* When decoding all variants are supported.
* </p>
*
* @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
* 4). If lineLength &lt;= 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.
* <p>
* When encoding the line length and line separator are given in the constructor, and the encoding table is
* STANDARD_ENCODE_TABLE.
* </p>
* <p>
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
* </p>
* <p>
* When decoding all variants are supported.
* </p>
*
* @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
* 4). If lineLength &lt;= 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.
* <p>
* When encoding the line length and line separator are given in the constructor, and the encoding table is
* STANDARD_ENCODE_TABLE.
* </p>
* <p>
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
* </p>
* <p>
* When decoding all variants are supported.
* </p>
*
* @param lineLength Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
* 4). If lineLength &lt;= 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.
* <b>Note: no padding is added when using the URL-safe alphabet.</b>
* @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;
}
/**
* <p>
* 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).
* </p>
* <p><b>Note: no padding is added when encoding using the URL-safe alphabet.</b></p>
* <p>
* 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/
* </p>
*
* @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;
}
}
}
}
}
/**
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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/
* </p>
*
* @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 <code>true</code> if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
* <code>false</code>, 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 <code>octet</code> is in the base 64 alphabet.
*
* @param octet The value to test
* @return <code>true</code> if the value is defined in the the base 64 alphabet, <code>false</code> 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 <code>true</code> if all characters in the String are valid characters in the Base64 alphabet or if
* the String is empty; <code>false</code>, 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 <code>true</code> if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
* <code>false</code>, 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.
* <p>
* 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.
* <b>Note: no padding is added.</b>
*
* @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.
* <b>Note: no padding is added.</b>
*
* @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 <code>true</code> 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 <code>true</code> this encoder will chunk the base64 output into 76 character blocks
* @param urlSafe if <code>true</code> this encoder will emit - and _ instead of the usual + and / characters.
* <b>Note: no padding is added when encoding using the URL-safe alphabet.</b>
* @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 <code>true</code> this encoder will chunk the base64 output into 76 character blocks
* @param urlSafe if <code>true</code> this encoder will emit - and _ instead of the usual + and / characters.
* <b>Note: no padding is added when encoding using the URL-safe alphabet.</b>
* @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.
* <p>
* <b>Note:</b> this method seamlessly handles data encoded in URL-safe or normal mode.
* </p>
*
* @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.
* <p>
* <b>Note:</b> this method seamlessly handles data encoded in URL-safe or normal mode.
* </p>
*
* @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 <code>BigInteger</code> without sign bit.
*
* @param bigInt <code>BigInteger</code> 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 <code>octet</code> is in the Base64 alphabet.
*
* @param octet The value to test
* @return <code>true</code> if the value is defined in the the Base64 alphabet <code>false</code> otherwise.
*/
@Override
protected boolean isInAlphabet(final byte octet) {
return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
}
}

View File

@ -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.
* <p>
* 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.
* </p>
* <p>
* This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose
* Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and Borenstein.
* </p>
* <p>
* 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).
* </p>
*
* @version $Id$
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
* @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 &lt;= 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 &lt;= 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);
}
}

View File

@ -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.
* <p>
* 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.
* </p>
* <p>
* This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose
* Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and Borenstein.
* </p>
* <p>
* 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).
* </p>
* <p>
* <b>Note:</b> 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.
* </p>
*
* @version $Id$
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
* @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 &lt;= 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 &lt;= 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);
}
}

View File

@ -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.
* <p>
* <p>
* This class is thread-safe.
* </p>
*
* @version $Id$
*/
public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
/**
* Holds thread context so classes can be thread-safe.
* <p>
* 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 &gt; 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.
* <p>
* <p>
* The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
* equal signs.
* </p>
*
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a>
*/
public static final int MIME_CHUNK_SIZE = 76;
/**
* PEM chunk size per RFC 1421 section 4.3.2.4.
* <p>
* <p>
* The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
* equal signs.
* </p>
*
* @see <a href="http://tools.ietf.org/html/rfc1421">RFC 1421 section 4.3.2.4</a>
*/
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} &gt; 0.
*/
private final int chunkSeparatorLength;
/**
* Note <code>lineLength</code> is rounded down to the nearest multiple of {@link #encodedBlockSize}
* If <code>chunkSeparatorLength</code> 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 &gt; 0, use chunking with a length <code>lineLength</code>
* @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 <code>lineLength</code> is rounded down to the nearest multiple of {@link #encodedBlockSize}
* If <code>chunkSeparatorLength</code> 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 &gt; 0, use chunking with a length <code>lineLength</code>
* @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 <code>size</code> 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.
* <p>
* 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 <code>octet</code> is in the current alphabet.
* Does not allow whitespace or pad.
*
* @param value The value to test
* @return <code>true</code> if the value is defined in the current alphabet, <code>false</code> 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 <code>true</code>, then whitespace and PAD are also allowed
* @return <code>true</code> if all bytes are valid characters in the alphabet or if the byte array is empty;
* <code>false</code>, 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 <code>true</code> if all characters in the String are valid characters in the alphabet or if
* the String is empty; <code>false</code>, 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.
* <p>
* Intended for use in checking line-ending arrays
*
* @param arrayOctet byte array to test
* @return <code>true</code> if any byte is a valid character in the alphabet or PAD; <code>false</code> 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 &gt; 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;
}
}

View File

@ -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 <code>0</code> if the {@link InputStream} has reached <code>EOF</code>,
* <code>1</code> 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.
* <p>The {@link #mark} method of {@link BaseNCodecInputStream} does nothing.</p>
*
* @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 <code>false</code>
*/
@Override
public boolean markSupported() {
return false; // not an easy job to support marks
}
/**
* Reads one <code>byte</code> 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 <code>len</code> bytes into the specified <code>b</code> array starting at <code>offset</code>
* 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.
* <p>
* 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;
}
}

View File

@ -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.
* <p>
* To write the EOF marker without closing the stream, call {@link #eof()} or use an <a
* href="https://commons.apache.org/proper/commons-io/">Apache Commons IO</a> <a href=
* "https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/output/CloseShieldOutputStream.html"
* >CloseShieldOutputStream</a>.
* </p>
*
* @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 <code>byte</code> 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 <code>len</code> bytes from the specified <code>b</code> array starting at <code>offset</code> 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.
* <p>
* To write the EOF marker without closing the stream, call {@link #eof()} or use an
* <a href="https://commons.apache.org/proper/commons-io/">Apache Commons IO</a> <a href=
* "https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/output/CloseShieldOutputStream.html"
* >CloseShieldOutputStream</a>.
* </p>
*
* @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);
}
}
}

View File

@ -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.
* <p>
* <p>This class is immutable and thread-safe.</p>
* <p>
* 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 <code>true</code> if the given array is <code>null</code> or empty (size 0.)
*
* @param array the source array
* @return <code>true</code> if the given array is <code>null</code> 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));
}
}

View File

@ -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;
/**
* <p>
* Operations on {@link CharSequence} that are <code>null</code> safe.
* </p>
* <p>
* Copied from Apache Commons Lang r1586295 on April 10, 2014 (day of 3.3.2 release).
* </p>
*
* @see CharSequence
* @since 1.10
*/
public class CharSequenceUtils {
/**
* Green implementation of regionMatches.
*
* @param cs the <code>CharSequence</code> to be processed
* @param ignoreCase whether or not to be case insensitive
* @param thisStart the index to start on the <code>cs</code> CharSequence
* @param substring the <code>CharSequence</code> to be looked for
* @param start the index to start on the <code>substring</code> 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;
}
}

View File

@ -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}
* <p>
* 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 <code>true</code> converts to lowercase, <code>false</code> 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 <code>true</code> converts to lowercase, <code>false</code> 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.
* <p>
* The conversion from hexadecimal characters to the returned bytes is performed with the charset named by
* {@link #getCharset()}.
* </p>
*
* @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.
* <p>
* The conversion from hexadecimal characters to the returned bytes is performed with the charset named by
* {@link #getCharset()}.
* </p>
*
* @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.
* <p>
* The conversion from hexadecimal characters to bytes to be encoded to performed with the charset named by
* {@link #getCharset()}.
* </p>
*
* @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 + "]";
}
}

View File

@ -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 <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">
* Standard charsets</a>.
* <p>
* <p>This class is immutable and thread-safe.</p>
*
* @version $Id$
* @see CharEncoding
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @since 1.4
*/
public class StringUtils {
/**
* <p>
* Compares two CharSequences, returning <code>true</code> if they represent equal sequences of characters.
* </p>
* <p>
* <p>
* <code>null</code>s are handled without exceptions. Two <code>null</code> references are considered to be equal.
* The comparison is case sensitive.
* </p>
* <p>
* <pre>
* 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
* </pre>
* <p>
* <p>
* Copied from Apache Commons Lang r1583482 on April 10, 2014 (day of 3.3.2 release).
* </p>
*
* @param cs1 the first CharSequence, may be <code>null</code>
* @param cs2 the second CharSequence, may be <code>null</code>
* @return <code>true</code> if the CharSequences are equal (case-sensitive), or both <code>null</code>
* @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 <code>String</code>
* @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 <code>String</code>
* @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 <code>null</code>
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
* @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 <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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 <code>null</code>
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
* @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 <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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.
* <p>
* 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.
* </p>
*
* @param string the String to encode, may be <code>null</code>
* @param charsetName The name of a required {@link java.nio.charset.Charset}
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
* @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 <code>null</code>
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
* @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 <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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 <code>null</code>
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
* @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 <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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 <code>null</code>
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
* @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 <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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 <code>null</code>
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
* @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 <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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 <code>null</code>
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
* @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 <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @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 <code>String</code> 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 <code>String</code>
* @return A new <code>String</code> decoded from the specified array of bytes using the given charset,
* or <code>null</code> if the input byte array was <code>null</code>.
* @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 <code>String</code> by decoding the specified array of bytes using the given charset.
* <p>
* 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.
* </p>
*
* @param bytes The bytes to be decoded into characters, may be <code>null</code>
* @param charsetName The name of a required {@link java.nio.charset.Charset}
* @return A new <code>String</code> decoded from the specified array of bytes using the given charset,
* or <code>null</code> if the input byte array was <code>null</code>.
* @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 <code>String</code> by decoding the specified array of bytes using the ISO-8859-1 charset.
*
* @param bytes The bytes to be decoded into characters, may be <code>null</code>
* @return A new <code>String</code> decoded from the specified array of bytes using the ISO-8859-1 charset, or
* <code>null</code> if the input byte array was <code>null</code>.
* @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 <code>String</code> by decoding the specified array of bytes using the US-ASCII charset.
*
* @param bytes The bytes to be decoded into characters
* @return A new <code>String</code> decoded from the specified array of bytes using the US-ASCII charset,
* or <code>null</code> if the input byte array was <code>null</code>.
* @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 <code>String</code> by decoding the specified array of bytes using the UTF-16 charset.
*
* @param bytes The bytes to be decoded into characters
* @return A new <code>String</code> decoded from the specified array of bytes using the UTF-16 charset
* or <code>null</code> if the input byte array was <code>null</code>.
* @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 <code>String</code> by decoding the specified array of bytes using the UTF-16BE charset.
*
* @param bytes The bytes to be decoded into characters
* @return A new <code>String</code> decoded from the specified array of bytes using the UTF-16BE charset,
* or <code>null</code> if the input byte array was <code>null</code>.
* @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 <code>String</code> by decoding the specified array of bytes using the UTF-16LE charset.
*
* @param bytes The bytes to be decoded into characters
* @return A new <code>String</code> decoded from the specified array of bytes using the UTF-16LE charset,
* or <code>null</code> if the input byte array was <code>null</code>.
* @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 <code>String</code> by decoding the specified array of bytes using the UTF-8 charset.
*
* @param bytes The bytes to be decoded into characters
* @return A new <code>String</code> decoded from the specified array of bytes using the UTF-8 charset,
* or <code>null</code> if the input byte array was <code>null</code>.
* @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);
}
}

View File

@ -1,21 +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.
-->
<html>
<body>
Base64, Base32, Binary, and Hexadecimal String encoding and decoding.
</body>
</html>

View File

@ -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.
* <p>
* TODO: Can Base64 be reused?
* <p>
* <p>
* This class is immutable and thread-safe.
* </p>
*
* @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();
}
}

View File

@ -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.
* <p>
* See {@link #crypt(String, String)} for further details.
* <p>
* This class is immutable and thread-safe.
*
* @version $Id$
* @since 1.7
*/
public class Crypt {
/**
* Encrypts a password in a crypt(3) compatible way.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* The exact algorithm depends on the format of the salt string:
* <ul>
* <li>SHA-512 salts start with {@code $6$} and are up to 16 chars long.
* <li>SHA-256 salts start with {@code $5$} and are up to 16 chars long
* <li>MD5 salts start with {@code $1$} and are up to 8 chars long
* <li>DES, the traditional UnixCrypt algorithm is used with only 2 chars
* <li>Only the first 8 chars of the passwords are used in the DES algorithm!
* </ul>
* 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.
* <p>
* 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:
* <p>
* <pre>
* storedPwd.equals(crypt(enteredPwd, storedPwd))
* </pre>
* <p>
* 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:
* <ul>
* <li>SHA-512: 106 chars
* <li>SHA-256: 63 chars
* <li>MD5: 34 chars
* <li>DES: 13 chars
* </ul>
* <p>
* Example:
* <p>
* <pre>
* crypt("secret", "$1$xxxx") =&gt; "$1$xxxx$aMkevjfEIpa35Bh3G4bAc."
* crypt("secret", "xx") =&gt; "xxWAum7tHdIUw"
* </pre>
* <p>
* 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);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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 <cite>Java Cryptography Architecture Standard Algorithm Name
* Documentation</cite>.
* <p>
* <p>
* <strong>Note: Not all JCE implementations supports all algorithms in this enum.</strong>
* </p>
*
* @version $Id$
* @see <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html">Java Cryptography
* Architecture Standard Algorithm Name Documentation</a>
* @since 1.10
*/
public enum HmacAlgorithms {
/**
* The HmacMD5 Message Authentication Code (MAC) algorithm specified in RFC 2104 and RFC 1321.
* <p>
* Every implementation of the Java platform is required to support this standard Mac algorithm.
* </p>
*/
HMAC_MD5("HmacMD5"),
/**
* The HmacSHA1 Message Authentication Code (MAC) algorithm specified in RFC 2104 and FIPS PUB 180-2.
* <p>
* Every implementation of the Java platform is required to support this standard Mac algorithm.
* </p>
*/
HMAC_SHA_1("HmacSHA1"),
/**
* The HmacSHA256 Message Authentication Code (MAC) algorithm specified in RFC 2104 and FIPS PUB 180-2.
* <p>
* Every implementation of the Java platform is required to support this standard Mac algorithm.
* </p>
*/
HMAC_SHA_256("HmacSHA256"),
/**
* The HmacSHA384 Message Authentication Code (MAC) algorithm specified in RFC 2104 and FIPS PUB 180-2.
* <p>
* Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
* </p>
*/
HMAC_SHA_384("HmacSHA384"),
/**
* The HmacSHA512 Message Authentication Code (MAC) algorithm specified in RFC 2104 and FIPS PUB 180-2.
* <p>
* Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
* </p>
*/
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 <a
* href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/SunProviders.html#SunJCEProvider">Java
* Cryptography Architecture Sun Providers Documentation</a>
*/
@Override
public String toString() {
return algorithm;
}
}

View File

@ -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.
* <p>
* <p>
* <p>
* <strong>Note: Not all JCE implementations supports all algorithms. If not supported, an IllegalArgumentException is
* thrown.</strong>
* </p>
*
* @version $Id$
* @since 1.10
*/
public final class HmacUtils {
private static final int STREAM_BUFFER_LENGTH = 1024;
/**
* Returns an initialized <code>Mac</code> for the HmacMD5 algorithm.
* <p>
* Every implementation of the Java platform is required to support this standard Mac algorithm.
* </p>
*
* @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 <code>Mac</code> for the HmacSHA1 algorithm.
* <p>
* Every implementation of the Java platform is required to support this standard Mac algorithm.
* </p>
*
* @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 <code>Mac</code> for the HmacSHA256 algorithm.
* <p>
* Every implementation of the Java platform is required to support this standard Mac algorithm.
* </p>
*
* @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 <code>Mac</code> for the HmacSHA384 algorithm.
* <p>
* Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
* </p>
*
* @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 <code>Mac</code> for the HmacSHA512 algorithm.
* <p>
* Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
* </p>
*
* @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 <code>Mac</code> for the given <code>algorithm</code>.
*
* @param algorithm the name of the algorithm requested. See <a href=
* "http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA" >Appendix
* A in the Java Cryptography Architecture Reference Guide</a> 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 <code>Mac</code> for the given <code>algorithm</code>.
*
* @param algorithm the name of the algorithm requested. See <a href=
* "http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA" >Appendix
* A in the Java Cryptography Architecture Reference Guide</a> 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
* <p>
* The InputStream must not be null and will not be closed
* </p>
* @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
* <p>
* The InputStream must not be null and will not be closed
* </p>
* @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
* <p>
* The InputStream must not be null and will not be closed
* </p>
* @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
* <p>
* The InputStream must not be null and will not be closed
* </p>
* @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
* <p>
* The InputStream must not be null and will not be closed
* </p>
* @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
* <p>
* The InputStream must not be null and will not be closed
* </p>
* @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
* <p>
* The InputStream must not be null and will not be closed
* </p>
* @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
* <p>
* The InputStream must not be null and will not be closed
* </p>
* @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
* <p>
* The InputStream must not be null and will not be closed
* </p>
* @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
* <p>
* The InputStream must not be null and will not be closed
* </p>
* @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
* <p>
* The InputStream must not be null and will not be closed
* </p>
* @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;
}
}

View File

@ -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.
* <p>
* Based on the public domain ("beer-ware") C implementation from Poul-Henning Kamp which was found at: <a
* href="http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libcrypt/crypt-md5.c?rev=1.1;content-type=text%2Fplain">
* crypt-md5.c @ freebsd.org</a><br>
* <p>
* Source:
* <p>
* <pre>
* $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.1 1999/01/21 13:50:09 brandon Exp $
* </pre>
* <p>
* Conversion to Kotlin and from there to Java in 2012.
* <p>
* The C style comments are from the original C code, the ones with "//" from the port.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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();
}
}

View File

@ -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 <cite>Java Cryptography Architecture Standard Algorithm Name
* Documentation</cite>.
* <p>
* This class is immutable and thread-safe.
* </p>
* TODO 2.0 This should be an enum.
*
* @version $Id$
* @see <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html">Java Cryptography
* Architecture Standard Algorithm Name Documentation</a>
* @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.
* <p>
* Java 8 only.
* </p>
*
* @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";
}

View File

@ -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.
* <p>
* Based on the C implementation released into the Public Domain by Ulrich Drepper &lt;drepper@redhat.com&gt;
* http://www.akkadia.org/drepper/SHA-crypt.txt
* <p>
* Conversion to Kotlin and from there to Java in 2012 by Christian Hammers &lt;ch@lathspell.de&gt; and likewise put
* into the Public Domain.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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 <code>null</code> 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=<N> 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=<N>
// 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=<N>
// 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=<N> 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.
* <p>
* 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.
* <p>
* 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);
}
}

View File

@ -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.
* <p>
* 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().
* <p>
* The Java implementation was taken from the JetSpeed Portal project (see
* org.apache.jetspeed.services.security.ldap.UnixCrypt).
* <p>
* This class is slightly incompatible if the given salt contains characters that are not part of the allowed range
* [a-zA-Z0-9./].
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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;
}
}

View File

@ -1,24 +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.
-->
<html>
<body>
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.
</body>
</html>

View File

@ -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.
* <p>
* This is an algorithm created by the Caversham Project at the University of Otago. It implements the Caverphone 2.0
* algorithm:
* <p>
* <p>This class is immutable and thread-safe.</p>
*
* @version $Id: Caverphone.java 1075947 2011-03-01 17:56:14Z ggregory $
* @see <a href="http://en.wikipedia.org/wiki/Caverphone">Wikipedia - Caverphone</a>
* @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.
* <p>
* 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 <code>true</code> if the encodings of these strings are identical, <code>false</code> 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));
}
}

View File

@ -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.
* <p>
* 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 <a href="http://en.wikipedia.org/wiki/Caverphone">Wikipedia - Caverphone</a>
* @see <a href="http://caversham.otago.ac.nz/files/working/ctp150804.pdf">Caverphone 2.0 specification</a>
* @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 <code>true</code> if the caverphones of these strings are identical, <code>false</code> otherwise.
*/
public boolean isCaverphoneEqual(final String str1, final String str2) {
return this.caverphone(str1).equals(this.caverphone(str2));
}
}

View File

@ -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.
* <p>
* 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 <a href="http://en.wikipedia.org/wiki/Caverphone">Wikipedia - Caverphone</a>
* @see <a href="http://caversham.otago.ac.nz/files/working/ctp060902.pdf">Caverphone 1.0 specification</a>
* @since 1.5
* <p>
* <p>This class is immutable and thread-safe.</p>
*/
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());
}
}

View File

@ -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.
* <p>
* 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 <a href="http://en.wikipedia.org/wiki/Caverphone">Wikipedia - Caverphone</a>
* @see <a href="http://caversham.otago.ac.nz/files/working/ctp150804.pdf">Caverphone 2.0 specification</a>
* @since 1.5
* <p>
* <p>This class is immutable and thread-safe.</p>
*/
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());
}
}

View File

@ -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.
* <p>
* Implements the <a href="http://de.wikipedia.org/wiki/K%C3%B6lner_Phonetik">K&ouml;lner Phonetik</a> (Cologne
* Phonetic) algorithm issued by Hans Joachim Postel in 1969.
* </p>
* <p>
* The <i>K&ouml;lner Phonetik</i> is a phonetic algorithm which is optimized for the German language. It is related to
* the well-known soundex algorithm.
* </p>
* <p>
* <h2>Algorithm</h2>
* <p>
* <ul>
* <p>
* <li>
* <h3>Step 1:</h3>
* After preprocessing (conversion to upper case, transcription of <a
* href="http://en.wikipedia.org/wiki/Germanic_umlaut">germanic umlauts</a>, removal of non alphabetical characters) the
* letters of the supplied text are replaced by their phonetic code according to the following table.
* <table border="1">
* <caption style="caption-side: bottom"><small><i>(Source: <a
* href="http://de.wikipedia.org/wiki/K%C3%B6lner_Phonetik#Buchstabencodes">Wikipedia (de): K&ouml;lner Phonetik --
* Buchstabencodes</a>)</i></small></caption> <tbody>
* <tr>
* <th>Letter</th>
* <th>Context</th>
* <th align="center">Code</th>
* </tr>
* <tr>
* <td>A, E, I, J, O, U, Y</td>
* <td></td>
* <td align="center">0</td>
* </tr>
* <tr>
* <p>
* <td>H</td>
* <td></td>
* <td align="center">-</td>
* </tr>
* <tr>
* <td>B</td>
* <td></td>
* <td rowspan="2" align="center">1</td>
* </tr>
* <tr>
* <td>P</td>
* <td>not before H</td>
* <p>
* </tr>
* <tr>
* <td>D, T</td>
* <td>not before C, S, Z</td>
* <td align="center">2</td>
* </tr>
* <tr>
* <td>F, V, W</td>
* <td></td>
* <td rowspan="2" align="center">3</td>
* </tr>
* <tr>
* <p>
* <td>P</td>
* <td>before H</td>
* </tr>
* <tr>
* <td>G, K, Q</td>
* <td></td>
* <td rowspan="3" align="center">4</td>
* </tr>
* <tr>
* <td rowspan="2">C</td>
* <td>at onset before A, H, K, L, O, Q, R, U, X</td>
* <p>
* </tr>
* <tr>
* <td>before A, H, K, O, Q, U, X except after S, Z</td>
* </tr>
* <tr>
* <td>X</td>
* <td>not after C, K, Q</td>
* <td align="center">48</td>
* </tr>
* <tr>
* <td>L</td>
* <td></td>
* <p>
* <td align="center">5</td>
* </tr>
* <tr>
* <td>M, N</td>
* <td></td>
* <td align="center">6</td>
* </tr>
* <tr>
* <td>R</td>
* <td></td>
* <td align="center">7</td>
* </tr>
* <p>
* <tr>
* <td>S, Z</td>
* <td></td>
* <td rowspan="6" align="center">8</td>
* </tr>
* <tr>
* <td rowspan="3">C</td>
* <td>after S, Z</td>
* </tr>
* <tr>
* <td>at onset except before A, H, K, L, O, Q, R, U, X</td>
* </tr>
* <p>
* <tr>
* <td>not before A, H, K, O, Q, U, X</td>
* </tr>
* <tr>
* <td>D, T</td>
* <td>before C, S, Z</td>
* </tr>
* <tr>
* <td>X</td>
* <td>after C, K, Q</td>
* </tr>
* </tbody>
* </table>
* <p>
* <h4>Example:</h4>
* <p>
* <code>"M</code>&uuml;<code>ller-L</code>&uuml;
* <code>denscheidt" =&gt; "MULLERLUDENSCHEIDT" =&gt; "6005507500206880022"</code>
* <p>
* </li>
* <p>
* <li>
* <h3>Step 2:</h3>
* Collapse of all multiple consecutive code digits.
* <h4>Example:</h4>
* <code>"6005507500206880022" =&gt; "6050750206802"</code></li>
* <p>
* <li>
* <h3>Step 3:</h3>
* Removal of all codes "0" except at the beginning. This means that two or more identical consecutive digits can occur
* if they occur after removing the "0" digits.
* <p>
* <h4>Example:</h4>
* <code>"6050750206802" =&gt; "65752682"</code></li>
* <p>
* </ul>
* <p>
* <p>
* This class is thread-safe.
* </p>
*
* @see <a href="http://de.wikipedia.org/wiki/K%C3%B6lner_Phonetik">Wikipedia (de): K&ouml;lner Phonetik (in German)</a>
* @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:
* <ul>
* <li>capital a, umlaut mark</li>
* <li>capital u, umlaut mark</li>
* <li>capital o, umlaut mark</li>
* <li>small sharp s, German</li>
* </ul>
*/
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;
}
/**
* <p>
* Implements the <i>K&ouml;lner Phonetik</i> algorithm.
* </p>
* <p>
* In contrast to the initial description of the algorithm, this implementation does the encoding in one pass.
* </p>
*
* @param text The source text to encode
* @return the corresponding encoding according to the <i>K&ouml;lner Phonetik</i> 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);
}
}

View File

@ -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.
* <p>
* 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.
* </p>
* <p>
* The main differences compared to the other soundex variants are:
* </p>
* <ul>
* <li>coded names are 6 digits long
* <li>the initial character of the name is coded
* <li>rules to encoded multi-character n-grams
* <li>multiple possible encodings for the same name (branching)
* </ul>
* <p>
* This implementation supports branching, depending on the used method:
* <ul>
* <li>{@link #encode(String)} - branching disabled, only the first code will be returned
* <li>{@link #soundex(String)} - branching enabled, all codes will be returned, separated by '|'
* </ul>
* <p>
* 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}.
* </p>
* <p>
* This class is thread-safe.
* </p>
*
* @version $Id$
* @see Soundex
* @see <a href="http://en.wikipedia.org/wiki/Daitch%E2%80%93Mokotoff_Soundex"> Wikipedia - Daitch-Mokotoff Soundex</a>
* @see <a href="http://www.avotaynu.com/soundex.htm">Avotaynu - Soundexing and Genealogy</a>
* @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<Character, List<Rule>> RULES = new HashMap<Character, List<Rule>>();
/**
* Folding rules.
*/
private static final Map<Character, Character> FOLDINGS = new HashMap<Character, Character>();
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<Character, List<Rule>> rule : RULES.entrySet()) {
final List<Rule> ruleList = rule.getValue();
Collections.sort(ruleList, new Comparator<Rule>() {
@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<Character, List<Rule>> ruleMapping, final Map<Character, Character> 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<Rule> rules = ruleMapping.get(patternKey);
if (rules == null) {
rules = new ArrayList<Rule>();
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.
* <p>
* With ASCII-folding enabled, certain accented characters will be transformed to equivalent ASCII characters, e.g.
* è -&gt; e.
* </p>
*
* @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.
* <p>
* Removes all whitespace characters and performs ASCII folding if enabled.
* </p>
*
* @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.
* <p>
* 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.
* </p>
*
* @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.
* <p>
* In case a string is encoded into multiple codes (see branching rules), the result will contain all codes,
* separated by '|'.
* </p>
* <p>
* Example: the name "AUERBACH" is encoded as both
* </p>
* <ul>
* <li>097400</li>
* <li>097500</li>
* </ul>
* <p>
* Thus the result will be "097400|097500".
* </p>
*
* @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<Branch> currentBranches = new LinkedHashSet<Branch>();
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<Rule> 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<Branch> nextBranches = branching ? new ArrayList<Branch>() : 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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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 <CITE>Western Airlines</CITE> in 1977.
* <p>
* This class is immutable and thread-safe.
*
* @see <a href="http://en.wikipedia.org/wiki/Match_rating_approach">Wikipedia - Match Rating Approach</a>
* @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.
* <p>
* <h2>API Usage</h2>
* <p>
* Consider this method private, it is package protected for unit testing only.
* </p>
*
* @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 &gt; 6 characters) Else just returns the name.
* <p>
* <h2>API Usage</h2>
* <p>
* Consider this method private, it is package protected for unit testing only.
* </p>
*
* @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.
* <p>
* <h2>API Usage</h2>
* <p>
* Consider this method private, it is package protected for unit testing only.
* </p>
*
* @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 <code>true</code> if the encodings are identical <code>false</code> 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.
* <p>
* <h2>API Usage</h2>
* <p>
* Consider this method private, it is package protected for unit testing only.
* </p>
*
* @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.
* <p>
* <h2>API Usage</h2>
* <p>
* Consider this method private, it is package protected for unit testing only.
* </p>
*
* @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.
* <p>
* <h2>API Usage</h2>
* <p>
* Consider this method private, it is package protected for unit testing only.
* </p>
*
* @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.
* <p>
* <h2>API Usage</h2>
* <p>
* Consider this method private, it is package protected for unit testing only.
* </p>
*
* @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;
}
}
}

View File

@ -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.
* <p>
* Initial Java implementation by <CITE>William B. Brogden. December, 1997</CITE>.
* Permission given by <CITE>wbrogden</CITE> for code to be used anywhere.
* <p>
* <CITE>Hanging on the Metaphone</CITE> by <CITE>Lawrence Philips</CITE> in <CITE>Computer Language of Dec. 1990,
* p 39.</CITE>
* <p>
* Note, that this does not match the algorithm that ships with PHP, or the algorithm found in the Perl implementations:
* </p>
* <ul>
* <li><a href="http://search.cpan.org/~mschwern/Text-Metaphone-1.96/Metaphone.pm">Text:Metaphone-1.96</a>
* (broken link 4/30/2013) </li>
* <li><a href="https://metacpan.org/source/MSCHWERN/Text-Metaphone-1.96//Metaphone.pm">Text:Metaphone-1.96</a>
* (link checked 4/30/2013) </li>
* </ul>
* <p>
* They have had undocumented changes from the originally published algorithm.
* For more information, see <a href="https://issues.apache.org/jira/browse/CODEC-57">CODEC-57</a>.
* <p>
* 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 <code>true</code> if the metaphones of these strings are identical,
* <code>false</code> 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;
}
}

View File

@ -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.
* <p>
* NYSIIS features an accuracy increase of 2.7% over the traditional Soundex algorithm.
* <p>
* Algorithm description:
* <pre>
* 1. Transcode first characters of name
* 1a. MAC -&gt; MCC
* 1b. KN -&gt; NN
* 1c. K -&gt; C
* 1d. PH -&gt; FF
* 1e. PF -&gt; FF
* 1f. SCH -&gt; SSS
* 2. Transcode last characters of name
* 2a. EE, IE -&gt; Y
* 2b. DT,RT,RD,NT,ND -&gt; 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 -&gt; AF else A,E,I,O,U -&gt; A
* 4b. Q -&gt; G
* 4c. Z -&gt; S
* 4d. M -&gt; N
* 4e. KN -&gt; N else K -&gt; C
* 4f. SCH -&gt; SSS
* 4g. PH -&gt; FF
* 4h. H -&gt; If previous or next is nonvowel, previous
* 4i. W -&gt; 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
* </pre>
* <p>
* This class is immutable and thread-safe.
*
* @version $Id$
* @see <a href="http://en.wikipedia.org/wiki/NYSIIS">NYSIIS on Wikipedia</a>
* @see <a href="http://www.dropby.com/NYSIIS.html">NYSIIS on dropby.com</a>
* @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 <code>true</code> if the character is a vowel, <code>false</code> 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:
* <p>
* <ul>
* <li><code>true</code>: encoded strings have a maximum length of 6</li>
* <li><code>false</code>: encoded strings may have arbitrary length</li>
* </ul>
*
* @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 <code>true</code> if the encoder is configured for strict mode, <code>false</code> 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;
}
}

View File

@ -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
* <CITE>Margaret Odell</CITE> and <CITE>Robert Russell</CITE>.
* <p>
* <p>This class is immutable and thread-safe.</p>
*
* @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 <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp">
* MS T-SQL DIFFERENCE</a>
* @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();
}
}

View File

@ -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.
* <p>
* 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 <code>0</code> for a letter position
* means do not encode.
* <p>
* (This constant is provided as both an implementation convenience and to allow Javadoc to pick
* up the value for the constant values page.)
* </p>
*
* @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 <code>0</code> 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.
* <p>
* 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 <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp"> MS
* T-SQL DIFFERENCE </a>
* @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 <code>ch</code> 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);
}
}

View File

@ -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.
* <p>
* <p>This class is immutable and thread-safe.</p>
*
* @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.
* <ul>
* <li>For Soundex, this return value ranges from 0 through 4: 0 indicates
* little or no similarity, and 4 indicates strong similarity or identical
* values.</li>
* <li>For refined Soundex, the return value can be greater than 4.</li>
* </ul>
*
* @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 <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp">
* MS T-SQL DIFFERENCE</a>
*/
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.
* <ul>
* <li>For Soundex, this return value ranges from 0 through 4: 0 indicates
* little or no similarity, and 4 indicates strong similarity or identical
* values.</li>
* <li>For refined Soundex, the return value can be greater than 4.</li>
* </ul>
*
* @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 <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp">
* MS T-SQL DIFFERENCE</a>
*/
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;
}
}

View File

@ -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.
* <p>
* Beider-Morse phonetic encodings are optimised for family names. However, they may be useful for a wide range of
* words.
* <p>
* 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.
* <p>
* <b>Encoding overview</b>
* <p>
* 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 "<code>ault</code>" 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.
* <p>
* 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, "<code>Mac/Mc</code>" 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.
* <p>
* <b>Encoding format</b>
* <p>
* 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 (<code>|</code>) 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, "<code>d'ortley</code>" has a possible prefix. The form
* without prefix encodes to "<code>ortlaj|ortlej</code>", while the form with prefix encodes to "
* <code>dortlaj|dortlej</code>". Thus, the full, combined encoding is "<code>(ortlaj|ortlej)-(dortlaj|dortlej)</code>".
* <p>
* 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, "<code>Renault</code>" encodes to "
* <code>rYnDlt|rYnalt|rYnult|rinDlt|rinalt|rinult</code>". The <code>APPROX</code> 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 (<code>|</code>) and indexing under each of these alternatives.
* <p>
* <b>Note</b>: this version of the Beider-Morse encoding is equivalent with v3.4 of the reference implementation.
*
* @version $Id$
* @see <a href="http://stevemorse.org/phonetics/bmpm.htm">Beider-Morse Phonetic Matching</a>
* @see <a href="http://stevemorse.org/phoneticinfo.htm">Reference implementation</a>
* @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);
}
}

View File

@ -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.
* <p>
* 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.
* <p>
* 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.
* <p>
* This class is intended to be immutable and thread-safe.
* <p>
* <b>Lang resources</b>
* <p>
* Language guessing rules are typically loaded from resource files. These are UTF-8 encoded text files.
* They are systematically named following the pattern:
* <blockquote>org/apache/commons/codec/language/bm/lang.txt</blockquote>
* The format of these resources is the following:
* <ul>
* <li><b>Rules:</b> whitespace separated strings.
* There should be 3 columns to each row, and these will be interpreted as:
* <ol>
* <li>pattern: a regular expression.</li>
* <li>languages: a '+'-separated list of languages.</li>
* <li>acceptOnMatch: 'true' or 'false' indicating if a match rules in or rules out the language.</li>
* </ol>
* </li>
* <li><b>End-of-line comments:</b> Any occurrence of '//' will cause all text following on that line to be
* discarded as a comment.</li>
* <li><b>Multi-line comments:</b> Any line starting with '/*' will start multi-line commenting mode.
* This will skip all content until a line ending in '*' and '/' is found.</li>
* <li><b>Blank lines:</b> All blank lines will be skipped.</li>
* </ul>
* <p>
* 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 <code>instance</code> method to get their Lang instances.
private static final class LangRule {
private final boolean acceptOnMatch;
private final Set<String> languages;
private final Pattern pattern;
private LangRule(final Pattern pattern, final Set<String> 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<NameType, Lang> Langs = new EnumMap<NameType, Lang>(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.
* <p>
* 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<LangRule> rules = new ArrayList<LangRule>();
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<String>(Arrays.asList(langs)), accept));
}
}
}
} finally {
scanner.close();
}
return new Lang(rules, languages);
}
private final Languages languages;
private final List<LangRule> rules;
private Lang(final List<LangRule> 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<String> langs = new HashSet<String>(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;
}
}

View File

@ -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.
* <p>
* Language codes are typically loaded from resource files. These are UTF-8 encoded text files. They are
* systematically named following the pattern:
* <blockquote>org/apache/commons/codec/language/bm/${{@link NameType#getName()} languages.txt</blockquote>
* <p>
* The format of these resources is the following:
* <ul>
* <li><b>Language:</b> a single string containing no whitespace</li>
* <li><b>End-of-line comments:</b> Any occurrence of '//' will cause all text following on that line to be
* discarded as a comment.</li>
* <li><b>Multi-line comments:</b> Any line starting with '/*' will start multi-line commenting mode.
* This will skip all content until a line ending in '*' and '/' is found.</li>
* <li><b>Blank lines:</b> All blank lines will be skipped.</li>
* </ul>
* <p>
* Ported from language.php
* <p>
* 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<String> 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<String> languages;
private SomeLanguages(final Set<String> 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<String> 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<String> ls = new HashSet<String>(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<String> ls = new HashSet<String>(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<NameType, Languages> LANGUAGES = new EnumMap<NameType, Languages>(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<String> ls = new HashSet<String>();
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<String> 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<String> languages) {
this.languages = languages;
}
public Set<String> getLanguages() {
return this.languages;
}
}

View File

@ -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
* <code>GENERIC</code> 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;
}
}

View File

@ -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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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<Rule.Phoneme> phonemes;
private PhonemeBuilder(final Rule.Phoneme phoneme) {
this.phonemes = new LinkedHashSet<Rule.Phoneme>();
this.phonemes.add(phoneme);
}
private PhonemeBuilder(final Set<Rule.Phoneme> phonemes) {
this.phonemes = phonemes;
}
/**
* Creates a new phoneme builder containing all phonemes in this one extended by <code>str</code>.
*
* @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.
* <p>
* 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<Rule.Phoneme> newPhonemes = new LinkedHashSet<Rule.Phoneme>(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<Rule.Phoneme> 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 <code>i</code> and <code>found</code> are updated. <code>i</code> points to the
* index of the next char in <code>input</code> that must be processed next (the input up to that index having been
* processed already), and <code>found</code> indicates if a matching rule was found or not. In the case where a
* matching rule was found, <code>phonemeBuilder</code> is replaced with a new builder containing the phonemes
* updated by the matching rule.
* <p>
* 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<String, List<Rule>> finalRules;
private final CharSequence input;
private PhonemeBuilder phonemeBuilder;
private int i;
private final int maxPhonemes;
private boolean found;
public RulesApplication(final Map<String, List<Rule>> 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, <code>i</code> is advanced one and the character is silently dropped from the phonetic spelling.
*
* @return <code>this</code>
*/
public RulesApplication invoke() {
this.found = false;
int patternLength = 1;
final List<Rule> 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<NameType, Set<String>> NAME_PREFIXES = new EnumMap<NameType, Set<String>>(NameType.class);
static {
NAME_PREFIXES.put(NameType.ASHKENAZI,
Collections.unmodifiableSet(
new HashSet<String>(Arrays.asList("bar", "ben", "da", "de", "van", "von"))));
NAME_PREFIXES.put(NameType.SEPHARDIC,
Collections.unmodifiableSet(
new HashSet<String>(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<String>(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 <code>strings</code> interleaved by <code>sep</code>
*/
private static String join(final Iterable<String> strings, final String sep) {
final StringBuilder sb = new StringBuilder();
final Iterator<String> 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<String, List<Rule>> finalRules) {
if (finalRules == null) {
throw new NullPointerException("finalRules can not be null");
}
if (finalRules.isEmpty()) {
return phonemeBuilder;
}
final Map<Rule.Phoneme, Rule.Phoneme> phonemes =
new TreeMap<Rule.Phoneme, Rule.Phoneme>(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<String, List<Rule>> rules = Rule.getInstanceMap(this.nameType, RuleType.RULES, languageSet);
// rules common across many (all) languages
final Map<String, List<Rule>> 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<String, List<Rule>> 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<String> words = Arrays.asList(input.split("\\s+"));
final List<String> words2 = new ArrayList<String>();
// 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;
}
}

Some files were not shown because too many files have changed in this diff Show More