Merge branch 'master' into bukkit

This commit is contained in:
sk89q 2011-01-02 17:09:11 -08:00
commit 0dfb88c41d
86 changed files with 7676 additions and 909 deletions

View File

@ -1,3 +1,32 @@
2.5:
- Fixed issues with permissions not being read correctly.
- WorldEdit is now world-aware (not that the Minecraft server is).
- Abstracted super pickaxe mode/tools and changed commands to /tree, /info,
/none, /single, /area, and /recur.
- New /repl super pickaxe tool.
- Now bundling JNBT.
- Add a very rudimentary command line program that will check the integrity
(a very basic integrity check) of a world.
2.4:
- Added the ability to use (require) inventory with operations, preventing
people from setting blocks that they don't have.
- Simplified the max blocks change limit to be binary (either you have it or
not). Also separated the 'max' limit and the 'default' limit in terms
of configuration. This means that the WorldEdit restrictions file is
no longer used.
- A large part of the code was moved around (again) to make porting
WorldEdit to other modding APIs easier, but this means that something
may have broken.
- Chest handling was rewritten for Minecraft beta, so it should be
reliable now and not cause exceptions.
- Item damage is now managed by WorldEdit's chest handling APIs.
- Worked around an issue with the java.util.zip implementation that
caused ZIP files containing backslashes to not work correctly.
- Changed the TrueZip support to use the API for java.util.zip, meaning
some bugs should be fixed.
- Made all commands support double forward slashes as the command prefix.
2.3.4:
- Fixed issues with chests.
- Added configuration option that disables the "//" prefix and lets you use

View File

@ -5,7 +5,7 @@ This plugin requires Hey0's server modification.
1. Create a "plugins" folder inside your "bin" folder.
2. Copy WorldEdit.jar and jnbt.jar into "plugins".
2. Copy WorldEdit.jar into "plugins".
3. Add "WorldEdit" to the "plugins" line of your server.properties file.
If it's not already there, add the line. The line should look like this:

View File

@ -202,3 +202,29 @@ 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.
JOpt Simple License
-------------------
Copyright (c) 2009 Paul R. Holser, Jr.
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.

View File

@ -2,3 +2,5 @@ This product includes software from JNBT (http://jnbt.sourceforge.net/).
This product includes software from WorldEdit
(http://www.sk89q.com), under GNU Lesser General Public License, version 3.
This product includes software from JOpt Simple, under the MIT license.

View File

@ -18,7 +18,6 @@
<classpath>
<fileset dir="${lib.dir}">
<include name="truezip.jar" />
<include name="jnbt.jar" />
<include name="Minecraft_Mod.jar" />
<include name="minecraft_server.jar" />
<include name="Bukkit.jar" />
@ -34,7 +33,8 @@
<attribute name="Implementation-Title" value="WorldEdit"/>
<attribute name="Implementation-Version" value="${version}"/>
<attribute name="WorldEdit-Version" value="${version}"/>
<attribute name="Class-Path" value="jnbt.jar truezip.jar"/>
<attribute name="Class-Path" value="truezip.jar"/>
<attribute name="Main-Class" value="com.sk89q.worldedit.cli.Main"/>
</manifest>
<copy tofile="${build.dir}/plugin.yml" file="plugin.yml"/>
<jar jarfile="${dist.dir}/WorldEdit.jar" basedir="${build.dir}" manifest="manifest.mf"/>
@ -59,17 +59,12 @@
<copy tofile="${release.dir}/worldedit.updatr" file="worldedit.updatr"/>
<replace file="${release.dir}/worldedit.updatr" token="%version%" value="${version}"/>
<copy tofile="${release.dir}/WorldEdit.jar" file="${dist.dir}/WorldEdit.jar"/>
<copy todir="${release.dir}">
<fileset dir="lib">
<include name="jnbt.jar"/>
</fileset>
</copy>
<zip destfile="${release.dir}/worldedit-${version}.zip" basedir="${release.dir}" excludes="*.zip"/>
<mkdir dir="${release.dir}/src"/>
<copy todir="${release.dir}/src">
<fileset dir="${src.dir}"/>
</copy>
<zip destfile="${release.dir}/worldedit-${version}-source.zip" basedir="${release.dir}" excludes="*.zip"/>
<zip destfile="${release.dir}/worldedit-${version}-src.zip" basedir="${release.dir}" excludes="*.zip"/>
</target>
<!-- Clean the output -->

122
src/HMConfiguration.java Normal file
View File

@ -0,0 +1,122 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.io.IOException;
import java.util.HashSet;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LogFormat;
import com.sk89q.worldedit.snapshots.SnapshotRepository;
/**
* Configuration for hMod.
*
* @author sk89q
*/
public class HMConfiguration extends LocalConfiguration {
/**
* Logger.
*/
private static final Logger logger = Logger.getLogger("Minecraft.WorldEdit");
/**
* Properties file.
*/
private PropertiesFile properties;
/**
* Construct the object.
*/
public HMConfiguration() {
properties = new PropertiesFile("worldedit.properties");
}
/**
* Loads the configuration.
*/
public void load() {
try {
properties.load();
} catch (IOException e) {
logger.warning("worldedit.properties could not be loaded: "
+ e.getMessage());
}
profile = properties.getBoolean("debug-profile", profile);
wandItem = properties.getInt("wand-item", wandItem);
defaultChangeLimit = Math.max(-1, properties.getInt(
"default-max-blocks-changed", defaultChangeLimit));
maxChangeLimit = Math.max(-1,
properties.getInt("max-blocks-changed", maxChangeLimit));
maxRadius = Math.max(-1, properties.getInt("max-radius", maxRadius));
maxSuperPickaxeSize = Math.max(1, properties.getInt(
"max-super-pickaxe-size", maxSuperPickaxeSize));
registerHelp = properties.getBoolean("register-help", registerHelp);
logComands = properties.getBoolean("log-commands", logComands);
superPickaxeDrop = properties.getBoolean("super-pickaxe-drop-items",
superPickaxeDrop);
superPickaxeManyDrop = properties.getBoolean(
"super-pickaxe-many-drop-items", superPickaxeManyDrop);
noDoubleSlash = properties.getBoolean("no-double-slash", noDoubleSlash);
useInventory = properties.getBoolean("use-inventory", useInventory);
useInventoryOverride = properties.getBoolean("use-inventory-override",
useInventoryOverride);
// Get disallowed blocks
disallowedBlocks = new HashSet<Integer>();
String defdisallowedBlocks = StringUtil.joinString(defaultDisallowedBlocks, ",", 0);
for (String b : properties.getString("disallowed-blocks",
defdisallowedBlocks).split(",")) {
try {
disallowedBlocks.add(Integer.parseInt(b));
} catch (NumberFormatException e) {
}
}
String snapshotsDir = properties.getString("snapshots-dir", "");
if (!snapshotsDir.trim().equals("")) {
snapshotRepo = new SnapshotRepository(snapshotsDir);
} else {
snapshotRepo = null;
}
String type = properties.getString("shell-save-type", "").trim();
shellSaveType = type.equals("") ? null : type;
String logFile = properties.getString("log-file", "");
if (!logFile.equals("")) {
try {
FileHandler handler = new FileHandler(logFile, true);
handler.setFormatter(new LogFormat());
logger.addHandler(handler);
} catch (IOException e) {
logger.log(Level.WARNING, "Could not use log file " + logFile + ": "
+ e.getMessage());
}
} else {
for (Handler handler : logger.getHandlers()) {
logger.removeHandler(handler);
}
}
}
}

View File

@ -17,9 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.ServerInterface;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditPlayer;
import com.sk89q.worldedit.LocalPlayer;
import com.sk89q.worldedit.WorldVector;
import com.sk89q.worldedit.bags.BlockBag;
import com.sk89q.worldedit.blocks.BlockType;
@ -27,7 +29,7 @@ import com.sk89q.worldedit.blocks.BlockType;
*
* @author sk89q
*/
public class HMPlayer extends WorldEditPlayer {
public class HMPlayer extends LocalPlayer {
/**
* Stores the player.
*/
@ -38,8 +40,8 @@ public class HMPlayer extends WorldEditPlayer {
*
* @param player
*/
public HMPlayer(Player player) {
super();
public HMPlayer(ServerInterface server, Player player) {
super(server);
this.player = player;
}
@ -58,13 +60,13 @@ public class HMPlayer extends WorldEditPlayer {
* @param range
* @return point
*/
public Vector getBlockTrace(int range) {
public WorldVector getBlockTrace(int range) {
HitBlox hitBlox = new HitBlox(player,range, 0.2);
Block block = hitBlox.getTargetBlock();
if (block == null) {
return null;
}
return new Vector(block.getX(), block.getY(), block.getZ());
return new WorldVector(null, block.getX(), block.getY(), block.getZ());
}
/**
@ -73,7 +75,7 @@ public class HMPlayer extends WorldEditPlayer {
* @param range
* @return point
*/
public Vector getSolidBlockTrace(int range) {
public WorldVector getSolidBlockTrace(int range) {
HitBlox hitBlox = new HitBlox(player,range, 0.2);
Block block = null;
@ -85,14 +87,9 @@ public class HMPlayer extends WorldEditPlayer {
if (block == null) {
return null;
}
return new Vector(block.getX(), block.getY(), block.getZ());
return new WorldVector(null, block.getX(), block.getY(), block.getZ());
}
/**
* Get the ID of the item that the player is holding.
*
* @return
*/
/**
* Get the ID of the item that the player is holding.
*
@ -111,11 +108,6 @@ public class HMPlayer extends WorldEditPlayer {
return player.getName();
}
/**
* Get the player's view pitch.
*
* @return pitch
*/
/**
* Get the player's view pitch.
*
@ -130,15 +122,19 @@ public class HMPlayer extends WorldEditPlayer {
*
* @return point
*/
public Vector getPosition() {
return new Vector(player.getX(), player.getY(), player.getZ());
public WorldVector getPosition() {
return new WorldVector(null, player.getX(), player.getY(), player.getZ());
}
/**
* Get the player's view yaw.
* Get the player's world.
*
* @return yaw
* @return point
*/
public LocalWorld getWorld() {
return null;
}
/**
* Get the player's view yaw.
*
@ -148,12 +144,6 @@ public class HMPlayer extends WorldEditPlayer {
return player.getRotation();
}
/**
* Gives the player an item.
*
* @param type
* @param amt
*/
/**
* Gives the player an item.
*
@ -174,6 +164,7 @@ public class HMPlayer extends WorldEditPlayer {
boolean foundNext = false;
int searchDist = 0;
HitBlox hitBlox = new HitBlox(player,range, 0.2);
LocalWorld world = getPosition().getWorld();
Block block;
while ((block = hitBlox.getNextBlock()) != null) {
searchDist++;
@ -183,7 +174,7 @@ public class HMPlayer extends WorldEditPlayer {
if (block.getType() == 0) {
if (foundNext) {
Vector v = new Vector(block.getX(), block.getY() - 1, block.getZ());
if (server.getBlockType(v) == 0) {
if (server.getBlockType(world, v) == 0) {
setPosition(v.add(0.5, 0, 0.5));
return true;
}

View File

@ -43,7 +43,7 @@ public class HMServerInterface extends ServerInterface {
* @param type
* @return
*/
public boolean setBlockType(Vector pt, int type) {
public boolean setBlockType(LocalWorld world, Vector pt, int type) {
// Can't set colored cloth or crash
if ((type >= 21 && type <= 34) || type == 36) {
return false;
@ -58,7 +58,7 @@ public class HMServerInterface extends ServerInterface {
* @param pt
* @return
*/
public int getBlockType(Vector pt) {
public int getBlockType(LocalWorld world, Vector pt) {
return etc.getServer().getBlockIdAt(pt.getBlockX(), pt.getBlockY(),
pt.getBlockZ());
}
@ -70,7 +70,7 @@ public class HMServerInterface extends ServerInterface {
* @param data
* @return
*/
public void setBlockData(Vector pt, int data) {
public void setBlockData(LocalWorld world, Vector pt, int data) {
etc.getServer().setBlockData(pt.getBlockX(), pt.getBlockY(),
pt.getBlockZ(), data);
}
@ -81,7 +81,7 @@ public class HMServerInterface extends ServerInterface {
* @param pt
* @return
*/
public int getBlockData(Vector pt) {
public int getBlockData(LocalWorld world, Vector pt) {
return etc.getServer().getBlockData(pt.getBlockX(), pt.getBlockY(),
pt.getBlockZ());
}
@ -92,7 +92,7 @@ public class HMServerInterface extends ServerInterface {
* @param pt
* @param text
*/
public void setSignText(Vector pt, String[] text) {
public void setSignText(LocalWorld world, Vector pt, String[] text) {
Sign signData = (Sign)etc.getServer().getComplexBlock(
pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
if (signData == null) {
@ -110,7 +110,7 @@ public class HMServerInterface extends ServerInterface {
* @param pt
* @return
*/
public String[] getSignText(Vector pt) {
public String[] getSignText(LocalWorld world, Vector pt) {
Sign signData = (Sign)etc.getServer().getComplexBlock(
pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
if (signData == null) {
@ -130,7 +130,7 @@ public class HMServerInterface extends ServerInterface {
* @param pt
* @return
*/
public BaseItemStack[] getChestContents(Vector pt) {
public BaseItemStack[] getChestContents(LocalWorld world, Vector pt) {
ComplexBlock cblock = etc.getServer().getOnlyComplexBlock(
pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
@ -165,7 +165,7 @@ public class HMServerInterface extends ServerInterface {
* @param contents
* @return
*/
public boolean setChestContents(Vector pt,
public boolean setChestContents(LocalWorld world, Vector pt,
BaseItemStack[] contents) {
ComplexBlock cblock = etc.getServer().getOnlyComplexBlock(
@ -197,7 +197,7 @@ public class HMServerInterface extends ServerInterface {
*
* @param pt
*/
public boolean clearChest(Vector pt) {
public boolean clearChest(LocalWorld world, Vector pt) {
ComplexBlock cblock = etc.getServer().getOnlyComplexBlock(
pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
@ -247,7 +247,7 @@ public class HMServerInterface extends ServerInterface {
* @param pt
* @param mobType
*/
public void setMobSpawnerType(Vector pt, String mobType) {
public void setMobSpawnerType(LocalWorld world, Vector pt, String mobType) {
ComplexBlock cblock = etc.getServer().getComplexBlock(
pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
@ -266,7 +266,7 @@ public class HMServerInterface extends ServerInterface {
* @param pt
* @param mobType
*/
public String getMobSpawnerType(Vector pt) {
public String getMobSpawnerType(LocalWorld world, Vector pt) {
try {
return MinecraftServerInterface.getMobSpawnerType(pt);
} catch (Throwable t) {
@ -282,7 +282,7 @@ public class HMServerInterface extends ServerInterface {
* @param pt
* @return
*/
public boolean generateTree(EditSession editSession, Vector pt) {
public boolean generateTree(EditSession editSession, LocalWorld world, Vector pt) {
try {
return MinecraftServerInterface.generateTree(editSession, pt);
} catch (Throwable t) {
@ -300,7 +300,7 @@ public class HMServerInterface extends ServerInterface {
* @param count
* @param times
*/
public void dropItem(Vector pt, int type, int count, int times) {
public void dropItem(LocalWorld world, Vector pt, int type, int count, int times) {
for (int i = 0; i < times; i++) {
etc.getServer().dropItem(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ(),
type, count);
@ -315,7 +315,7 @@ public class HMServerInterface extends ServerInterface {
* @param count
* @param times
*/
public void dropItem(Vector pt, int type, int count) {
public void dropItem(LocalWorld world, Vector pt, int type, int count) {
etc.getServer().dropItem(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ(),
type, count);
}
@ -328,7 +328,7 @@ public class HMServerInterface extends ServerInterface {
* @param count
* @param times
*/
public void dropItem(Vector pt, int type) {
public void dropItem(LocalWorld world, Vector pt, int type) {
etc.getServer().dropItem(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ(),
type, 1);
}
@ -338,57 +338,57 @@ public class HMServerInterface extends ServerInterface {
*
* @param pt
*/
public void simulateBlockMine(Vector pt) {
int type = getBlockType(pt);
setBlockType(pt, 0);
public void simulateBlockMine(LocalWorld world, Vector pt) {
int type = getBlockType(world, pt);
//setBlockType(world, pt, 0);
if (type == 1) { dropItem(pt, 4); } // Stone
else if (type == 2) { dropItem(pt, 3); } // Grass
if (type == 1) { dropItem(world, pt, 4); } // Stone
else if (type == 2) { dropItem(world, pt, 3); } // Grass
else if (type == 7) { } // Bedrock
else if (type == 8) { } // Water
else if (type == 9) { } // Water
else if (type == 10) { } // Lava
else if (type == 11) { } // Lava
else if (type == 13) { // Gravel
dropItem(pt, type);
dropItem(world, pt, type);
if (random.nextDouble() >= 0.9) {
dropItem(pt, 318);
dropItem(world, pt, 318);
}
}
else if (type == 16) { dropItem(pt, 263); } // Coal ore
else if (type == 16) { dropItem(world, pt, 263); } // Coal ore
else if (type == 18) { // Leaves
if (random.nextDouble() > 0.95) {
dropItem(pt, 6);
dropItem(world, pt, 6);
}
}
else if (type == 20) { } // Glass
else if (type == 43) { dropItem(pt, 44); } // Double step
else if (type == 43) { dropItem(world, pt, 44); } // Double step
else if (type == 47) { } // Bookshelves
else if (type == 51) { } // Fire
else if (type == 52) { } // Mob spawner
else if (type == 53) { dropItem(pt, 5); } // Wooden stairs
else if (type == 55) { dropItem(pt, 331); } // Redstone wire
else if (type == 56) { dropItem(pt, 264); } // Diamond ore
else if (type == 59) { dropItem(pt, 295); } // Crops
else if (type == 60) { dropItem(pt, 3); } // Soil
else if (type == 62) { dropItem(pt, 61); } // Furnace
else if (type == 63) { dropItem(pt, 323); } // Sign post
else if (type == 64) { dropItem(pt, 324); } // Wood door
else if (type == 67) { dropItem(pt, 4); } // Cobblestone stairs
else if (type == 68) { dropItem(pt, 323); } // Wall sign
else if (type == 71) { dropItem(pt, 330); } // Iron door
else if (type == 73) { dropItem(pt, 331, 1, 4); } // Redstone ore
else if (type == 74) { dropItem(pt, 331, 1, 4); } // Glowing redstone ore
else if (type == 75) { dropItem(pt, 76); } // Redstone torch
else if (type == 53) { dropItem(world, pt, 5); } // Wooden stairs
else if (type == 55) { dropItem(world, pt, 331); } // Redstone wire
else if (type == 56) { dropItem(world, pt, 264); } // Diamond ore
else if (type == 59) { dropItem(world, pt, 295); } // Crops
else if (type == 60) { dropItem(world, pt, 3); } // Soil
else if (type == 62) { dropItem(world, pt, 61); } // Furnace
else if (type == 63) { dropItem(world, pt, 323); } // Sign post
else if (type == 64) { dropItem(world, pt, 324); } // Wood door
else if (type == 67) { dropItem(world, pt, 4); } // Cobblestone stairs
else if (type == 68) { dropItem(world, pt, 323); } // Wall sign
else if (type == 71) { dropItem(world, pt, 330); } // Iron door
else if (type == 73) { dropItem(world, pt, 331, 1, 4); } // Redstone ore
else if (type == 74) { dropItem(world, pt, 331, 1, 4); } // Glowing redstone ore
else if (type == 75) { dropItem(world, pt, 76); } // Redstone torch
else if (type == 78) { } // Snow
else if (type == 79) { } // Ice
else if (type == 82) { dropItem(pt, 337, 1, 4); } // Clay
else if (type == 83) { dropItem(pt, 338); } // Reed
else if (type == 89) { dropItem(pt, 348); } // Lightstone
else if (type == 82) { dropItem(world, pt, 337, 1, 4); } // Clay
else if (type == 83) { dropItem(world, pt, 338); } // Reed
else if (type == 89) { dropItem(world, pt, 348); } // Lightstone
else if (type == 90) { } // Portal
else if (type != 0) {
dropItem(pt, type);
dropItem(world, pt, type);
}
}
@ -409,7 +409,7 @@ public class HMServerInterface extends ServerInterface {
* @param radius
* @return
*/
public int killMobs(Vector origin, int radius) {
public int killMobs(LocalWorld world, Vector origin, int radius) {
int killed = 0;
for (Mob mob : etc.getServer().getMobList()) {

View File

@ -17,53 +17,48 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.Handler;
import java.util.logging.FileHandler;
import java.io.*;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.bags.BlockBag;
import com.sk89q.worldedit.blocks.*;
import com.sk89q.worldedit.data.*;
import com.sk89q.worldedit.filters.*;
import com.sk89q.worldedit.snapshots.*;
import com.sk89q.worldedit.regions.*;
import com.sk89q.worldedit.patterns.*;
/**
* Plugin base.
* The event listener for WorldEdit in hMod.
*
* @author sk89q
*/
public class HMWorldEditListener extends PluginListener {
/**
* Logger.
*/
private static final Logger logger = Logger.getLogger("Minecraft.WorldEdit");
/**
* WorldEditLibrary's properties file.
*/
private PropertiesFile properties;
/**
* Main WorldEdit controller.
*/
private WorldEditController controller = new WorldEditController();
private WorldEditController controller;
/**
* Configuration.
*/
private LocalConfiguration config;
/**
* A copy of the server instance. This is where all world<->WorldEdit calls
* will go through.
*/
private ServerInterface server;
/**
* Constructs an instance.
*
* @param server
*/
public HMWorldEditListener(ServerInterface server) {
this.server = server;
config = new HMConfiguration();
controller = new WorldEditController(server, config);
}
/**
*
* @param player
*/
@Override
public void onDisconnect(Player player) {
controller.handleDisconnect(new HMPlayer(player));
controller.handleDisconnect(wrapPlayer(player));
}
/**
@ -72,7 +67,7 @@ public class HMWorldEditListener extends PluginListener {
* @param player
*/
public void onArmSwing(Player player) {
controller.handleArmSwing(new HMPlayer(player));
controller.handleArmSwing(wrapPlayer(player));
}
/**
@ -91,7 +86,7 @@ public class HMWorldEditListener extends PluginListener {
Vector pos = new Vector(blockClicked.getX(),
blockClicked.getY(),
blockClicked.getZ());
return controller.handleBlockRightClick(new HMPlayer(player), pos);
return controller.handleBlockRightClick(wrapPlayer(player), null, pos);
}
/**
@ -107,7 +102,7 @@ public class HMWorldEditListener extends PluginListener {
Vector pos = new Vector(blockClicked.getX(),
blockClicked.getY(),
blockClicked.getZ());
return controller.handleBlockLeftClick(new HMPlayer(player), pos);
return controller.handleBlockLeftClick(wrapPlayer(player), null, pos);
}
/**
@ -118,81 +113,21 @@ public class HMWorldEditListener extends PluginListener {
*/
@Override
public boolean onCommand(Player player, String[] split) {
return controller.handleCommand(new HMPlayer(player), split);
return controller.handleCommand(wrapPlayer(player), split);
}
/**
* Loads the configuration.
*/
public void loadConfiguration() {
if (properties == null) {
properties = new PropertiesFile("worldedit.properties");
} else {
try {
properties.load();
} catch (IOException e) {
logger.warning("worldedit.properties could not be loaded: "
+ e.getMessage());
}
}
controller.profile = properties.getBoolean("debug-profile", false);
controller.wandItem = properties.getInt("wand-item", 271);
controller.defaultChangeLimit = Math.max(-1, properties.getInt("default-max-blocks-changed", -1));
controller.maxChangeLimit = Math.max(-1, properties.getInt("max-blocks-changed", -1));
controller.maxRadius = Math.max(-1, properties.getInt("max-radius", -1));
controller.maxSuperPickaxeSize = Math.max(1, properties.getInt("max-super-pickaxe-size", 5));
controller.registerHelp = properties.getBoolean("register-help", true);
controller.logComands = properties.getBoolean("log-commands", false);
controller.superPickaxeDrop = properties.getBoolean("super-pickaxe-drop-items", true);
controller.superPickaxeManyDrop = properties.getBoolean("super-pickaxe-many-drop-items", false);
controller.noDoubleSlash = properties.getBoolean("no-double-slash", false);
controller.useInventory = properties.getBoolean("use-inventory", false);
controller.useInventoryOverride = properties.getBoolean("use-inventory-override", false);
// Get allowed blocks
controller.allowedBlocks = new HashSet<Integer>();
for (String b : properties.getString("allowed-blocks",
WorldEditController.getDefaultAllowedBlocks()).split(",")) {
try {
controller.allowedBlocks.add(Integer.parseInt(b));
} catch (NumberFormatException e) {
}
}
String snapshotsDir = properties.getString("snapshots-dir", "");
if (!snapshotsDir.trim().equals("")) {
controller.snapshotRepo = new SnapshotRepository(snapshotsDir);
} else {
controller.snapshotRepo = null;
}
String type = properties.getString("shell-save-type", "").trim();
controller.shellSaveType = type.equals("") ? null : type;
String logFile = properties.getString("log-file", "");
if (!logFile.equals("")) {
try {
FileHandler handler = new FileHandler(logFile, true);
handler.setFormatter(new LogFormat());
logger.addHandler(handler);
} catch (IOException e) {
logger.log(Level.WARNING, "Could not use log file " + logFile + ": "
+ e.getMessage());
}
} else {
for (Handler handler : logger.getHandlers()) {
logger.removeHandler(handler);
}
}
config.load();
}
/**
* Register commands with help.
*/
public void registerCommands() {
if (controller.registerHelp) {
if (config.registerHelp) {
for (Map.Entry<String,String> entry : controller.getCommands().entrySet()) {
etc.getInstance().addCommand(entry.getKey(), entry.getValue());
}
@ -221,7 +156,17 @@ public class HMWorldEditListener extends PluginListener {
* @param player
* @return
*/
public WorldEditSession _bridgeSession(Player player) {
return controller.getBridgeSession(new HMPlayer(player));
public LocalSession _bridgeSession(Player player) {
return controller.getBridgeSession(wrapPlayer(player));
}
/**
* Wrap a hMod player for WorldEdit.
*
* @param player
* @return
*/
private LocalPlayer wrapPlayer(Player player) {
return new HMPlayer(server, player);
}
}

View File

@ -20,8 +20,6 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sk89q.worldedit.ServerInterface;
/**
* Entry point for the plugin for hey0's mod.
*
@ -31,18 +29,29 @@ public class WorldEdit extends Plugin {
/**
* Logger.
*/
private static final Logger logger = Logger.getLogger("Minecraft.WorldEdit");
/**
* WorldEditLibrary instance.
*/
private static final HMWorldEditListener listener = new HMWorldEditListener();
private static final Logger logger = Logger
.getLogger("Minecraft.WorldEdit");
/**
* WorldEdit version, fetched from the .jar's manifest. Used to print the
* WorldEdit version in various places.
* The event listener for WorldEdit an hMod. Configuration and such is
* also loaded here as well, although the core of the WorldEdit is
* actually in com.sk89q.worldedit.WorldEditController and is merely
* loaded by this listener.
*/
private final HMWorldEditListener listener;
/**
* WorldEdit version, fetched from the .jar's manifest.
*/
private String version;
/**
* Construct an instance of the plugin.
*/
public WorldEdit() {
listener = new HMWorldEditListener(new HMServerInterface());
}
/**
* Initializes the plugin.
*/
@ -63,8 +72,6 @@ public class WorldEdit extends Plugin {
loader.addListener(PluginLoader.Hook.ARM_SWING, listener, this,
PluginListener.Priority.MEDIUM);
ServerInterface.setup(new HMServerInterface());
logger.log(Level.INFO, "WorldEdit version " + getVersion() + " loaded");
}
@ -114,13 +121,4 @@ public class WorldEdit extends Plugin {
return version;
}
/**
* Returns the listener.
*
* @return
*/
public HMWorldEditListener getListener() {
return listener;
}
}

View File

@ -0,0 +1,101 @@
// $Id$
/*
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.util;
/**
* String utilities.
*
* @author sk89q
*/
public class StringUtil {
/**
* Trim a string if it is longer than a certain length.
*
* @param str
* @param len
* @return
*/
public static String trimLength(String str, int len) {
if (str.length() > len) {
return str.substring(0, len);
}
return str;
}
/**
* Join an array of strings into a string.
*
* @param str
* @param delimiter
* @param initialIndex
* @return
*/
public static String joinString(String[] str, String delimiter,
int initialIndex) {
if (str.length == 0) {
return "";
}
StringBuilder buffer = new StringBuilder(str[initialIndex]);
for (int i = initialIndex + 1; i < str.length; i++) {
buffer.append(delimiter).append(str[i]);
}
return buffer.toString();
}
/**
* Join an array of strings into a string.
*
* @param str
* @param delimiter
* @param initialIndex
* @return
*/
public static String joinString(Object[] str, String delimiter,
int initialIndex) {
if (str.length == 0) {
return "";
}
StringBuilder buffer = new StringBuilder(str[initialIndex].toString());
for (int i = initialIndex + 1; i < str.length; i++) {
buffer.append(delimiter).append(str[i].toString());
}
return buffer.toString();
}
/**
* Join an array of strings into a string.
*
* @param str
* @param delimiter
* @param initialIndex
* @return
*/
public static String joinString(int[] str, String delimiter,
int initialIndex) {
if (str.length == 0) {
return "";
}
StringBuilder buffer = new StringBuilder(Integer.toString(str[initialIndex]));
for (int i = initialIndex + 1; i < str.length; i++) {
buffer.append(delimiter).append(Integer.toString(str[i]));
}
return buffer.toString();
}
}

View File

@ -0,0 +1,101 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit;
/**
* Extension of Vector that supports being compared as ints (for accuracy).
*
* @author sk89q
*/
public class BlockWorldVector extends WorldVector {
/**
* Construct the Vector object.
*
* @param pt
*/
public BlockWorldVector(WorldVector pt) {
super(pt.getWorld(), pt);
}
/**
* Construct the Vector object.
*
* @param pt
*/
public BlockWorldVector(LocalWorld world, Vector pt) {
super(world, pt);
}
/**
* Construct the Vector object.
*
* @param pt
*/
public BlockWorldVector(LocalWorld world, int x, int y, int z) {
super(world, x, y, z);
}
/**
* Construct the Vector object.
*
* @param pt
*/
public BlockWorldVector(LocalWorld world, float x, float y, float z) {
super(world, x, y, z);
}
/**
* Construct the Vector object.
*
* @param pt
*/
public BlockWorldVector(LocalWorld world, double x, double y, double z) {
super(world, x, y, z);
}
/**
* Checks if another object is equivalent.
*
* @param obj
* @return whether the other object is equivalent
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof WorldVector)) {
return false;
}
WorldVector other = (WorldVector)obj;
return (int)other.x == (int)this.x && (int)other.y == (int)this.y
&& (int)other.z == (int)this.z;
}
/**
* Gets the hash code.
*
* @return hash code
*/
@Override
public int hashCode() {
return (Integer.valueOf((int)x).hashCode() >> 13) ^
(Integer.valueOf((int)y).hashCode() >> 7) ^
Integer.valueOf((int)z).hashCode();
}
}

View File

@ -1,4 +1,3 @@
package com.sk89q.worldedit;
// $Id$
/*
* WorldEdit
@ -18,7 +17,8 @@ package com.sk89q.worldedit;
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.sk89q.worldedit.*;
package com.sk89q.worldedit;
import com.sk89q.worldedit.blocks.*;
import com.sk89q.worldedit.data.*;
import org.jnbt.*;

View File

@ -29,7 +29,6 @@ import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.regions.*;
import com.sk89q.worldedit.bags.*;
import com.sk89q.worldedit.blocks.*;
@ -37,11 +36,11 @@ import com.sk89q.worldedit.patterns.*;
/**
* This class can wrap all block editing operations into one "edit session" that
* stores the state of the blocks before modification. This allows for easy
* undo or redo. In addition to that, this class can use a "queue mode" that
* will know how to handle some special types of items such as signs and
* torches. For example, torches must be placed only after there is already
* a block below it, otherwise the torch will be placed as an item.
* stores the state of the blocks before modification. This allows for easy undo
* or redo. In addition to that, this class can use a "queue mode" that will
* know how to handle some special types of items such as signs and torches. For
* example, torches must be placed only after there is already a block below it,
* otherwise the torch will be placed as an item.
*
* @author sk89q
*/
@ -55,31 +54,35 @@ public class EditSession {
* Server interface.
*/
private ServerInterface server;
/**
* World.
*/
private LocalWorld world;
/**
* Stores the original blocks before modification.
*/
private DoubleArrayList<BlockVector,BaseBlock> original =
new DoubleArrayList<BlockVector,BaseBlock>(true);
private DoubleArrayList<BlockVector, BaseBlock> original = new DoubleArrayList<BlockVector, BaseBlock>(
true);
/**
* Stores the current blocks.
*/
private DoubleArrayList<BlockVector,BaseBlock> current =
new DoubleArrayList<BlockVector,BaseBlock>(false);
private DoubleArrayList<BlockVector, BaseBlock> current = new DoubleArrayList<BlockVector, BaseBlock>(
false);
/**
* Blocks that should be placed before last.
*/
private DoubleArrayList<BlockVector,BaseBlock> queueAfter =
new DoubleArrayList<BlockVector,BaseBlock>(false);
private DoubleArrayList<BlockVector, BaseBlock> queueAfter = new DoubleArrayList<BlockVector, BaseBlock>(
false);
/**
* Blocks that should be placed last.
*/
private DoubleArrayList<BlockVector,BaseBlock> queueLast =
new DoubleArrayList<BlockVector,BaseBlock>(false);
private DoubleArrayList<BlockVector, BaseBlock> queueLast = new DoubleArrayList<BlockVector, BaseBlock>(
false);
/**
* The maximum number of blocks to change at a time. If this number is
* exceeded, a MaxChangedBlocksException exception will be
* raised. -1 indicates no limit.
* exceeded, a MaxChangedBlocksException exception will be raised. -1
* indicates no limit.
*/
private int maxBlocks = -1;
/**
@ -98,25 +101,38 @@ public class EditSession {
/**
* Construct the object with a maximum number of blocks.
*
* @param server
* @param world
* @param maxBlocks
*/
public EditSession(int maxBlocks) {
public EditSession(ServerInterface server, LocalWorld world, int maxBlocks) {
if (maxBlocks < -1) {
throw new IllegalArgumentException("Max blocks must be >= -1");
}
this.maxBlocks = maxBlocks;
server = ServerInterface.getInstance();
this.server = server;
this.world = world;
}
/**
* Construct the object with a maximum number of blocks and a block bag.
*
* @param server
* @param maxBlocks
* @blockBag
*/
public EditSession(int maxBlocks, BlockBag blockBag) {
public EditSession(ServerInterface server, LocalWorld world, int maxBlocks,
BlockBag blockBag) {
if (maxBlocks < -1) {
throw new IllegalArgumentException("Max blocks must be >= -1");
}
this.maxBlocks = maxBlocks;
this.blockBag = blockBag;
server = ServerInterface.getInstance();
this.server = server;
this.world = world;
}
/**
@ -133,14 +149,14 @@ public class EditSession {
}
// Clear the chest so that it doesn't drop items
if (server.getBlockType(pt) == 54 && blockBag == null) {
server.clearChest(pt);
if (server.getBlockType(world, pt) == 54 && blockBag == null) {
server.clearChest(world, pt);
}
int id = block.getID();
if (blockBag != null) {
int existing = server.getBlockType(pt);
int existing = server.getBlockType(world, pt);
if (id > 0) {
try {
@ -161,25 +177,25 @@ public class EditSession {
}
}
boolean result = server.setBlockType(pt, id);
boolean result = server.setBlockType(world, pt, id);
if (id != 0) {
if (BlockType.usesData(id)) {
server.setBlockData(pt, block.getData());
server.setBlockData(world, pt, block.getData());
}
// Signs
if (block instanceof SignBlock) {
SignBlock signBlock = (SignBlock) block;
String[] text = signBlock.getText();
server.setSignText(pt, text);
server.setSignText(world, pt, text);
// Chests
} else if (block instanceof ChestBlock && blockBag == null) {
ChestBlock chestBlock = (ChestBlock) block;
server.setChestContents(pt, chestBlock.getItems());
server.setChestContents(world, pt, chestBlock.getItems());
// Mob spawners
} else if (block instanceof MobSpawnerBlock) {
MobSpawnerBlock mobSpawnerblock = (MobSpawnerBlock) block;
server.setMobSpawnerType(pt, mobSpawnerblock.getMobType());
server.setMobSpawnerType(world, pt, mobSpawnerblock.getMobType());
}
}
@ -188,8 +204,8 @@ public class EditSession {
/**
* Sets the block at position x, y, z with a block type. If queue mode is
* enabled, blocks may not be actually set in world until flushQueue()
* is called.
* enabled, blocks may not be actually set in world until flushQueue() is
* called.
*
* @param pt
* @param block
@ -264,11 +280,12 @@ public class EditSession {
// In the case of the queue, the block may have not actually been
// changed yet
if (queued) {
/*BlockVector blockPt = pt.toBlockVector();
if (current.containsKey(blockPt)) {
return current.get(blockPt);
}*/
/*
* BlockVector blockPt = pt.toBlockVector();
*
* if (current.containsKey(blockPt)) { return current.get(blockPt);
* }
*/
}
return rawGetBlock(pt);
@ -281,21 +298,21 @@ public class EditSession {
* @return BaseBlock
*/
public BaseBlock rawGetBlock(Vector pt) {
int type = server.getBlockType(pt);
int data = server.getBlockData(pt);
int type = server.getBlockType(world, pt);
int data = server.getBlockData(world, pt);
// Sign
if (type == 63 || type == 68) {
String[] text = server.getSignText(pt);
String[] text = server.getSignText(world, pt);
return new SignBlock(type, data, text);
// Chest
} else if (type == 54) {
BaseItemStack[] items =
server.getChestContents(pt);
BaseItemStack[] items = server.getChestContents(world, pt);
return new ChestBlock(data, items);
// Mob spawner
} else if (type == 52) {
return new MobSpawnerBlock(data, server.getMobSpawnerType(pt));
return new MobSpawnerBlock(data,
server.getMobSpawnerType(world, pt));
} else {
return new BaseBlock(type, data);
}
@ -332,8 +349,8 @@ public class EditSession {
}
/**
* Get the maximum number of blocks that can be changed. -1 will be
* returned if disabled.
* Get the maximum number of blocks that can be changed. -1 will be returned
* if disabled.
*
* @return block change limit
*/
@ -344,7 +361,8 @@ public class EditSession {
/**
* Set the maximum number of blocks that can be changed.
*
* @param maxBlocks -1 to disable
* @param maxBlocks
* -1 to disable
*/
public void setBlockChangeLimit(int maxBlocks) {
if (maxBlocks < -1) {
@ -383,7 +401,9 @@ public class EditSession {
* Finish off the queue.
*/
public void flushQueue() {
if (!queued) { return; }
if (!queued) {
return;
}
for (Map.Entry<BlockVector, BaseBlock> entry : queueAfter) {
BlockVector pt = (BlockVector) entry.getKey();
@ -413,9 +433,8 @@ public class EditSession {
* @param recursive
* @return number of blocks affected
*/
public int fillXZ(Vector origin, BaseBlock block,
int radius, int depth, boolean recursive)
throws MaxChangedBlocksException {
public int fillXZ(Vector origin, BaseBlock block, int radius, int depth,
boolean recursive) throws MaxChangedBlocksException {
int affected = 0;
int originX = origin.getBlockX();
@ -518,9 +537,8 @@ public class EditSession {
* @param recursive
* @return number of blocks affected
*/
public int fillXZ(Vector origin, Pattern pattern,
int radius, int depth, boolean recursive)
throws MaxChangedBlocksException {
public int fillXZ(Vector origin, Pattern pattern, int radius, int depth,
boolean recursive) throws MaxChangedBlocksException {
int affected = 0;
int originX = origin.getBlockX();
@ -621,8 +639,8 @@ public class EditSession {
* @param height
* @return number of blocks affected
*/
public int removeAbove(Vector pos, int size, int height) throws
MaxChangedBlocksException {
public int removeAbove(Vector pos, int size, int height)
throws MaxChangedBlocksException {
int maxY = Math.min(127, pos.getBlockY() + height - 1);
size--;
int affected = 0;
@ -655,8 +673,8 @@ public class EditSession {
* @param height
* @return number of blocks affected
*/
public int removeBelow(Vector pos, int size, int height) throws
MaxChangedBlocksException {
public int removeBelow(Vector pos, int size, int height)
throws MaxChangedBlocksException {
int minY = Math.max(0, pos.getBlockY() - height);
size--;
int affected = 0;
@ -689,8 +707,8 @@ public class EditSession {
* @param size
* @return number of blocks affected
*/
public int removeNear(Vector pos, int blockType, int size) throws
MaxChangedBlocksException {
public int removeNear(Vector pos, int blockType, int size)
throws MaxChangedBlocksException {
int affected = 0;
BaseBlock air = new BaseBlock(0);
@ -807,13 +825,14 @@ public class EditSession {
* Replaces all the blocks of a type inside a region to another block type.
*
* @param region
* @param fromBlockType -1 for non-air
* @param fromBlockType
* -1 for non-air
* @param toBlockType
* @return number of blocks affected
* @throws MaxChangedBlocksException
*/
public int replaceBlocks(Region region, Set<Integer> fromBlockTypes, BaseBlock toBlock)
throws MaxChangedBlocksException {
public int replaceBlocks(Region region, Set<Integer> fromBlockTypes,
BaseBlock toBlock) throws MaxChangedBlocksException {
int affected = 0;
if (region instanceof CuboidRegion) {
@ -834,9 +853,9 @@ public class EditSession {
Vector pt = new Vector(x, y, z);
int curBlockType = getBlock(pt).getID();
if ((fromBlockTypes == null && curBlockType != 0) ||
(fromBlockTypes != null &&
fromBlockTypes.contains(curBlockType))) {
if ((fromBlockTypes == null && curBlockType != 0)
|| (fromBlockTypes != null && fromBlockTypes
.contains(curBlockType))) {
if (setBlock(pt, toBlock)) {
affected++;
}
@ -848,8 +867,8 @@ public class EditSession {
for (Vector pt : region) {
int curBlockType = getBlock(pt).getID();
if (fromBlockTypes == null && curBlockType != 0 ||
fromBlockTypes.contains(curBlockType)) {
if (fromBlockTypes == null && curBlockType != 0
|| fromBlockTypes.contains(curBlockType)) {
if (setBlock(pt, toBlock)) {
affected++;
}
@ -864,14 +883,14 @@ public class EditSession {
* Replaces all the blocks of a type inside a region to another block type.
*
* @param region
* @param fromBlockType -1 for non-air
* @param fromBlockType
* -1 for non-air
* @param pattern
* @return number of blocks affected
* @throws MaxChangedBlocksException
*/
public int replaceBlocks(Region region, Set<Integer> fromBlockTypes,
Pattern pattern)
throws MaxChangedBlocksException {
Pattern pattern) throws MaxChangedBlocksException {
int affected = 0;
if (region instanceof CuboidRegion) {
@ -892,9 +911,9 @@ public class EditSession {
Vector pt = new Vector(x, y, z);
int curBlockType = getBlock(pt).getID();
if ((fromBlockTypes == null && curBlockType != 0) ||
(fromBlockTypes != null &&
fromBlockTypes.contains(curBlockType))) {
if ((fromBlockTypes == null && curBlockType != 0)
|| (fromBlockTypes != null && fromBlockTypes
.contains(curBlockType))) {
if (setBlock(pt, pattern.next(pt))) {
affected++;
}
@ -906,8 +925,8 @@ public class EditSession {
for (Vector pt : region) {
int curBlockType = getBlock(pt).getID();
if (fromBlockTypes == null && curBlockType != 0 ||
fromBlockTypes.contains(curBlockType)) {
if (fromBlockTypes == null && curBlockType != 0
|| fromBlockTypes.contains(curBlockType)) {
if (setBlock(pt, pattern.next(pt))) {
affected++;
}
@ -942,23 +961,35 @@ public class EditSession {
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
if (setBlock(new Vector(x, y, minZ), block)) { affected++; }
if (setBlock(new Vector(x, y, maxZ), block)) { affected++; }
if (setBlock(new Vector(x, y, minZ), block)) {
affected++;
}
if (setBlock(new Vector(x, y, maxZ), block)) {
affected++;
}
affected++;
}
}
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
if (setBlock(new Vector(minX, y, z), block)) { affected++; }
if (setBlock(new Vector(maxX, y, z), block)) { affected++; }
if (setBlock(new Vector(minX, y, z), block)) {
affected++;
}
if (setBlock(new Vector(maxX, y, z), block)) {
affected++;
}
}
}
for (int z = minZ; z <= maxZ; z++) {
for (int x = minX; x <= maxX; x++) {
if (setBlock(new Vector(x, minY, z), block)) { affected++; }
if (setBlock(new Vector(x, maxY, z), block)) { affected++; }
if (setBlock(new Vector(x, minY, z), block)) {
affected++;
}
if (setBlock(new Vector(x, maxY, z), block)) {
affected++;
}
}
}
@ -989,16 +1020,24 @@ public class EditSession {
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
if (setBlock(new Vector(x, y, minZ), block)) { affected++; }
if (setBlock(new Vector(x, y, maxZ), block)) { affected++; }
if (setBlock(new Vector(x, y, minZ), block)) {
affected++;
}
if (setBlock(new Vector(x, y, maxZ), block)) {
affected++;
}
affected++;
}
}
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
if (setBlock(new Vector(minX, y, z), block)) { affected++; }
if (setBlock(new Vector(maxX, y, z), block)) { affected++; }
if (setBlock(new Vector(minX, y, z), block)) {
affected++;
}
if (setBlock(new Vector(maxX, y, z), block)) {
affected++;
}
}
}
@ -1057,9 +1096,8 @@ public class EditSession {
* @return number of blocks affected
* @throws MaxChangedBlocksException
*/
public int stackCuboidRegion(Region region, Vector dir,
int count, boolean copyAir)
throws MaxChangedBlocksException {
public int stackCuboidRegion(Region region, Vector dir, int count,
boolean copyAir) throws MaxChangedBlocksException {
int affected = 0;
Vector min = region.getMinimumPoint();
@ -1083,10 +1121,9 @@ public class EditSession {
if (!block.isAir() || copyAir) {
for (int i = 1; i <= count; i++) {
Vector pos = new Vector(
x + xs * dir.getBlockX() * i,
y + ys * dir.getBlockY() * i,
z + zs * dir.getBlockZ() * i);
Vector pos = new Vector(x + xs * dir.getBlockX()
* i, y + ys * dir.getBlockY() * i, z + zs
* dir.getBlockZ() * i);
if (setBlock(pos, block)) {
affected++;
@ -1111,8 +1148,8 @@ public class EditSession {
* @return number of blocks moved
* @throws MaxChangedBlocksException
*/
public int moveCuboidRegion(Region region, Vector dir,
int distance, boolean copyAir, BaseBlock replace)
public int moveCuboidRegion(Region region, Vector dir, int distance,
boolean copyAir, BaseBlock replace)
throws MaxChangedBlocksException {
int affected = 0;
@ -1146,8 +1183,10 @@ public class EditSession {
// Don't want to replace the old block if it's in
// the new area
if (x >= newMin.getBlockX() && x <= newMax.getBlockX()
&& y >= newMin.getBlockY() && y <= newMax.getBlockY()
&& z >= newMin.getBlockZ() && z <= newMax.getBlockZ()) {
&& y >= newMin.getBlockY()
&& y <= newMax.getBlockY()
&& z >= newMin.getBlockZ()
&& z <= newMax.getBlockZ()) {
} else {
setBlock(pos, replace);
}
@ -1172,7 +1211,8 @@ public class EditSession {
* @return number of blocks affected
* @throws MaxChangedBlocksException
*/
public int drainArea(Vector pos, int radius) throws MaxChangedBlocksException {
public int drainArea(Vector pos, int radius)
throws MaxChangedBlocksException {
int affected = 0;
HashSet<BlockVector> visited = new HashSet<BlockVector>();
@ -1303,8 +1343,8 @@ public class EditSession {
* @param block
* @throws MaxChangedBlocksException
*/
private int makeHCylinderPoints(Vector center, int x, int z,
int height, BaseBlock block) throws MaxChangedBlocksException {
private int makeHCylinderPoints(Vector center, int x, int z, int height,
BaseBlock block) throws MaxChangedBlocksException {
int affected = 0;
if (x == 0) {
@ -1350,8 +1390,8 @@ public class EditSession {
* @return number of blocks set
* @throws MaxChangedBlocksException
*/
public int makeHollowCylinder(Vector pos, BaseBlock block,
int radius, int height) throws MaxChangedBlocksException {
public int makeHollowCylinder(Vector pos, BaseBlock block, int radius,
int height) throws MaxChangedBlocksException {
int x = 0;
int z = radius;
int d = (5 - radius * 4) / 4;
@ -1398,8 +1438,8 @@ public class EditSession {
* @param block
* @throws MaxChangedBlocksException
*/
private int makeCylinderPoints(Vector center, int x, int z,
int height, BaseBlock block) throws MaxChangedBlocksException {
private int makeCylinderPoints(Vector center, int x, int z, int height,
BaseBlock block) throws MaxChangedBlocksException {
int affected = 0;
if (x == z) {
@ -1437,8 +1477,8 @@ public class EditSession {
* @return number of blocks set
* @throws MaxChangedBlocksException
*/
public int makeCylinder(Vector pos, BaseBlock block,
int radius, int height) throws MaxChangedBlocksException {
public int makeCylinder(Vector pos, BaseBlock block, int radius, int height)
throws MaxChangedBlocksException {
int x = 0;
int z = radius;
int d = (5 - radius * 4) / 4;
@ -1485,8 +1525,8 @@ public class EditSession {
* @return number of blocks changed
* @throws MaxChangedBlocksException
*/
public int makeSphere(Vector pos, BaseBlock block, int radius, boolean filled)
throws MaxChangedBlocksException {
public int makeSphere(Vector pos, BaseBlock block, int radius,
boolean filled) throws MaxChangedBlocksException {
int affected = 0;
for (int x = 0; x <= radius; x++) {
@ -1496,14 +1536,30 @@ public class EditSession {
double d = vec.distance(pos);
if (d <= radius + 0.5 && (filled || d >= radius - 0.5)) {
if (setBlock(vec, block)) { affected++; }
if (setBlock(pos.add(-x, y, z), block)) { affected++; }
if (setBlock(pos.add(x, -y, z), block)) { affected++; }
if (setBlock(pos.add(x, y, -z), block)) { affected++; }
if (setBlock(pos.add(-x, -y, z), block)) { affected++; }
if (setBlock(pos.add(x, -y, -z), block)) { affected++; }
if (setBlock(pos.add(-x, y, -z), block)) { affected++; }
if (setBlock(pos.add(-x, -y, -z), block)) { affected++; }
if (setBlock(vec, block)) {
affected++;
}
if (setBlock(pos.add(-x, y, z), block)) {
affected++;
}
if (setBlock(pos.add(x, -y, z), block)) {
affected++;
}
if (setBlock(pos.add(x, y, -z), block)) {
affected++;
}
if (setBlock(pos.add(-x, -y, z), block)) {
affected++;
}
if (setBlock(pos.add(x, -y, -z), block)) {
affected++;
}
if (setBlock(pos.add(-x, y, -z), block)) {
affected++;
}
if (setBlock(pos.add(-x, -y, -z), block)) {
affected++;
}
}
}
}
@ -1555,8 +1611,8 @@ public class EditSession {
|| id == 53 // Wood steps
|| id == 55 // Redstone wire
|| id == 59 // Crops
|| (id >= 63 && id <= 72)
|| id == 75 // Redstone torch
|| (id >= 63 && id <= 72) || id == 75 // Redstone
// torch
|| id == 76 // Redstone torch
|| id == 77 // Stone button
|| id == 78 // Snow
@ -1599,7 +1655,8 @@ public class EditSession {
*
* @param pos
* @param block
* @param c 0-1 chance
* @param c
* 0-1 chance
* @return whether a block was changed
*/
private boolean setChanceBlockIfAir(Vector pos, BaseBlock block, double c)
@ -1637,8 +1694,10 @@ public class EditSession {
*/
private void makePumpkinPatchVine(Vector basePos, Vector pos)
throws MaxChangedBlocksException {
if (pos.distance(basePos) > 4) return;
if (getBlock(pos).getID() != 0) return;
if (pos.distance(basePos) > 4)
return;
if (getBlock(pos).getID() != 0)
return;
for (int i = -1; i > -3; i--) {
Vector testPos = pos.add(0, i, 0);
@ -1655,20 +1714,28 @@ public class EditSession {
int h = prng.nextInt(3) - 1;
if (t == 0) {
if (prng.nextBoolean()) makePumpkinPatchVine(basePos, pos.add(1, 0, 0));
if (prng.nextBoolean()) setBlockIfAir(pos.add(1, h, -1), new BaseBlock(18));
if (prng.nextBoolean())
makePumpkinPatchVine(basePos, pos.add(1, 0, 0));
if (prng.nextBoolean())
setBlockIfAir(pos.add(1, h, -1), new BaseBlock(18));
setBlockIfAir(pos.add(0, 0, -1), new BaseBlock(86));
} else if (t == 1) {
if (prng.nextBoolean()) makePumpkinPatchVine(basePos, pos.add(0, 0, 1));
if (prng.nextBoolean()) setBlockIfAir(pos.add(1, h, 0), new BaseBlock(18));
if (prng.nextBoolean())
makePumpkinPatchVine(basePos, pos.add(0, 0, 1));
if (prng.nextBoolean())
setBlockIfAir(pos.add(1, h, 0), new BaseBlock(18));
setBlockIfAir(pos.add(1, 0, 1), new BaseBlock(86));
} else if (t == 2) {
if (prng.nextBoolean()) makePumpkinPatchVine(basePos, pos.add(0, 0, -1));
if (prng.nextBoolean()) setBlockIfAir(pos.add(-1, h, 0), new BaseBlock(18));
if (prng.nextBoolean())
makePumpkinPatchVine(basePos, pos.add(0, 0, -1));
if (prng.nextBoolean())
setBlockIfAir(pos.add(-1, h, 0), new BaseBlock(18));
setBlockIfAir(pos.add(-1, 0, 1), new BaseBlock(86));
} else if (t == 3) {
if (prng.nextBoolean()) makePumpkinPatchVine(basePos, pos.add(-1, 0, 0));
if (prng.nextBoolean()) setBlockIfAir(pos.add(-1, h, -1), new BaseBlock(18));
if (prng.nextBoolean())
makePumpkinPatchVine(basePos, pos.add(-1, 0, 0));
if (prng.nextBoolean())
setBlockIfAir(pos.add(-1, h, -1), new BaseBlock(18));
setBlockIfAir(pos.add(-1, 0, -1), new BaseBlock(86));
}
}
@ -1684,13 +1751,17 @@ public class EditSession {
throws MaxChangedBlocksException {
int affected = 0;
for (int x = basePos.getBlockX() - size; x <= basePos.getBlockX() + size; x++) {
for (int z = basePos.getBlockZ() - size; z <= basePos.getBlockZ() + size; z++) {
for (int x = basePos.getBlockX() - size; x <= basePos.getBlockX()
+ size; x++) {
for (int z = basePos.getBlockZ() - size; z <= basePos.getBlockZ()
+ size; z++) {
// Don't want to be in the ground
if (!getBlock(new Vector(x, basePos.getBlockY(), z)).isAir())
continue;
// The gods don't want a pumpkin patch here
if (Math.random() < 0.98) { continue; }
if (Math.random() < 0.98) {
continue;
}
for (int y = basePos.getBlockY(); y >= basePos.getBlockY() - 10; y--) {
// Check if we hit the ground
@ -1722,13 +1793,17 @@ public class EditSession {
boolean pineTree) throws MaxChangedBlocksException {
int affected = 0;
for (int x = basePos.getBlockX() - size; x <= basePos.getBlockX() + size; x++) {
for (int z = basePos.getBlockZ() - size; z <= basePos.getBlockZ() + size; z++) {
for (int x = basePos.getBlockX() - size; x <= basePos.getBlockX()
+ size; x++) {
for (int z = basePos.getBlockZ() - size; z <= basePos.getBlockZ()
+ size; z++) {
// Don't want to be in the ground
if (!getBlock(new Vector(x, basePos.getBlockY(), z)).isAir())
continue;
// The gods don't want a tree here
if (Math.random() >= density) { continue; } // def 0.05
if (Math.random() >= density) {
continue;
} // def 0.05
for (int y = basePos.getBlockY(); y >= basePos.getBlockY() - 10; y--) {
// Check if we hit the ground
@ -1737,7 +1812,8 @@ public class EditSession {
if (pineTree) {
makePineTree(new Vector(x, y + 1, z));
} else {
server.generateTree(this, new Vector(x, y + 1, z));
server.generateTree(this, world,
new Vector(x, y + 1, z));
}
affected++;
break;
@ -1756,8 +1832,7 @@ public class EditSession {
*
* @param basePos
*/
private void makePineTree(Vector basePos)
throws MaxChangedBlocksException {
private void makePineTree(Vector basePos) throws MaxChangedBlocksException {
int trunkHeight = (int) Math.floor(Math.random() * 2) + 3;
int height = (int) Math.floor(Math.random() * 5) + 8;
@ -1861,10 +1936,8 @@ public class EditSession {
* @return
*/
public List<Countable<Integer>> getBlockDistribution(Region region) {
List<Countable<Integer>> distribution
= new ArrayList<Countable<Integer>>();
Map<Integer,Countable<Integer>> map =
new HashMap<Integer,Countable<Integer>>();
List<Countable<Integer>> distribution = new ArrayList<Countable<Integer>>();
Map<Integer, Countable<Integer>> map = new HashMap<Integer, Countable<Integer>>();
if (region instanceof CuboidRegion) {
// Doing this for speed
@ -1920,8 +1993,10 @@ public class EditSession {
*
* @param x
* @param z
* @param minY minimal height
* @param maxY maximal height
* @param minY
* minimal height
* @param maxY
* maximal height
* @return height of highest block found or 'minY'
*/
@ -1974,7 +2049,8 @@ public class EditSession {
}
/**
* @param blockBag the blockBag to set
* @param blockBag
* the blockBag to set
*/
public void setBlockBag(BlockBag blockBag) {
this.blockBag = blockBag;

View File

@ -0,0 +1,59 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit;
import java.util.Set;
import com.sk89q.worldedit.snapshots.SnapshotRepository;
/**
* Represents WorldEdit's configuration.
*
* @author sk89q
*/
public abstract class LocalConfiguration {
protected static final int[] defaultDisallowedBlocks = new int[] {
6, 7, 14, 15, 16, 21, 22, 23, 24, 25, 26, 27, 28, 29, 39, 31,
32, 33, 34, 36, 37, 38, 39, 40, 46, 50, 51, 56, 59, 69, 73, 74,
75, 76, 77, 81, 83
};
public boolean profile = false;
public Set<Integer> disallowedBlocks = null;
public int defaultChangeLimit = -1;
public int maxChangeLimit = -1;
public String shellSaveType = null;
public SnapshotRepository snapshotRepo = null;
public int maxRadius = -1;
public int maxSuperPickaxeSize = 5;
public boolean logComands = false;
public boolean registerHelp = true;
public int wandItem = 271;
public boolean superPickaxeDrop = true;
public boolean superPickaxeManyDrop = true;
public boolean noDoubleSlash = false;
public boolean useInventory = false;
public boolean useInventoryOverride = false;
/**
* Loads the configuration.
*/
public abstract void load();
}

View File

@ -26,7 +26,7 @@ import com.sk89q.worldedit.blocks.BlockType;
*
* @author sk89q
*/
public abstract class WorldEditPlayer {
public abstract class LocalPlayer {
/**
* Directions.
*/
@ -48,9 +48,11 @@ public abstract class WorldEditPlayer {
/**
* Construct the object.
*
* @param server
*/
protected WorldEditPlayer() {
server = ServerInterface.getInstance();
protected LocalPlayer(ServerInterface server) {
this.server = server;
}
/**
@ -72,7 +74,7 @@ public abstract class WorldEditPlayer {
*
* @param searchPos search position
*/
public void findFreePosition(Vector searchPos) {
public void findFreePosition(LocalWorld world, Vector searchPos) {
int x = searchPos.getBlockX();
int y = Math.max(0, searchPos.getBlockY());
int origY = y;
@ -81,7 +83,8 @@ public abstract class WorldEditPlayer {
byte free = 0;
while (y <= 129) {
if (BlockType.canPassThrough(server.getBlockType(new Vector(x, y, z)))) {
if (BlockType.canPassThrough(server.getBlockType(world,
new Vector(x, y, z)))) {
free++;
} else {
free = 0;
@ -106,7 +109,7 @@ public abstract class WorldEditPlayer {
* that free position.
*/
public void findFreePosition() {
findFreePosition(getBlockIn());
findFreePosition(getPosition().getWorld(), getBlockIn());
}
/**
@ -119,12 +122,13 @@ public abstract class WorldEditPlayer {
int x = pos.getBlockX();
int y = Math.max(0, pos.getBlockY());
int z = pos.getBlockZ();
LocalWorld world = getPosition().getWorld();
byte free = 0;
byte spots = 0;
while (y <= 129) {
if (BlockType.canPassThrough(server.getBlockType(new Vector(x, y, z)))) {
if (BlockType.canPassThrough(server.getBlockType(world, new Vector(x, y, z)))) {
free++;
} else {
free = 0;
@ -133,7 +137,7 @@ public abstract class WorldEditPlayer {
if (free == 2) {
spots++;
if (spots == 2) {
int type = server.getBlockType(new Vector(x, y - 2, z));
int type = server.getBlockType(world, new Vector(x, y - 2, z));
// Don't get put in lava!
if (type == 10 || type == 11) {
@ -161,11 +165,12 @@ public abstract class WorldEditPlayer {
int x = pos.getBlockX();
int y = Math.max(0, pos.getBlockY() - 1);
int z = pos.getBlockZ();
LocalWorld world = getPosition().getWorld();
byte free = 0;
while (y >= 1) {
if (BlockType.canPassThrough(server.getBlockType(new Vector(x, y, z)))) {
if (BlockType.canPassThrough(server.getBlockType(world, new Vector(x, y, z)))) {
free++;
} else {
free = 0;
@ -176,7 +181,7 @@ public abstract class WorldEditPlayer {
// lightly and also check to see if there's something to
// stand upon
while (y >= 0) {
int type = server.getBlockType(new Vector(x, y, z));
int type = server.getBlockType(world, new Vector(x, y, z));
// Don't want to end up in lava
if (type != 0 && type != 10 && type != 11) {
@ -209,17 +214,18 @@ public abstract class WorldEditPlayer {
int initialY = Math.max(0, pos.getBlockY());
int y = Math.max(0, pos.getBlockY() + 2);
int z = pos.getBlockZ();
LocalWorld world = getPosition().getWorld();
// No free space above
if (server.getBlockType(new Vector(x, y, z)) != 0) {
if (server.getBlockType(world, new Vector(x, y, z)) != 0) {
return false;
}
while (y <= 127) {
// Found a ceiling!
if (!BlockType.canPassThrough(server.getBlockType(new Vector(x, y, z)))) {
if (!BlockType.canPassThrough(server.getBlockType(world, new Vector(x, y, z)))) {
int platformY = Math.max(initialY, y - 3 - clearance);
server.setBlockType(new Vector(x, platformY, z),
server.setBlockType(world, new Vector(x, platformY, z),
BlockType.GLASS.getID());
setPosition(new Vector(x + 0.5, platformY + 1, z + 0.5));
return true;
@ -244,14 +250,15 @@ public abstract class WorldEditPlayer {
int y = Math.max(0, pos.getBlockY() + 1);
int z = pos.getBlockZ();
int maxY = Math.min(128, initialY + distance);
LocalWorld world = getPosition().getWorld();
while (y <= 129) {
if (!BlockType.canPassThrough(server.getBlockType(new Vector(x, y, z)))) {
if (!BlockType.canPassThrough(server.getBlockType(world, new Vector(x, y, z)))) {
break; // Hit something
} else if (y > maxY + 1) {
break;
} else if (y == maxY + 1) {
server.setBlockType(new Vector(x, y - 2, z),
server.setBlockType(world, new Vector(x, y - 2, z),
BlockType.GLASS.getID());
setPosition(new Vector(x + 0.5, y - 1, z + 0.5));
return true;
@ -268,8 +275,8 @@ public abstract class WorldEditPlayer {
*
* @return point
*/
public Vector getBlockIn() {
return getPosition().toBlockVector();
public WorldVector getBlockIn() {
return getPosition();
}
/**
@ -277,8 +284,9 @@ public abstract class WorldEditPlayer {
*
* @return point
*/
public Vector getBlockOn() {
return getPosition().subtract(0, 1, 0).toBlockVector();
public WorldVector getBlockOn() {
WorldVector pos = getPosition();
return new WorldVector(pos.getWorld(), pos.subtract(0, 1, 0));
}
/**
@ -287,7 +295,7 @@ public abstract class WorldEditPlayer {
* @param range
* @return point
*/
public abstract Vector getBlockTrace(int range);
public abstract WorldVector getBlockTrace(int range);
/**
* Get the point of the block being looked at. May return null.
@ -295,14 +303,14 @@ public abstract class WorldEditPlayer {
* @param range
* @return point
*/
public abstract Vector getSolidBlockTrace(int range);
public abstract WorldVector getSolidBlockTrace(int range);
/**
* Get the player's cardinal direction (N, W, NW, etc.). May return null.
*
* @return
*/
public WorldEditPlayer.DIRECTION getCardinalDirection() {
public LocalPlayer.DIRECTION getCardinalDirection() {
// From hey0's code
double rot = (getYaw() - 90) % 360;
if (rot < 0) {
@ -317,25 +325,25 @@ public abstract class WorldEditPlayer {
* @param rot
* @return
*/
private static WorldEditPlayer.DIRECTION getDirection(double rot) {
private static LocalPlayer.DIRECTION getDirection(double rot) {
if (0 <= rot && rot < 22.5) {
return WorldEditPlayer.DIRECTION.NORTH;
return LocalPlayer.DIRECTION.NORTH;
} else if (22.5 <= rot && rot < 67.5) {
return WorldEditPlayer.DIRECTION.NORTH_EAST;
return LocalPlayer.DIRECTION.NORTH_EAST;
} else if (67.5 <= rot && rot < 112.5) {
return WorldEditPlayer.DIRECTION.EAST;
return LocalPlayer.DIRECTION.EAST;
} else if (112.5 <= rot && rot < 157.5) {
return WorldEditPlayer.DIRECTION.SOUTH_EAST;
return LocalPlayer.DIRECTION.SOUTH_EAST;
} else if (157.5 <= rot && rot < 202.5) {
return WorldEditPlayer.DIRECTION.SOUTH;
return LocalPlayer.DIRECTION.SOUTH;
} else if (202.5 <= rot && rot < 247.5) {
return WorldEditPlayer.DIRECTION.SOUTH_WEST;
return LocalPlayer.DIRECTION.SOUTH_WEST;
} else if (247.5 <= rot && rot < 292.5) {
return WorldEditPlayer.DIRECTION.WEST;
return LocalPlayer.DIRECTION.WEST;
} else if (292.5 <= rot && rot < 337.5) {
return WorldEditPlayer.DIRECTION.NORTH_WEST;
return LocalPlayer.DIRECTION.NORTH_WEST;
} else if (337.5 <= rot && rot < 360.0) {
return WorldEditPlayer.DIRECTION.NORTH;
return LocalPlayer.DIRECTION.NORTH;
} else {
return null;
}
@ -360,7 +368,14 @@ public abstract class WorldEditPlayer {
*
* @return point
*/
public abstract Vector getPosition();
public abstract WorldVector getPosition();
/**
* Get the player's world.
*
* @return point
*/
public abstract LocalWorld getWorld();
/**
* Get the player's view pitch.
@ -463,6 +478,15 @@ public abstract class WorldEditPlayer {
*/
public abstract boolean hasPermission(String perm);
/**
* Returns true if the player can destroy bedrock.
*
* @return
*/
public boolean canDestroyBedrock() {
return hasPermission("worldeditbedrock");
}
/**
* Returns true if equal.
*
@ -471,10 +495,10 @@ public abstract class WorldEditPlayer {
*/
@Override
public boolean equals(Object other) {
if (!(other instanceof WorldEditPlayer)) {
if (!(other instanceof LocalPlayer)) {
return false;
}
WorldEditPlayer other2 = (WorldEditPlayer)other;
LocalPlayer other2 = (LocalPlayer)other;
return other2.getName().equals(getName());
}

View File

@ -21,6 +21,8 @@ package com.sk89q.worldedit;
import java.util.LinkedList;
import com.sk89q.worldedit.snapshots.Snapshot;
import com.sk89q.worldedit.superpickaxe.SinglePickaxe;
import com.sk89q.worldedit.superpickaxe.SuperPickaxeMode;
import com.sk89q.worldedit.bags.BlockBag;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.CuboidRegion;
@ -29,25 +31,9 @@ import com.sk89q.worldedit.regions.CuboidRegion;
*
* @author sk89q
*/
public class WorldEditSession {
/**
* List of super pick axe modes.
*/
public static enum SuperPickaxeMode {
SINGLE,
SAME_TYPE_RECURSIVE,
SAME_TYPE_AREA
};
/**
* List of tools.
*/
public static enum Tool {
NONE,
INFO,
TREE,
}
public class LocalSession {
public static final int MAX_HISTORY_SIZE = 15;
private boolean placeAtPos1 = false;
private Vector pos1, pos2;
private Region region;
@ -55,10 +41,9 @@ public class WorldEditSession {
private int historyPointer = 0;
private CuboidClipboard clipboard;
private boolean toolControl = true;
private boolean superPickAxe = false;
private SuperPickaxeMode superPickaxeMode = SuperPickaxeMode.SINGLE;
private Tool tool = Tool.NONE;
private int superPickaxeRange = 3;
private boolean superPickaxe = false;
private SuperPickaxeMode superPickaxeMode = new SinglePickaxe();
private SuperPickaxeMode tool;
private int maxBlocksChanged = -1;
private boolean useInventory;
private Snapshot snapshot;
@ -291,25 +276,25 @@ public class WorldEditSession {
* @return status
*/
public boolean hasSuperPickAxe() {
return superPickAxe;
return superPickaxe;
}
/**
* Enable super pick axe.
*
* @param superPickAxe
* @param superPickaxe
*/
public void enableSuperPickAxe() {
superPickAxe = true;
superPickaxe = true;
}
/**
* Disable super pick axe.
*
* @param superPickAxe
* @param superPickaxe
*/
public void disableSuperPickAxe() {
superPickAxe = false;
superPickaxe = false;
}
/**
@ -318,15 +303,15 @@ public class WorldEditSession {
* @return status
*/
public boolean toggleSuperPickAxe() {
superPickAxe = !superPickAxe;
return superPickAxe;
superPickaxe = !superPickaxe;
return superPickaxe;
}
/**
* @return position
* @throws IncompleteRegionException
*/
public Vector getPlacementPosition(WorldEditPlayer player)
public Vector getPlacementPosition(LocalPlayer player)
throws IncompleteRegionException {
if (!placeAtPos1) {
return player.getBlockIn();
@ -350,7 +335,7 @@ public class WorldEditSession {
* @param player
* @return
*/
public BlockBag getBlockBag(WorldEditPlayer player) {
public BlockBag getBlockBag(LocalPlayer player) {
if (!useInventory) {
return null;
}
@ -385,31 +370,17 @@ public class WorldEditSession {
this.superPickaxeMode = superPickaxeMode;
}
/**
* @return the superPickaxeRange
*/
public int getSuperPickaxeRange() {
return superPickaxeRange;
}
/**
* @param superPickaxeRange the superPickaxeRange to set
*/
public void setSuperPickaxeRange(int superPickaxeRange) {
this.superPickaxeRange = superPickaxeRange;
}
/**
* @return the tool
*/
public Tool getTool() {
public SuperPickaxeMode getTool() {
return tool;
}
/**
* @param tool the tool to set
*/
public void setTool(Tool tool) {
public void setTool(SuperPickaxeMode tool) {
this.tool = tool;
}

View File

@ -0,0 +1,41 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit;
/**
* Represents a world.
*
* @author sk89q
*/
public abstract class LocalWorld {
/**
* Compare if the other world is equal.
*
* @param other
* @return
*/
public abstract boolean equals(Object other);
/**
* Hash code.
*
* @return
*/
public abstract int hashCode();
}

View File

@ -26,28 +26,6 @@ import com.sk89q.worldedit.blocks.BaseItemStack;
* @author sk89q
*/
public abstract class ServerInterface {
/**
* Instance.
*/
private static ServerInterface instance;
/**
* Get the current instance.
*
* @return
*/
public static ServerInterface getInstance() {
return instance;
}
/**
* Set up an instance.
* @param instance
*/
public static void setup(ServerInterface instance) {
ServerInterface.instance = instance;
}
/**
* Set block type.
*
@ -55,7 +33,7 @@ public abstract class ServerInterface {
* @param type
* @return
*/
public abstract boolean setBlockType(Vector pt, int type);
public abstract boolean setBlockType(LocalWorld world, Vector pt, int type);
/**
* Get block type.
@ -63,7 +41,7 @@ public abstract class ServerInterface {
* @param pt
* @return
*/
public abstract int getBlockType(Vector pt);
public abstract int getBlockType(LocalWorld world, Vector pt);
/**
* Set block data.
@ -72,7 +50,7 @@ public abstract class ServerInterface {
* @param data
* @return
*/
public abstract void setBlockData(Vector pt, int data);
public abstract void setBlockData(LocalWorld world, Vector pt, int data);
/**
* Get block data.
@ -80,7 +58,7 @@ public abstract class ServerInterface {
* @param pt
* @return
*/
public abstract int getBlockData(Vector pt);
public abstract int getBlockData(LocalWorld world, Vector pt);
/**
* Set sign text.
@ -88,7 +66,7 @@ public abstract class ServerInterface {
* @param pt
* @param text
*/
public abstract void setSignText(Vector pt, String[] text);
public abstract void setSignText(LocalWorld world, Vector pt, String[] text);
/**
* Get sign text.
@ -96,7 +74,7 @@ public abstract class ServerInterface {
* @param pt
* @return
*/
public abstract String[] getSignText(Vector pt);
public abstract String[] getSignText(LocalWorld world, Vector pt);
/**
* Gets the contents of chests. Will return null if the chest does not
@ -105,7 +83,7 @@ public abstract class ServerInterface {
* @param pt
* @return
*/
public abstract BaseItemStack[] getChestContents(Vector pt);
public abstract BaseItemStack[] getChestContents(LocalWorld world, Vector pt);
/**
* Sets a chest slot.
@ -114,14 +92,15 @@ public abstract class ServerInterface {
* @param contents
* @return
*/
public abstract boolean setChestContents(Vector pt, BaseItemStack[] contents);
public abstract boolean setChestContents(LocalWorld world, Vector pt,
BaseItemStack[] contents);
/**
* Clear a chest's contents.
*
* @param pt
*/
public abstract boolean clearChest(Vector pt);
public abstract boolean clearChest(LocalWorld world, Vector pt);
/**
* Checks if a mob type is valid.
@ -137,7 +116,8 @@ public abstract class ServerInterface {
* @param pt
* @param mobType
*/
public abstract void setMobSpawnerType(Vector pt, String mobType);
public abstract void setMobSpawnerType(LocalWorld world, Vector pt,
String mobType);
/**
* Get mob spawner mob type. May return an empty string.
@ -145,7 +125,7 @@ public abstract class ServerInterface {
* @param pt
* @param mobType
*/
public abstract String getMobSpawnerType(Vector pt);
public abstract String getMobSpawnerType(LocalWorld world, Vector pt);
/**
* Generate a tree at a location.
@ -153,7 +133,8 @@ public abstract class ServerInterface {
* @param pt
* @return
*/
public abstract boolean generateTree(EditSession editSession, Vector pt);
public abstract boolean generateTree(EditSession editSession,
LocalWorld world, Vector pt);
/**
* Drop an item.
@ -163,7 +144,8 @@ public abstract class ServerInterface {
* @param count
* @param times
*/
public abstract void dropItem(Vector pt, int type, int count, int times);
public abstract void dropItem(LocalWorld world, Vector pt, int type,
int count, int times);
/**
* Drop an item.
@ -173,7 +155,8 @@ public abstract class ServerInterface {
* @param count
* @param times
*/
public abstract void dropItem(Vector pt, int type, int count);
public abstract void dropItem(LocalWorld world, Vector pt, int type,
int count);
/**
* Drop an item.
@ -183,14 +166,14 @@ public abstract class ServerInterface {
* @param count
* @param times
*/
public abstract void dropItem(Vector pt, int type);
public abstract void dropItem(LocalWorld world, Vector pt, int type);
/**
* Simulate a block being mined.
*
* @param pt
*/
public abstract void simulateBlockMine(Vector pt);
public abstract void simulateBlockMine(LocalWorld world, Vector pt);
/**
* Resolves an item name to its ID.
@ -207,5 +190,5 @@ public abstract class ServerInterface {
* @param radius
* @return
*/
public abstract int killMobs(Vector origin, int radius);
public abstract int killMobs(LocalWorld world, Vector origin, int radius);
}

View File

@ -21,7 +21,7 @@ package com.sk89q.worldedit;
/**
*
* @author Albert
* @author sk89q
*/
public class Vector {
protected final double x, y, z;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,104 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit;
/**
* A vector with a world component.
*
* @author sk89q
*/
public class WorldVector extends Vector {
/**
* Represents the world.
*/
private LocalWorld world;
/**
* Construct the Vector object.
*
* @param x
* @param y
* @param z
*/
public WorldVector(LocalWorld world, double x, double y, double z) {
super(x, y, z);
this.world = world;
}
/**
* Construct the Vector object.
*
* @param x
* @param y
* @param z
*/
public WorldVector(LocalWorld world, int x, int y, int z) {
super(x, y, z);
this.world = world;
}
/**
* Construct the Vector object.
*
* @param x
* @param y
* @param z
*/
public WorldVector(LocalWorld world, float x, float y, float z) {
super(x, y, z);
this.world = world;
}
/**
* Construct the Vector object.
*
* @param pt
*/
public WorldVector(LocalWorld world, Vector pt) {
super(pt);
this.world = world;
}
/**
* Construct the Vector object.
*/
public WorldVector(LocalWorld world) {
super();
this.world = world;
}
/**
* Get the world.
*
* @return
*/
public LocalWorld getWorld() {
return world;
}
/**
* Gets a BlockVector version.
*
* @return BlockWorldVector
*/
public BlockWorldVector toWorldBlockVector() {
return new BlockWorldVector(this);
}
}

View File

@ -0,0 +1,94 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010, 2011 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.cli;
import static java.util.Arrays.*;
import java.util.List;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.OptionSpec;
/**
*
* @author sk89q
*/
public class Main {
/**
* @param args
*/
public static void main(String[] _args) throws Throwable {
OptionParser parser = new OptionParser();
OptionSpec<String> world =
parser.accepts("world").withRequiredArg().ofType(String.class)
.describedAs("world directory").defaultsTo("world");
parser.acceptsAll(asList("?", "h"), "show help");
OptionSet options = parser.parse(_args);
List<String> args = options.nonOptionArguments();
if (args.size() != 1 || options.has("?")) {
System.err.println("worldedit <action>");
System.err.println();
parser.printHelpOn(System.err);
return;
}
System.err.println("WorldEdit v" + getVersion());
System.err.println("Copyright (c) 2010-2011 sk89q <http://www.sk89q.com>");
System.err.println();
String act = args.get(0);
String worldPath = options.valueOf(world);
if (act.equalsIgnoreCase("check")) {
new WorldChecker(worldPath);
} else {
System.err.println("Only valid action is 'check'.");
}
}
/**
* Get the version.
*
* @return
*/
public static String getVersion() {
Package p = com.sk89q.worldedit.cli.Main.class.getPackage();
if (p == null) {
p = Package.getPackage("com.sk89q.worldedit");
}
String version;
if (p == null) {
return "(unknown)";
} else {
version = p.getImplementationVersion();
if (version == null) {
return "(unknown)";
}
}
return version;
}
}

View File

@ -0,0 +1,92 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010, 2011 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.cli;
import java.io.*;
import java.nio.*;
import java.util.regex.Pattern;
import org.jnbt.NBTInputStream;
import org.jnbt.Tag;
public class WorldChecker {
private File worldPath;
public WorldChecker(String path) {
worldPath = new File(path);
checkLevelDat();
checkFiles();
System.out.println("Done.");
}
public void checkLevelDat() {
try {
checkNBT(new File(worldPath, "level.dat"));
} catch (IOException e) {
System.out.println("BAD: level.dat: " + e.getMessage());
}
}
public void checkFiles() {
final Pattern chunkFilePattern = Pattern.compile("^c\\..*\\.dat$");
FileFilter folderFilter = new FileFilter() {
@Override
public boolean accept(File f) {
return f.isDirectory();
}
};
FileFilter chunkFilter = new FileFilter() {
@Override
public boolean accept(File f) {
return f.isFile()
&& chunkFilePattern.matcher(f.getName()).matches();
}
};
for (File l1 : worldPath.listFiles(folderFilter)) {
for (File l2 : l1.listFiles(folderFilter)) {
for (File chunkFile : l2.listFiles(chunkFilter)) {
checkChunkFile(chunkFile,
l1.getName(), l2.getName(), chunkFile.getName());
}
}
}
}
public void checkChunkFile(File f, String a, String b, String c) {
String id = a + "/" + b + "/" + c;
try {
checkNBT(f);
} catch (IOException e) {
System.out.println("BAD: " + id);
}
}
public void checkNBT(File file) throws IOException {
FileInputStream stream = new FileInputStream(file);
NBTInputStream nbt = new NBTInputStream(stream);
Tag tag = nbt.readTag();
}
}

View File

@ -0,0 +1,82 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.superpickaxe;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockID;
/**
* A super pickaxe mode that will remove blocks in an area.
*
* @author sk89q
*/
public class AreaPickaxe implements SuperPickaxeMode {
private static final BaseBlock air = new BaseBlock(0);
private int range;
public AreaPickaxe(int range) {
this.range = range;
}
@Override
public boolean act(ServerInterface server, LocalConfiguration config,
LocalPlayer player, LocalSession session, LocalWorld world,
Vector clicked) {
int ox = clicked.getBlockX();
int oy = clicked.getBlockY();
int oz = clicked.getBlockZ();
int initialType = server.getBlockType(world, clicked);
if (initialType == 0) {
return true;
}
if (initialType == BlockID.BEDROCK && !player.canDestroyBedrock()) {
return true;
}
EditSession editSession = new EditSession(server, world,
session.getBlockChangeLimit());
try {
for (int x = ox - range; x <= ox + range; x++) {
for (int y = oy - range; y <= oy + range; y++) {
for (int z = oz - range; z <= oz + range; z++) {
Vector pos = new Vector(x, y, z);
if (server.getBlockType(world, pos) == initialType) {
if (config.superPickaxeManyDrop) {
server.simulateBlockMine(world, pos);
}
editSession.setBlock(pos, air);
}
}
}
}
} catch (MaxChangedBlocksException e) {
player.printError("Max blocks change limit reached.");
} finally {
session.remember(editSession);
}
return true;
}
}

View File

@ -0,0 +1,54 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.superpickaxe;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.blocks.BaseBlock;
/**
* A smode that replaces one block.
*
* @author sk89q
*/
public class BlockReplacer implements SuperPickaxeMode {
private BaseBlock targetBlock;
public BlockReplacer(BaseBlock targetBlock) {
this.targetBlock = targetBlock;
}
@Override
public boolean act(ServerInterface server, LocalConfiguration config,
LocalPlayer player, LocalSession session, LocalWorld world,
Vector clicked) {
EditSession editSession = new EditSession(server, world, -1);
try {
editSession.setBlock(clicked, targetBlock);
} catch (MaxChangedBlocksException e) {
} finally {
session.remember(editSession);
}
return true;
}
}

View File

@ -0,0 +1,52 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.superpickaxe;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.blocks.*;
/**
* Plants a tree.
*
* @author sk89q
*/
public class QueryTool implements SuperPickaxeMode {
@Override
public boolean act(ServerInterface server, LocalConfiguration config,
LocalPlayer player, LocalSession session, LocalWorld world,
Vector clicked) {
BaseBlock block = (new EditSession(server, world, 0)).rawGetBlock(clicked);
player.print("\u00A79@" + clicked + ": " + "\u00A7e"
+ "Type: " + block.getID() + "\u00A77" + " ("
+ BlockType.fromID(block.getID()).getName() + ") "
+ "\u00A7f"
+ "[" + block.getData() + "]");
if (block instanceof MobSpawnerBlock) {
player.printRaw("\u00A7e" + "Mob Type: "
+ ((MobSpawnerBlock)block).getMobType());
}
return true;
}
}

View File

@ -0,0 +1,119 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.superpickaxe;
import java.util.HashSet;
import java.util.Set;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockID;
/**
* A pickaxe mode that recursively finds adjacent blocks within range of
* an initial block and of the same type.
*
* @author sk89q
*/
public class RecursivePickaxe implements SuperPickaxeMode {
private static final BaseBlock air = new BaseBlock(0);
private int range;
public RecursivePickaxe(int range) {
this.range = range;
}
@Override
public boolean act(ServerInterface server, LocalConfiguration config,
LocalPlayer player, LocalSession session, LocalWorld world,
Vector clicked) {
int initialType = server.getBlockType(world, clicked);
if (initialType == 0) {
return true;
}
if (initialType == BlockID.BEDROCK && !player.canDestroyBedrock()) {
return true;
}
EditSession editSession = new EditSession(server, world,
session.getBlockChangeLimit());
try {
recurse(server, editSession, world, clicked.toBlockVector(),
clicked, range, initialType, new HashSet<BlockVector>(),
config.superPickaxeManyDrop);
} catch (MaxChangedBlocksException e) {
player.printError("Max blocks change limit reached.");
} finally {
session.remember(editSession);
}
return true;
}
/**
* Helper method.
*
* @param server
* @param superPickaxeManyDrop
* @param world
* @param pos
* @param origin
* @param size
* @param initialType
* @param visited
*/
private void recurse(ServerInterface server, EditSession editSession,
LocalWorld world, BlockVector pos,
Vector origin, int size, int initialType,
Set<BlockVector> visited, boolean drop)
throws MaxChangedBlocksException {
if (origin.distance(pos) > size || visited.contains(pos)) {
return;
}
visited.add(pos);
if (editSession.getBlock(pos).getID() == initialType) {
if (drop) {
server.simulateBlockMine(world, pos);
}
editSession.setBlock(pos, air);
} else {
return;
}
recurse(server, editSession, world, pos.add(1, 0, 0).toBlockVector(),
origin, size, initialType, visited, drop);
recurse(server, editSession, world, pos.add(-1, 0, 0).toBlockVector(),
origin, size, initialType, visited, drop);
recurse(server, editSession, world, pos.add(0, 0, 1).toBlockVector(),
origin, size, initialType, visited, drop);
recurse(server, editSession, world, pos.add(0, 0, -1).toBlockVector(),
origin, size, initialType, visited, drop);
recurse(server, editSession, world, pos.add(0, 1, 0).toBlockVector(),
origin, size, initialType, visited, drop);
recurse(server, editSession, world, pos.add(0, -1, 0).toBlockVector(),
origin, size, initialType, visited, drop);
}
}

View File

@ -0,0 +1,52 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.superpickaxe;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.blocks.BlockID;
/**
* A super pickaxe mode that removes one block.
*
* @author sk89q
*/
public class SinglePickaxe implements SuperPickaxeMode {
@Override
public boolean act(ServerInterface server, LocalConfiguration config,
LocalPlayer player, LocalSession session, LocalWorld world,
Vector clicked) {
if (server.getBlockType(world, clicked) == BlockID.BEDROCK
&& !player.canDestroyBedrock()) {
return true;
} else if (server.getBlockType(world, clicked) == BlockID.TNT) {
return false;
}
if (config.superPickaxeDrop) {
server.simulateBlockMine(world, clicked);
}
server.setBlockType(world, clicked, 0);
return true;
}
}

View File

@ -0,0 +1,42 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.superpickaxe;
import com.sk89q.worldedit.*;
/**
* Represents a super pickaxe mode.
*
* @author sk89q
*/
public interface SuperPickaxeMode {
/**
* Perform the action. Should return true to deny the default
* action.
*
* @param player
* @param session
* @param clicked
* @return true to deny
*/
public boolean act(ServerInterface server, LocalConfiguration config,
LocalPlayer player, LocalSession session, LocalWorld world,
Vector clicked);
}

View File

@ -0,0 +1,49 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.superpickaxe;
import com.sk89q.worldedit.*;
/**
* Plants a tree.
*
* @author sk89q
*/
public class TreePlanter implements SuperPickaxeMode {
@Override
public boolean act(ServerInterface server, LocalConfiguration config,
LocalPlayer player, LocalSession session, LocalWorld world,
Vector clicked) {
EditSession editSession =
new EditSession(server, world, session.getBlockChangeLimit());
try {
if (!server.generateTree(editSession, player.getWorld(), clicked)) {
player.printError("Notch won't let you put a tree there.");
}
} finally {
session.remember(editSession);
}
return true;
}
}

View File

@ -0,0 +1,124 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static java.util.Collections.*;
import static joptsimple.internal.Strings.*;
/**
* @param <V> represents the type of the arguments this option accepts
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: AbstractOptionSpec.java,v 1.19 2009/11/28 21:31:53 pholser Exp $
*/
abstract class AbstractOptionSpec<V> implements OptionSpec<V> {
private final List<String> options = new ArrayList<String>();
private final String description;
protected AbstractOptionSpec( String option ) {
this( singletonList( option ), EMPTY );
}
protected AbstractOptionSpec( Collection<String> options, String description ) {
arrangeOptions( options );
this.description = description;
}
public final Collection<String> options() {
return unmodifiableCollection( options );
}
public final List<V> values( OptionSet detectedOptions ) {
return detectedOptions.valuesOf( this );
}
public final V value( OptionSet detectedOptions ) {
return detectedOptions.valueOf( this );
}
abstract List<V> defaultValues();
String description() {
return description;
}
protected abstract V convert( String argument );
abstract void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions,
String detectedArgument );
abstract boolean acceptsArguments();
abstract boolean requiresArgument();
abstract void accept( OptionSpecVisitor visitor );
private void arrangeOptions( Collection<String> unarranged ) {
if ( unarranged.size() == 1 ) {
options.addAll( unarranged );
return;
}
List<String> shortOptions = new ArrayList<String>();
List<String> longOptions = new ArrayList<String>();
for ( String each : unarranged ) {
if ( each.length() == 1 )
shortOptions.add( each );
else
longOptions.add( each );
}
sort( shortOptions );
sort( longOptions );
options.addAll( shortOptions );
options.addAll( longOptions );
}
@Override
public boolean equals( Object that ) {
if ( !( that instanceof AbstractOptionSpec<?> ) )
return false;
AbstractOptionSpec<?> other = (AbstractOptionSpec<?>) that;
return options.equals( other.options );
}
@Override
public int hashCode() {
return options.hashCode();
}
@Override
public String toString() {
return options.toString();
}
}

View File

@ -0,0 +1,57 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import static java.util.Collections.*;
import static joptsimple.ParserRules.*;
/**
* <p>Represents the <kbd>"-W"</kbd> form of long option specification.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: AlternativeLongOptionSpec.java,v 1.13 2009/09/28 01:12:48 pholser Exp $
*/
class AlternativeLongOptionSpec extends ArgumentAcceptingOptionSpec<String> {
AlternativeLongOptionSpec() {
super( singletonList( RESERVED_FOR_EXTENSIONS ), true, "Alternative form of long options" );
describedAs( "opt=value" );
}
@Override
protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) {
if ( !arguments.hasMore() )
throw new OptionMissingRequiredArgumentException( options() );
arguments.treatNextAsLongOption();
}
@Override
void accept( OptionSpecVisitor visitor ) {
visitor.visit( this );
}
}

View File

@ -0,0 +1,301 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.StringTokenizer;
import static java.util.Collections.*;
import joptsimple.internal.ReflectionException;
import static joptsimple.internal.Objects.*;
import static joptsimple.internal.Reflection.*;
import static joptsimple.internal.Strings.*;
/**
* <p>Specification of an option that accepts an argument.</p>
*
* <p>Instances are returned from {@link OptionSpecBuilder} methods to allow the formation
* of parser directives as sentences in a "fluent interface" language. For example:</p>
*
* <pre>
* <code>
* OptionParser parser = new OptionParser();
* parser.accepts( "c" ).withRequiredArg().<strong>ofType( Integer.class )</strong>;
* </code>
* </pre>
*
* <p>If no methods are invoked on an instance of this class, then that instance's option
* will treat its argument as a {@link String}.</p>
*
* @param <V> represents the type of the arguments this option accepts
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: ArgumentAcceptingOptionSpec.java,v 1.43 2009/10/25 18:37:06 pholser Exp $
*/
public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<V> {
private static final char NIL_VALUE_SEPARATOR = '\u0000';
private final boolean argumentRequired;
private ValueConverter<V> converter;
private String argumentDescription = "";
private String valueSeparator = String.valueOf( NIL_VALUE_SEPARATOR );
private final List<V> defaultValues = new ArrayList<V>();
ArgumentAcceptingOptionSpec( String option, boolean argumentRequired ) {
super( option );
this.argumentRequired = argumentRequired;
}
ArgumentAcceptingOptionSpec( Collection<String> options, boolean argumentRequired, String description ) {
super( options, description );
this.argumentRequired = argumentRequired;
}
/**
* <p>Specifies a type to which arguments of this spec's option are to be
* converted.</p>
*
* <p>JOpt Simple accepts types that have either:</p>
*
* <ol>
* <li>a public static method called {@code valueOf} which accepts a single
* argument of type {@link String} and whose return type is the same as the class
* on which the method is declared. The {@code java.lang} primitive wrapper
* classes have such methods.</li>
*
* <li>a public constructor which accepts a single argument of type
* {@link String}.</li>
* </ol>
*
* <p>This class converts arguments using those methods in that order; that is,
* {@code valueOf} would be invoked before a one-{@link String}-arg constructor
* would.</p>
*
* <p>Invoking this method will trump any previous calls to this method or to
* {@link #withValuesConvertedBy(ValueConverter)}.
*
* @param <T> represents the runtime class of the desired option argument type
* @param argumentType desired type of arguments to this spec's option
* @return self, so that the caller can add clauses to the fluent interface sentence
* @throws NullPointerException if the type is {@code null}
* @throws IllegalArgumentException if the type does not have the standard conversion
* methods
*/
public final <T> ArgumentAcceptingOptionSpec<T> ofType( Class<T> argumentType ) {
return withValuesConvertedBy( findConverter( argumentType ) );
}
/**
* <p>Specifies a converter to use to translate arguments of this spec's option into
* Java objects. This is useful when converting to types that do not have the
* requisite factory method or constructor for {@link #ofType(Class)}.</p>
*
* <p>Invoking this method will trump any previous calls to this method or to
* {@link #ofType(Class)}.
*
* @param <T> represents the runtime class of the desired option argument type
* @param aConverter the converter to use
* @return self, so that the caller can add clauses to the fluent interface sentence
* @throws NullPointerException if the converter is {@code null}
*/
@SuppressWarnings( "unchecked" )
public final <T> ArgumentAcceptingOptionSpec<T> withValuesConvertedBy( ValueConverter<T> aConverter ) {
if ( aConverter == null )
throw new NullPointerException( "illegal null converter" );
converter = (ValueConverter<V>) aConverter;
return (ArgumentAcceptingOptionSpec<T>) this;
}
/**
* <p>Specifies a description for the argument of the option that this spec
* represents. This description is used when generating help information about
* the parser.</p>
*
* @param description describes the nature of the argument of this spec's
* option
* @return self, so that the caller can add clauses to the fluent interface sentence
*/
public final ArgumentAcceptingOptionSpec<V> describedAs( String description ) {
argumentDescription = description;
return this;
}
/**
* <p>Specifies a value separator for the argument of the option that this spec
* represents. This allows a single option argument to represent multiple values
* for the option. For example:</p>
*
* <pre>
* <code>
* parser.accepts( "z" ).withRequiredArg()
* .<strong>withValuesSeparatedBy( ',' )</strong>;
* OptionSet options = parser.parse( new String[] { "-z", "foo,bar,baz", "-z",
* "fizz", "-z", "buzz" } );
* </code>
* </pre>
*
* <p>Then {@code options.valuesOf( "z" )} would yield the list {@code [foo, bar,
* baz, fizz, buzz]}.</p>
*
* <p>You cannot use Unicode U+0000 as the separator.</p>
*
* @param separator a character separator
* @return self, so that the caller can add clauses to the fluent interface sentence
* @throws IllegalArgumentException if the separator is Unicode U+0000
*/
public final ArgumentAcceptingOptionSpec<V> withValuesSeparatedBy( char separator ) {
if ( separator == NIL_VALUE_SEPARATOR )
throw new IllegalArgumentException( "cannot use U+0000 as separator" );
valueSeparator = String.valueOf( separator );
return this;
}
/**
* <p>Specifies a set of default values for the argument of the option that this spec
* represents.</p>
*
* @param value the first in the set of default argument values for this spec's option
* @param values the (optional) remainder of the set of default argument values for this spec's option
* @return self, so that the caller can add clauses to the fluent interface sentence
* @throws NullPointerException if {@code value}, {@code values}, or any elements of {@code values} are
* {@code null}
*/
public ArgumentAcceptingOptionSpec<V> defaultsTo( V value, V... values ) {
addDefaultValue( value );
for ( V each : values )
addDefaultValue( each );
return this;
}
private void addDefaultValue( V value ) {
ensureNotNull( value );
defaultValues.add( value );
}
@Override
final void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions,
String detectedArgument ) {
if ( isNullOrEmpty( detectedArgument ) )
detectOptionArgument( parser, arguments, detectedOptions );
else
addArguments( detectedOptions, detectedArgument );
}
protected void addArguments( OptionSet detectedOptions, String detectedArgument ) {
StringTokenizer lexer = new StringTokenizer( detectedArgument, valueSeparator );
if ( !lexer.hasMoreTokens() )
detectedOptions.addWithArgument( this, detectedArgument );
else {
while ( lexer.hasMoreTokens() )
detectedOptions.addWithArgument( this, lexer.nextToken() );
}
}
protected abstract void detectOptionArgument( OptionParser parser, ArgumentList arguments,
OptionSet detectedOptions );
@SuppressWarnings( "unchecked" )
@Override
protected final V convert( String argument ) {
if ( converter == null )
return (V) argument;
try {
return converter.convert( argument );
}
catch ( ReflectionException ex ) {
throw new OptionArgumentConversionException( options(), argument, converter.valueType(), ex );
}
catch ( ValueConversionException ex ) {
throw new OptionArgumentConversionException( options(), argument, converter.valueType(), ex );
}
}
protected boolean canConvertArgument( String argument ) {
StringTokenizer lexer = new StringTokenizer( argument, valueSeparator );
try {
while ( lexer.hasMoreTokens() )
convert( lexer.nextToken() );
return true;
}
catch ( OptionException ignored ) {
return false;
}
}
protected boolean isArgumentOfNumberType() {
return converter != null && Number.class.isAssignableFrom( converter.valueType() );
}
@Override
boolean acceptsArguments() {
return true;
}
@Override
boolean requiresArgument() {
return argumentRequired;
}
String argumentDescription() {
return argumentDescription;
}
String typeIndicator() {
if ( converter == null )
return null;
String pattern = converter.valuePattern();
return pattern == null ? converter.valueType().getName() : pattern;
}
@Override
List<V> defaultValues() {
return unmodifiableList( defaultValues );
}
@Override
public boolean equals( Object that ) {
if ( !super.equals( that ) )
return false;
ArgumentAcceptingOptionSpec<?> other = (ArgumentAcceptingOptionSpec<?>) that;
return requiresArgument() == other.requiresArgument();
}
@Override
public int hashCode() {
return super.hashCode() ^ ( argumentRequired ? 0 : 1 );
}
}

View File

@ -0,0 +1,60 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import static joptsimple.ParserRules.*;
/**
* <p>Wrapper for an array of command line arguments.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: ArgumentList.java,v 1.7 2009/08/13 00:34:35 pholser Exp $
*/
class ArgumentList {
private final String[] arguments;
private int currentIndex;
ArgumentList( String... arguments ) {
this.arguments = arguments.clone();
}
boolean hasMore() {
return currentIndex < arguments.length;
}
String next() {
return arguments[ currentIndex++ ];
}
String peek() {
return arguments[ currentIndex ];
}
void treatNextAsLongOption() {
if ( HYPHEN_CHAR != arguments[ currentIndex ].charAt( 0 ) )
arguments[ currentIndex ] = DOUBLE_HYPHEN + arguments[ currentIndex ];
}
}

View File

@ -0,0 +1,149 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import joptsimple.internal.ColumnarData;
import static joptsimple.ParserRules.*;
import static joptsimple.internal.Classes.*;
import static joptsimple.internal.Strings.*;
/**
* <p>Produces text for a help screen given a set of options.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: HelpFormatter.java,v 1.19 2009/10/04 00:13:41 pholser Exp $
*/
class HelpFormatter implements OptionSpecVisitor {
private final ColumnarData grid;
HelpFormatter() {
grid = new ColumnarData( "Option", "Description" );
}
String format( Map<String, AbstractOptionSpec<?>> options ) {
if ( options.isEmpty() )
return "No options specified";
grid.clear();
Comparator<AbstractOptionSpec<?>> comparator =
new Comparator<AbstractOptionSpec<?>>() {
public int compare( AbstractOptionSpec<?> first, AbstractOptionSpec<?> second ) {
return first.options().iterator().next().compareTo( second.options().iterator().next() );
}
};
Set<AbstractOptionSpec<?>> sorted = new TreeSet<AbstractOptionSpec<?>>( comparator );
sorted.addAll( options.values() );
for ( AbstractOptionSpec<?> each : sorted )
each.accept( this );
return grid.format();
}
void addHelpLineFor( AbstractOptionSpec<?> spec, String additionalInfo ) {
grid.addRow( createOptionDisplay( spec ) + additionalInfo, createDescriptionDisplay( spec ) );
}
public void visit( NoArgumentOptionSpec spec ) {
addHelpLineFor( spec, "" );
}
public void visit( RequiredArgumentOptionSpec<?> spec ) {
visit( spec, '<', '>' );
}
public void visit( OptionalArgumentOptionSpec<?> spec ) {
visit( spec, '[', ']' );
}
public void visit( AlternativeLongOptionSpec spec ) {
addHelpLineFor( spec, ' ' + surround( spec.argumentDescription(), '<', '>' ) );
}
private void visit( ArgumentAcceptingOptionSpec<?> spec, char begin, char end ) {
String argDescription = spec.argumentDescription();
String typeIndicator = typeIndicator( spec );
StringBuilder collector = new StringBuilder();
if ( typeIndicator.length() > 0 ) {
collector.append( typeIndicator );
if ( argDescription.length() > 0 )
collector.append( ": " ).append( argDescription );
}
else if ( argDescription.length() > 0 )
collector.append( argDescription );
String helpLine = collector.length() == 0
? ""
: ' ' + surround( collector.toString(), begin, end );
addHelpLineFor( spec, helpLine );
}
private String createOptionDisplay( AbstractOptionSpec<?> spec ) {
StringBuilder buffer = new StringBuilder();
for ( Iterator<String> iter = spec.options().iterator(); iter.hasNext(); ) {
String option = iter.next();
buffer.append( option.length() > 1 ? DOUBLE_HYPHEN : HYPHEN );
buffer.append( option );
if ( iter.hasNext() )
buffer.append( ", " );
}
return buffer.toString();
}
private String createDescriptionDisplay( AbstractOptionSpec<?> spec ) {
List<?> defaultValues = spec.defaultValues();
if ( defaultValues.isEmpty() )
return spec.description();
String defaultValuesDisplay = createDefaultValuesDisplay( defaultValues );
return spec.description() + ' ' + surround( "default: " + defaultValuesDisplay, '(', ')' );
}
private String createDefaultValuesDisplay( List<?> defaultValues ) {
return defaultValues.size() == 1 ? defaultValues.get( 0 ).toString() : defaultValues.toString();
}
private static String typeIndicator( ArgumentAcceptingOptionSpec<?> spec ) {
String indicator = spec.typeIndicator();
return indicator == null || String.class.getName().equals( indicator )
? ""
: shortNameOf( indicator );
}
}

View File

@ -0,0 +1,48 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import static java.util.Collections.*;
/**
* <p>Thrown when the option parser discovers a cluster of short options in which
* at least one of the short options can accept arguments.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: IllegalOptionClusterException.java,v 1.11 2009/10/25 18:37:06 pholser Exp $
*/
class IllegalOptionClusterException extends OptionException {
private static final long serialVersionUID = -1L;
IllegalOptionClusterException( String option ) {
super( singletonList( option ) );
}
@Override
public String getMessage() {
return "Option cluster containing " + singleOptionMessage() + " is illegal";
}
}

View File

@ -0,0 +1,48 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import static java.util.Collections.*;
/**
* <p>Thrown when the option parser is asked to recognize an option with illegal
* characters in it.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: IllegalOptionSpecificationException.java,v 1.11 2009/10/25 18:37:06 pholser Exp $
*/
class IllegalOptionSpecificationException extends OptionException {
private static final long serialVersionUID = -1L;
IllegalOptionSpecificationException( String option ) {
super( singletonList( option ) );
}
@Override
public String getMessage() {
return singleOptionMessage() + " is not a legal option character";
}
}

View File

@ -0,0 +1,48 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.Collection;
/**
* <p>Thrown when asking an {@link OptionSet} for a single argument of an option when
* many have been specified.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: MultipleArgumentsForOptionException.java,v 1.14 2009/10/25 18:37:06 pholser Exp $
*/
class MultipleArgumentsForOptionException extends OptionException {
private static final long serialVersionUID = -1L;
MultipleArgumentsForOptionException( Collection<String> options ) {
super( options );
}
@Override
public String getMessage() {
return "Found multiple arguments for option " + multipleOptionMessage() + ", but you asked for only one";
}
}

View File

@ -0,0 +1,79 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.Collection;
import java.util.List;
import static java.util.Collections.*;
/**
* <p>A specification for an option that does not accept arguments.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: NoArgumentOptionSpec.java,v 1.16 2009/10/04 00:13:41 pholser Exp $
*/
class NoArgumentOptionSpec extends AbstractOptionSpec<Void> {
NoArgumentOptionSpec( String option ) {
this( singletonList( option ), "" );
}
NoArgumentOptionSpec( Collection<String> options, String description ) {
super( options, description );
}
@Override
void handleOption( OptionParser parser, ArgumentList arguments,
OptionSet detectedOptions, String detectedArgument ) {
detectedOptions.add( this );
}
@Override
boolean acceptsArguments() {
return false;
}
@Override
boolean requiresArgument() {
return false;
}
@Override
void accept( OptionSpecVisitor visitor ) {
visitor.visit( this );
}
@Override
protected Void convert( String argument ) {
return null;
}
@Override
List<Void> defaultValues() {
return emptyList();
}
}

View File

@ -0,0 +1,56 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.Collection;
/**
* <p>Thrown when a problem occurs converting an argument of an option from {@link String}
* to another type.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: OptionArgumentConversionException.java,v 1.16 2009/10/25 18:37:06 pholser Exp $
*/
class OptionArgumentConversionException extends OptionException {
private static final long serialVersionUID = -1L;
private final String argument;
private final Class<?> valueType;
OptionArgumentConversionException( Collection<String> options, String argument, Class<?> valueType,
Throwable cause ) {
super( options, cause );
this.argument = argument;
this.valueType = valueType;
}
@Override
public String getMessage() {
return "Cannot convert argument '" + argument + "' of option " + multipleOptionMessage() + " to " + valueType;
}
}

View File

@ -0,0 +1,95 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import static java.util.Collections.*;
import static joptsimple.internal.Strings.*;
/**
* <p>Thrown when a problem occurs during option parsing.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: OptionException.java,v 1.21 2009/08/13 00:34:35 pholser Exp $
*/
public abstract class OptionException extends RuntimeException {
private static final long serialVersionUID = -1L;
private final List<String> options = new ArrayList<String>();
protected OptionException( Collection<String> options ) {
this.options.addAll( options );
}
protected OptionException( Collection<String> options, Throwable cause ) {
super( cause );
this.options.addAll( options );
}
/**
* <p>Gives the option being considered when the exception was created.</p>
*
* @return the option being considered when the exception was created
*/
public Collection<String> options() {
return unmodifiableCollection( options );
}
protected final String singleOptionMessage() {
return singleOptionMessage( options.get( 0 ) );
}
protected final String singleOptionMessage( String option ) {
return SINGLE_QUOTE + option + SINGLE_QUOTE;
}
protected final String multipleOptionMessage() {
StringBuilder buffer = new StringBuilder( "[" );
for ( Iterator<String> iter = options.iterator(); iter.hasNext(); ) {
buffer.append( singleOptionMessage( iter.next() ) );
if ( iter.hasNext() )
buffer.append( ", " );
}
buffer.append( ']' );
return buffer.toString();
}
static OptionException illegalOptionCluster( String option ) {
return new IllegalOptionClusterException( option );
}
static OptionException unrecognizedOption( String option ) {
return new UnrecognizedOptionException( option );
}
}

View File

@ -0,0 +1,48 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.Collection;
/**
* <p>Thrown when the option parser discovers an option that requires an argument,
* but that argument is missing.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: OptionMissingRequiredArgumentException.java,v 1.12 2009/10/25 18:37:06 pholser Exp $
*/
class OptionMissingRequiredArgumentException extends OptionException {
private static final long serialVersionUID = -1L;
OptionMissingRequiredArgumentException( Collection<String> options ) {
super( options );
}
@Override
public String getMessage() {
return "Option " + multipleOptionMessage() + " requires an argument";
}
}

View File

@ -0,0 +1,496 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.Collections.*;
import joptsimple.internal.AbbreviationMap;
import joptsimple.util.KeyValuePair;
import static joptsimple.OptionException.*;
import static joptsimple.OptionParserState.*;
import static joptsimple.ParserRules.*;
/**
* <p>Parses command line arguments, using a syntax that attempts to take from the best
* of POSIX {@code getopt()} and GNU {@code getopt_long()}.</p>
*
* <p>This parser supports short options and long options.</p>
*
* <ul>
* <li><dfn>Short options</dfn> begin with a single hyphen ("<kbd>-</kbd>") followed
* by a single letter or digit, or question mark ("<kbd>?</kbd>"), or dot
* ("<kbd>.</kbd>").</li>
*
* <li>Short options can accept single arguments. The argument can be made required or
* optional. The option's argument can occur:
* <ul>
* <li>in the slot after the option, as in <kbd>-d /tmp</kbd></li>
* <li>right up against the option, as in <kbd>-d/tmp</kbd></li>
* <li>right up against the option separated by an equals sign (<kbd>"="</kbd>),
* as in <kbd>-d=/tmp</kbd></li>
* </ul>
* To specify <var>n</var> arguments for an option, specify the option <var>n</var>
* times, once for each argument, as in <kbd>-d /tmp -d /var -d /opt</kbd>; or, when
* using the {@linkplain ArgumentAcceptingOptionSpec#withValuesSeparatedBy(char)
* "separated values"} clause of the "fluent interface" (see below), give multiple
* values separated by a given character as a single argument to the option.</li>
*
* <li>Short options can be clustered, so that <kbd>-abc</kbd> is treated as
* <kbd>-a -b -c</kbd>, if none of those options can accept arguments.</li>
*
* <li>An argument consisting only of two hyphens (<kbd>"--"</kbd>) signals that the
* remaining arguments are to be treated as non-options.</li>
*
* <li>An argument consisting only of a single hyphen is considered a non-option
* argument (though it can be an argument of an option). Many Unix programs treat
* single hyphens as stand-ins for the standard input or standard output streams.</li>
*
* <li><dfn>Long options</dfn> begin with two hyphens (<kbd>"--"</kbd>), followed
* by multiple letters, digits, hyphens, question marks, or dots. A hyphen cannot be
* the first character of a long option specification when configuring the parser.</li>
*
* <li>You can abbreviate long options, so long as the abbreviation is unique.</li>
*
* <li>Long options can accept single arguments. The argument can be made required or
* optional. The option's argument can occur:
* <ul>
* <li>in the slot after the option, as in <kbd>--directory /tmp</kbd></li>
* <li>right up against the option separated by an equals sign (<kbd>"="</kbd>),
* as in <kbd>--directory=/tmp</kbd>
* </ul>
* Specify multiple arguments for a long option in the same manner as for short options
* (see above).</li>
*
* <li>You can use a single hyphen (<kbd>"-"</kbd>) instead of a double hyphen
* (<kbd>"--"</kbd>) for a long option.</li>
*
* <li>The option <kbd>-W</kbd> is reserved. If you tell the parser to {@linkplain
* #recognizeAlternativeLongOptions(boolean) recognize alternative long options}, then
* it will treat, for example, <kbd>-W foo=bar</kbd> as the long option
* <kbd>foo</kbd> with argument <kbd>bar</kbd>, as though you had written
* <kbd>--foo=bar</kbd>.</li>
*
* <li>You can specify <kbd>-W</kbd> as a valid short option, or use it as an
* abbreviation for a long option, but {@linkplain
* #recognizeAlternativeLongOptions(boolean) recognizing alternative long options} will
* always supersede this behavior.</li>
*
* <li>You can specify a given short or long option multiple times on a single command
* line. The parser collects any arguments specified for those options as a list.</li>
*
* <li>If the parser detects an option whose argument is optional, and the next argument
* "looks like" an option, that argument is not treated as the argument to the option,
* but as a potentially valid option. If, on the other hand, the optional argument is
* typed as a derivative of {@link Number}, then that argument is treated as the
* negative number argument of the option, even if the parser recognizes the
* corresponding numeric option. For example:
* <pre><code>
* OptionParser parser = new OptionParser();
* parser.accepts( "a" ).withOptionalArg().ofType( Integer.class );
* parser.accepts( "2" );
* OptionSet options = parser.parse( "-a", "-2" );
* </code></pre>
* In this case, the option set contains <kbd>"a"</kbd> with argument <kbd>-2</kbd>,
* not both <kbd>"a"</kbd> and <kbd>"2"</kbd>. Swapping the elements in the
* <var>args</var> array gives the latter.</li>
* </ul>
*
* <p>There are two ways to tell the parser what options to recognize:</p>
*
* <ol>
* <li>A "fluent interface"-style API for specifying options, available since
* version 2. Sentences in this fluent interface language begin with a call to
* {@link #accepts(String) accepts} or {@link #acceptsAll(Collection) acceptsAll}
* methods; calls on the ensuing chain of objects describe whether the options can take
* an argument, whether the argument is required or optional, to what type arguments of
* the options should be converted if any, etc. Since version 3, these calls return
* an instance of {@link OptionSpec}, which can subsequently be used to retrieve the
* arguments of the associated option in a type-safe manner.</li>
*
* <li>Since version 1, a more concise way of specifying short options has been to use
* the special {@linkplain #OptionParser(String) constructor}. Arguments of options
* specified in this manner will be of type {@link String}. Here are the rules for the
* format of the specification strings this constructor accepts:
*
* <ul>
* <li>Any letter or digit is treated as an option character.</li>
*
* <li>If an option character is followed by a single colon (<kbd>":"</kbd>),
* then the option requires an argument.</li>
*
* <li>If an option character is followed by two colons (<kbd>"::"</kbd>), then
* the option accepts an optional argument.</li>
*
* <li>Otherwise, the option character accepts no argument.</li>
*
* <li>If the option specification string begins with a plus sign (<kbd>"+"</kbd>),
* the parser will behave "POSIX-ly correct".</li>
*
* <li>If the option specification string contains the sequence <kbd>"W;"</kbd>
* (capital W followed by a semicolon), the parser will recognize the alternative
* form of long options.</li>
* </ul>
* </li>
* </ol>
*
* <p>Each of the options in a list of options given to {@link #acceptsAll(Collection)
* acceptsAll} is treated as a synonym of the others. For example:
* <pre>
* <code>
* OptionParser parser = new OptionParser();
* parser.acceptsAll( asList( "w", "interactive", "confirmation" ) );
* OptionSet options = parser.parse( "-w" );
* </code>
* </pre>
* In this case, <code>options.{@link OptionSet#has(String) has}</code> would answer
* {@code true} when given arguments <kbd>"w"</kbd>, <kbd>"interactive"</kbd>, and
* <kbd>"confirmation"</kbd>. The {@link OptionSet} would give the same responses to
* these arguments for its other methods as well.</p>
*
* <p>By default, as with GNU {@code getopt()}, the parser allows intermixing of options
* and non-options. If, however, the parser has been created to be "POSIX-ly correct",
* then the first argument that does not look lexically like an option, and is not a
* required argument of a preceding option, signals the end of options. You can still
* bind optional arguments to their options using the abutting (for short options) or
* <kbd>=</kbd> syntax.</p>
*
* <p>Unlike GNU {@code getopt()}, this parser does not honor the environment variable
* {@code POSIXLY_CORRECT}. "POSIX-ly correct" parsers are configured by either:</p>
*
* <ol>
* <li>using the method {@link #posixlyCorrect(boolean)}, or</li>
*
* <li>using the {@linkplain #OptionParser(String) constructor} with an argument whose
* first character is a plus sign (<kbd>"+"</kbd>)</li>
* </ol>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: OptionParser.java,v 1.38 2009/10/25 18:37:06 pholser Exp $
* @see <a href="http://www.gnu.org/software/libc/manual">The GNU C Library </a>
*/
public class OptionParser {
private final AbbreviationMap<AbstractOptionSpec<?>> recognizedOptions;
private OptionParserState state;
private boolean posixlyCorrect;
/**
* <p>Creates an option parser that initially recognizes no options, and does not
* exhibit "POSIX-ly correct" behavior.</p>
*/
public OptionParser() {
recognizedOptions = new AbbreviationMap<AbstractOptionSpec<?>>();
state = moreOptions( false );
}
/**
* <p>Creates an option parser and configures it to recognize the short options
* specified in the given string.</p>
*
* <p>Arguments of options specified this way will be of type {@link String}.</p>
*
* @param optionSpecification an option specification
* @throws NullPointerException if <var>optionSpecification</var> is
* {@code null}
* @throws OptionException if the option specification contains illegal characters
* or otherwise cannot be recognized
*/
public OptionParser( String optionSpecification ) {
this();
new OptionSpecTokenizer( optionSpecification ).configure( this );
}
/**
* <p>Tells the parser to recognize the given option.</p>
*
* <p>This method returns an instance of {@link OptionSpecBuilder} to allow the
* formation of parser directives as sentences in a fluent interface language.
* For example:</p>
*
* <pre><code>
* OptionParser parser = new OptionParser();
* parser.<strong>accepts( "c" )</strong>.withRequiredArg().ofType( Integer.class );
* </code></pre>
*
* <p>If no methods are invoked on the returned {@link OptionSpecBuilder}, then the
* parser treats the option as accepting no argument.</p>
*
* @param option the option to recognize
* @return an object that can be used to flesh out more detail about the option
* @throws OptionException if the option contains illegal characters
* @throws NullPointerException if the option is {@code null}
*/
public OptionSpecBuilder accepts( String option ) {
return acceptsAll( singletonList( option ) );
}
/**
* <p>Tells the parser to recognize the given option.</p>
*
* @see #accepts(String)
* @param option the option to recognize
* @param description a string that describes the purpose of the option. This is
* used when generating help information about the parser.
* @return an object that can be used to flesh out more detail about the option
* @throws OptionException if the option contains illegal characters
* @throws NullPointerException if the option is {@code null}
*/
public OptionSpecBuilder accepts( String option, String description ) {
return acceptsAll( singletonList( option ), description );
}
/**
* <p>Tells the parser to recognize the given options, and treat them as
* synonymous.</p>
*
* @see #accepts(String)
* @param options the options to recognize and treat as synonymous
* @return an object that can be used to flesh out more detail about the options
* @throws OptionException if any of the options contain illegal characters
* @throws NullPointerException if the option list or any of its elements are
* {@code null}
*/
public OptionSpecBuilder acceptsAll( Collection<String> options ) {
return acceptsAll( options, "" );
}
/**
* <p>Tells the parser to recognize the given options, and treat them as
* synonymous.</p>
*
* @see #acceptsAll(Collection)
* @param options the options to recognize and treat as synonymous
* @param description a string that describes the purpose of the option. This is
* used when generating help information about the parser.
* @return an object that can be used to flesh out more detail about the options
* @throws OptionException if any of the options contain illegal characters
* @throws NullPointerException if the option list or any of its elements are
* {@code null}
* @throws IllegalArgumentException if the option list is empty
*/
public OptionSpecBuilder acceptsAll( Collection<String> options,
String description ) {
if ( options.isEmpty() )
throw new IllegalArgumentException( "need at least one option" );
ensureLegalOptions( options );
return new OptionSpecBuilder( this, options, description );
}
/**
* <p>Tells the parser whether or not to behave "POSIX-ly correct"-ly.</p>
*
* @param setting {@code true} if the parser should behave "POSIX-ly correct"-ly
*/
public void posixlyCorrect( boolean setting ) {
posixlyCorrect = setting;
state = moreOptions( setting );
}
boolean posixlyCorrect() {
return posixlyCorrect;
}
/**
* <p>Tells the parser either to recognize or ignore <kbd>"-W"</kbd>-style long
* options.</p>
*
* @param recognize {@code true} if the parser is to recognize the special style
* of long options
*/
public void recognizeAlternativeLongOptions( boolean recognize ) {
if ( recognize )
recognize( new AlternativeLongOptionSpec() );
else
recognizedOptions.remove( String.valueOf( RESERVED_FOR_EXTENSIONS ) );
}
void recognize( AbstractOptionSpec<?> spec ) {
recognizedOptions.putAll( spec.options(), spec );
}
/**
* <p>Writes information about the options this parser recognizes to the given output
* sink.</p>
*
* <p>The output sink is flushed, but not closed.</p>
*
* @param sink the sink to write information to
* @throws IOException if there is a problem writing to the sink
* @throws NullPointerException if <var>sink</var> is {@code null}
* @see #printHelpOn(Writer)
*/
public void printHelpOn( OutputStream sink ) throws IOException {
printHelpOn( new OutputStreamWriter( sink ) );
}
/**
* <p>Writes information about the options this parser recognizes to the given output
* sink.</p>
*
* <p>The output sink is flushed, but not closed.</p>
*
* @param sink the sink to write information to
* @throws IOException if there is a problem writing to the sink
* @throws NullPointerException if <var>sink</var> is {@code null}
* @see #printHelpOn(OutputStream)
*/
public void printHelpOn( Writer sink ) throws IOException {
sink.write( new HelpFormatter().format( recognizedOptions.toJavaUtilMap() ) );
sink.flush();
}
/**
* <p>Parses the given command line arguments according to the option specifications
* given to the parser.</p>
*
* @param arguments arguments to parse
* @return an {@link OptionSet} describing the parsed options, their arguments, and
* any non-option arguments found
* @throws OptionException if problems are detected while parsing
* @throws NullPointerException if the argument list is {@code null}
*/
public OptionSet parse( String... arguments ) {
ArgumentList argumentList = new ArgumentList( arguments );
OptionSet detected = new OptionSet( defaultValues() );
while ( argumentList.hasMore() )
state.handleArgument( this, argumentList, detected );
reset();
return detected;
}
void handleLongOptionToken( String candidate, ArgumentList arguments, OptionSet detected ) {
KeyValuePair optionAndArgument = parseLongOptionWithArgument( candidate );
if ( !isRecognized( optionAndArgument.key ) )
throw unrecognizedOption( optionAndArgument.key );
AbstractOptionSpec<?> optionSpec = specFor( optionAndArgument.key );
optionSpec.handleOption( this, arguments, detected, optionAndArgument.value );
}
void handleShortOptionToken( String candidate, ArgumentList arguments, OptionSet detected ) {
KeyValuePair optionAndArgument = parseShortOptionWithArgument( candidate );
if ( isRecognized( optionAndArgument.key ) ) {
specFor( optionAndArgument.key ).handleOption( this, arguments, detected, optionAndArgument.value );
}
else
handleShortOptionCluster( candidate, arguments, detected );
}
private void handleShortOptionCluster( String candidate, ArgumentList arguments, OptionSet detected ) {
char[] options = extractShortOptionsFrom( candidate );
validateOptionCharacters( options );
AbstractOptionSpec<?> optionSpec = specFor( options[ 0 ] );
if ( optionSpec.acceptsArguments() && options.length > 1 ) {
String detectedArgument = String.valueOf( options, 1, options.length - 1 );
optionSpec.handleOption( this, arguments, detected, detectedArgument );
}
else {
for ( char each : options )
specFor( each ).handleOption( this, arguments, detected, null );
}
}
void noMoreOptions() {
state = OptionParserState.noMoreOptions();
}
boolean looksLikeAnOption( String argument ) {
return isShortOptionToken( argument ) || isLongOptionToken( argument );
}
private boolean isRecognized( String option ) {
return recognizedOptions.contains( option );
}
private AbstractOptionSpec<?> specFor( char option ) {
return specFor( String.valueOf( option ) );
}
private AbstractOptionSpec<?> specFor( String option ) {
return recognizedOptions.get( option );
}
private void reset() {
state = moreOptions( posixlyCorrect );
}
private static char[] extractShortOptionsFrom( String argument ) {
char[] options = new char[ argument.length() - 1 ];
argument.getChars( 1, argument.length(), options, 0 );
return options;
}
private void validateOptionCharacters( char[] options ) {
for ( int i = 0; i < options.length; ++i ) {
String option = String.valueOf( options[ i ] );
if ( !isRecognized( option ) )
throw unrecognizedOption( option );
if ( specFor( option ).acceptsArguments() ) {
if ( i > 0 )
throw illegalOptionCluster( option );
// remainder of chars are the argument to the option at char 0
return;
}
}
}
private static KeyValuePair parseLongOptionWithArgument( String argument ) {
return KeyValuePair.valueOf( argument.substring( 2 ) );
}
private static KeyValuePair parseShortOptionWithArgument( String argument ) {
return KeyValuePair.valueOf( argument.substring( 1 ) );
}
private Map<String, List<?>> defaultValues() {
Map<String, List<?>> defaults = new HashMap<String, List<?>>();
for ( Map.Entry<String, AbstractOptionSpec<?>> each : recognizedOptions.toJavaUtilMap().entrySet() )
defaults.put( each.getKey(), each.getValue().defaultValues() );
return defaults;
}
}

View File

@ -0,0 +1,69 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import static joptsimple.ParserRules.*;
/**
* <p>Abstraction of parser state; mostly serves to model how a parser behaves depending
* on whether end-of-options has been detected.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: OptionParserState.java,v 1.8 2009/09/28 01:12:48 pholser Exp $
*/
abstract class OptionParserState {
static OptionParserState noMoreOptions() {
return new OptionParserState() {
@Override
protected void handleArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) {
detectedOptions.addNonOptionArgument( arguments.next() );
}
};
}
static OptionParserState moreOptions( final boolean posixlyCorrect ) {
return new OptionParserState() {
@Override
protected void handleArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) {
String candidate = arguments.next();
if ( isOptionTerminator( candidate ) )
parser.noMoreOptions();
else if ( isLongOptionToken( candidate ) )
parser.handleLongOptionToken( candidate, arguments, detectedOptions );
else if ( isShortOptionToken( candidate ) )
parser.handleShortOptionToken( candidate, arguments, detectedOptions );
else {
if ( posixlyCorrect )
parser.noMoreOptions();
detectedOptions.addNonOptionArgument( candidate );
}
}
};
}
protected abstract void handleArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions );
}

View File

@ -0,0 +1,301 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import static java.util.Collections.*;
import static joptsimple.internal.Objects.*;
/**
* <p>Representation of a group of detected command line options, their arguments, and
* non-option arguments.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: OptionSet.java,v 1.26 2009/10/25 18:37:05 pholser Exp $
*/
public class OptionSet {
private final Map<String, AbstractOptionSpec<?>> detectedOptions;
private final Map<AbstractOptionSpec<?>, List<String>> optionsToArguments;
private final List<String> nonOptionArguments;
private final Map<String, List<?>> defaultValues;
/**
* Package-private because clients don't create these.
*/
OptionSet( Map<String, List<?>> defaults ) {
detectedOptions = new HashMap<String, AbstractOptionSpec<?>>();
optionsToArguments = new IdentityHashMap<AbstractOptionSpec<?>, List<String>>();
nonOptionArguments = new ArrayList<String>();
defaultValues = new HashMap<String, List<?>>( defaults );
}
/**
* <p>Tells whether the given option was detected.</p>
*
* @param option the option to search for
* @return {@code true} if the option was detected
* @see #has(OptionSpec)
*/
public boolean has( String option ) {
return detectedOptions.containsKey( option );
}
/**
* <p>Tells whether the given option was detected.</p>
*
* <p>This method recognizes only instances of options returned from the fluent
* interface methods.</p>
*
* <p>Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[])} default argument value}
* for an option does not cause this method to return {@code true} if the option was not detected on the command
* line.</p>
*
* @param option the option to search for
* @return {@code true} if the option was detected
* @see #has(String)
*/
public boolean has( OptionSpec<?> option ) {
return optionsToArguments.containsKey( option );
}
/**
* <p>Tells whether there are any arguments associated with the given option.</p>
*
* @param option the option to search for
* @return {@code true} if the option was detected and at least one argument was
* detected for the option
* @see #hasArgument(OptionSpec)
*/
public boolean hasArgument( String option ) {
AbstractOptionSpec<?> spec = detectedOptions.get( option );
return spec != null && hasArgument( spec );
}
/**
* <p>Tells whether there are any arguments associated with the given option.</p>
*
* <p>This method recognizes only instances of options returned from the fluent
* interface methods.</p>
*
* <p>Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value}
* for an option does not cause this method to return {@code true} if the option was not detected on the command
* line, or if the option can take an optional argument but did not have one on the command line.</p>
*
* @param option the option to search for
* @return {@code true} if the option was detected and at least one argument was
* detected for the option
* @throws NullPointerException if {@code option} is {@code null}
* @see #hasArgument(String)
*/
public boolean hasArgument( OptionSpec<?> option ) {
ensureNotNull( option );
List<String> values = optionsToArguments.get( option );
return values != null && !values.isEmpty();
}
/**
* <p>Gives the argument associated with the given option. If the option was given
* an argument type, the argument will take on that type; otherwise, it will be a
* {@link String}.</p>
*
* <p>Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value}
* for an option will cause this method to return that default value even if the option was not detected on the
* command line, or if the option can take an optional argument but did not have one on the command line.</p>
*
* @param option the option to search for
* @return the argument of the given option; {@code null} if no argument is
* present, or that option was not detected
* @throws NullPointerException if {@code option} is {@code null}
* @throws OptionException if more than one argument was detected for the option
*/
public Object valueOf( String option ) {
ensureNotNull( option );
AbstractOptionSpec<?> spec = detectedOptions.get( option );
if ( spec == null ) {
List<?> defaults = defaultValuesFor( option );
return defaults.isEmpty() ? null : defaults.get( 0 );
}
return valueOf( spec );
}
/**
* <p>Gives the argument associated with the given option.</p>
*
* <p>This method recognizes only instances of options returned from the fluent
* interface methods.</p>
*
* @param <V> represents the type of the arguments the given option accepts
* @param option the option to search for
* @return the argument of the given option; {@code null} if no argument is
* present, or that option was not detected
* @throws OptionException if more than one argument was detected for the option
* @throws NullPointerException if {@code option} is {@code null}
* @throws ClassCastException if the arguments of this option are not of the
* expected type
*/
public <V> V valueOf( OptionSpec<V> option ) {
ensureNotNull( option );
List<V> values = valuesOf( option );
switch ( values.size() ) {
case 0:
return null;
case 1:
return values.get( 0 );
default:
throw new MultipleArgumentsForOptionException( option.options() );
}
}
/**
* <p>Gives any arguments associated with the given option. If the option was given
* an argument type, the arguments will take on that type; otherwise, they will be
* {@link String}s.</p>
*
* @param option the option to search for
* @return the arguments associated with the option, as a list of objects of the
* type given to the arguments; an empty list if no such arguments are present, or if
* the option was not detected
* @throws NullPointerException if {@code option} is {@code null}
*/
public List<?> valuesOf( String option ) {
ensureNotNull( option );
AbstractOptionSpec<?> spec = detectedOptions.get( option );
return spec == null ? defaultValuesFor( option ) : valuesOf( spec );
}
/**
* <p>Gives any arguments associated with the given option. If the option was given
* an argument type, the arguments will take on that type; otherwise, they will be
* {@link String}s.</p>
*
* <p>This method recognizes only instances of options returned from the fluent
* interface methods.</p>
*
* @param <V> represents the type of the arguments the given option accepts
* @param option the option to search for
* @return the arguments associated with the option; an empty list if no such
* arguments are present, or if the option was not detected
* @throws NullPointerException if {@code option} is {@code null}
* @throws OptionException if there is a problem converting the option's arguments to
* the desired type; for example, if the type does not implement a correct conversion
* constructor or method
*/
public <V> List<V> valuesOf( OptionSpec<V> option ) {
ensureNotNull( option );
List<String> values = optionsToArguments.get( option );
if ( values == null || values.isEmpty() )
return defaultValueFor( option );
AbstractOptionSpec<V> spec = (AbstractOptionSpec<V>) option;
List<V> convertedValues = new ArrayList<V>();
for ( String each : values )
convertedValues.add( spec.convert( each ) );
return unmodifiableList( convertedValues );
}
/**
* @return the detected non-option arguments
*/
public List<String> nonOptionArguments() {
return unmodifiableList( nonOptionArguments );
}
void add( AbstractOptionSpec<?> option ) {
addWithArgument( option, null );
}
void addWithArgument( AbstractOptionSpec<?> option, String argument ) {
for ( String each : option.options() )
detectedOptions.put( each, option );
List<String> optionArguments = optionsToArguments.get( option );
if ( optionArguments == null ) {
optionArguments = new ArrayList<String>();
optionsToArguments.put( option, optionArguments );
}
if ( argument != null )
optionArguments.add( argument );
}
void addNonOptionArgument( String argument ) {
nonOptionArguments.add( argument );
}
@Override
public boolean equals( Object that ) {
if ( this == that )
return true;
if ( that == null || !getClass().equals( that.getClass() ) )
return false;
OptionSet other = (OptionSet) that;
Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments =
new HashMap<AbstractOptionSpec<?>, List<String>>( optionsToArguments );
Map<AbstractOptionSpec<?>, List<String>> otherOptionsToArguments =
new HashMap<AbstractOptionSpec<?>, List<String>>( other.optionsToArguments );
return detectedOptions.equals( other.detectedOptions )
&& thisOptionsToArguments.equals( otherOptionsToArguments )
&& nonOptionArguments.equals( other.nonOptionArguments() );
}
@Override
public int hashCode() {
Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments =
new HashMap<AbstractOptionSpec<?>, List<String>>( optionsToArguments );
return detectedOptions.hashCode()
^ thisOptionsToArguments.hashCode()
^ nonOptionArguments.hashCode();
}
private <V> List<V> defaultValuesFor( String option ) {
if ( defaultValues.containsKey( option ) ) {
@SuppressWarnings( "unchecked" )
List<V> defaults = (List<V>) defaultValues.get( option );
return defaults;
}
return emptyList();
}
private <V> List<V> defaultValueFor( OptionSpec<V> option ) {
return defaultValuesFor( option.options().iterator().next() );
}
}

View File

@ -0,0 +1,95 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.Collection;
import java.util.List;
/**
* <p>Describes options that an option parser recognizes.</p>
*
* <p>Instances of this interface are returned by the "fluent interface" methods to allow
* retrieval of option arguments in a type-safe manner. Here's an example:</p>
* <pre><code>
* OptionParser parser = new OptionParser();
* <strong>OptionSpec&lt;Integer&gt;</strong> count =
* parser.accepts( "count" ).withRequiredArg().ofType( Integer.class );
* OptionSet options = parser.parse( "--count", "2" );
* assert options.has( count );
* int countValue = options.valueOf( count );
* assert countValue == count.value( options );
* List&lt;Integer&gt; countValues = options.valuesOf( count );
* assert countValues.equals( count.values( options ) );
* </code></pre>
*
* @param <V> represents the type of the arguments this option accepts
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: OptionSpec.java,v 1.25 2009/10/25 18:37:06 pholser Exp $
*/
public interface OptionSpec<V> {
/**
* <p>Gives any arguments associated with the given option in the given set of
* detected options.</p>
*
* <p>Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value}
* for this option will cause this method to return that default value even if this option was not detected on the
* command line, or if this option can take an optional argument but did not have one on the command line.</p>
*
* @param detectedOptions the detected options to search in
* @return the arguments associated with this option; an empty list if no such
* arguments are present, or if this option was not detected
* @throws OptionException if there is a problem converting this option's arguments
* to the desired type; for example, if the type does not implement a correct
* conversion constructor or method
* @throws NullPointerException if {@code detectedOptions} is {@code null}
* @see OptionSet#valuesOf(OptionSpec)
*/
List<V> values( OptionSet detectedOptions );
/**
* <p>Gives the argument associated with the given option in the given set of
* detected options.</p>
*
* <p>Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value}
* for this option will cause this method to return that default value even if this option was not detected on the
* command line, or if this option can take an optional argument but did not have one on the command line.</p>
*
* @param detectedOptions the detected options to search in
* @return the argument of the this option; {@code null} if no argument is present,
* or that option was not detected
* @throws OptionException if more than one argument was detected for the option
* @throws NullPointerException if {@code detectedOptions} is {@code null}
* @throws ClassCastException if the arguments of this option are not of the
* expected type
* @see OptionSet#valueOf(OptionSpec)
*/
V value( OptionSet detectedOptions );
/**
* @return the string representations of this option
*/
Collection<String> options();
}

View File

@ -0,0 +1,101 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.Collection;
/**
* <p>Allows callers to specify whether a given option accepts arguments (required or
* optional).</p>
*
* <p>Instances are returned from {@link OptionParser#accepts(String)} to allow the
* formation of parser directives as sentences in a "fluent interface" language. For
* example:</p>
*
* <pre><code>
* OptionParser parser = new OptionParser();
* parser.accepts( "c" ).<strong>withRequiredArg()</strong>.ofType( Integer.class );
* </code></pre>
*
* <p>If no methods are invoked on an instance of this class, then that instance's option
* will accept no argument.</p>
*
* <p>Note that you should not use the fluent interface clauses in a way that would
* defeat the typing of option arguments:</p>
*
* <pre><code>
* OptionParser parser = new OptionParser();
* ArgumentAcceptingOptionSpec&lt;String&gt; optionC =
* parser.accepts( "c" ).withRequiredArg();
* <strong>optionC.ofType( Integer.class ); // DON'T THROW AWAY THE TYPE!</strong>
*
* String value = parser.parse( "-c", "2" ).valueOf( optionC ); // ClassCastException
* </code></pre>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: OptionSpecBuilder.java,v 1.19 2009/10/25 18:37:06 pholser Exp $
*/
public class OptionSpecBuilder extends NoArgumentOptionSpec {
private final OptionParser parser;
OptionSpecBuilder( OptionParser parser, Collection<String> options, String description ) {
super( options, description );
this.parser = parser;
attachToParser();
}
private void attachToParser() {
parser.recognize( this );
}
/**
* <p>Informs an option parser that this builder's option requires an argument.</p>
*
* @return a specification for the option
*/
public ArgumentAcceptingOptionSpec<String> withRequiredArg() {
ArgumentAcceptingOptionSpec<String> newSpec =
new RequiredArgumentOptionSpec<String>( options(), description() );
parser.recognize( newSpec );
return newSpec;
}
/**
* <p>Informs an option parser that this builder's option accepts an optional
* argument.</p>
*
* @return a specification for the option
*/
public ArgumentAcceptingOptionSpec<String> withOptionalArg() {
ArgumentAcceptingOptionSpec<String> newSpec =
new OptionalArgumentOptionSpec<String>( options(), description() );
parser.recognize( newSpec );
return newSpec;
}
}

View File

@ -0,0 +1,119 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.NoSuchElementException;
import static joptsimple.ParserRules.*;
/**
* <p>Tokenizes a short option specification string.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: OptionSpecTokenizer.java,v 1.14 2009/10/25 18:37:06 pholser Exp $
*/
class OptionSpecTokenizer {
private static final char POSIXLY_CORRECT_MARKER = '+';
private String specification;
private int index;
OptionSpecTokenizer( String specification ) {
if ( specification == null )
throw new NullPointerException( "null option specification" );
this.specification = specification;
}
boolean hasMore() {
return index < specification.length();
}
AbstractOptionSpec<?> next() {
if ( !hasMore() )
throw new NoSuchElementException();
String optionCandidate = String.valueOf( specification.charAt( index ) );
index++;
AbstractOptionSpec<?> spec;
if ( RESERVED_FOR_EXTENSIONS.equals( optionCandidate ) ) {
spec = handleReservedForExtensionsToken();
if ( spec != null )
return spec;
}
ensureLegalOption( optionCandidate );
if ( hasMore() )
spec = specification.charAt( index ) == ':'
? handleArgumentAcceptingOption( optionCandidate )
: new NoArgumentOptionSpec( optionCandidate );
else
spec = new NoArgumentOptionSpec( optionCandidate );
return spec;
}
void configure( OptionParser parser ) {
adjustForPosixlyCorrect( parser );
while ( hasMore() )
parser.recognize( next() );
}
private void adjustForPosixlyCorrect( OptionParser parser ) {
if ( POSIXLY_CORRECT_MARKER == specification.charAt( 0 ) ) {
parser.posixlyCorrect( true );
specification = specification.substring( 1 );
}
}
private AbstractOptionSpec<?> handleReservedForExtensionsToken() {
if ( !hasMore() )
return new NoArgumentOptionSpec( RESERVED_FOR_EXTENSIONS );
if ( specification.charAt( index ) == ';' ) {
++index;
return new AlternativeLongOptionSpec();
}
return null;
}
private AbstractOptionSpec<?> handleArgumentAcceptingOption( String candidate ) {
index++;
if ( hasMore() && specification.charAt( index ) == ':' ) {
index++;
return new OptionalArgumentOptionSpec<String>( candidate );
}
return new RequiredArgumentOptionSpec<String>( candidate );
}
}

View File

@ -0,0 +1,42 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
/**
* <p>Visitor interface for option specifications.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: OptionSpecVisitor.java,v 1.6 2009/08/13 00:34:35 pholser Exp $
*/
interface OptionSpecVisitor {
void visit( NoArgumentOptionSpec spec );
void visit( RequiredArgumentOptionSpec<?> spec );
void visit( OptionalArgumentOptionSpec<?> spec );
void visit( AlternativeLongOptionSpec spec );
}

View File

@ -0,0 +1,75 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.Collection;
/**
* <p>Specification of an option that accepts an optional argument.</p>
*
* @param <V> represents the type of the arguments this option accepts
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: OptionalArgumentOptionSpec.java,v 1.17 2009/09/28 01:12:48 pholser Exp $
*/
class OptionalArgumentOptionSpec<V> extends ArgumentAcceptingOptionSpec<V> {
OptionalArgumentOptionSpec( String option ) {
super( option, false );
}
OptionalArgumentOptionSpec( Collection<String> options, String description ) {
super( options, false, description );
}
@Override
protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) {
if ( arguments.hasMore() ) {
String nextArgument = arguments.peek();
if ( !parser.looksLikeAnOption( nextArgument ) )
handleOptionArgument( parser, detectedOptions, arguments );
else if ( isArgumentOfNumberType() && canConvertArgument( nextArgument ) )
addArguments( detectedOptions, arguments.next() );
else
detectedOptions.add( this );
}
else
detectedOptions.add( this );
}
private void handleOptionArgument( OptionParser parser, OptionSet detectedOptions, ArgumentList arguments ) {
if ( parser.posixlyCorrect() ) {
detectedOptions.add( this );
parser.noMoreOptions();
}
else
addArguments( detectedOptions, arguments.next() );
}
@Override
void accept( OptionSpecVisitor visitor ) {
visitor.visit( this );
}
}

View File

@ -0,0 +1,88 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.Collection;
import static java.lang.Character.*;
/**
* <p>Can tell whether or not options are well-formed.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: ParserRules.java,v 1.14 2009/09/23 00:39:14 pholser Exp $
*/
final class ParserRules {
static final char HYPHEN_CHAR = '-';
static final String HYPHEN = String.valueOf( HYPHEN_CHAR );
static final String DOUBLE_HYPHEN = "--";
static final String OPTION_TERMINATOR = DOUBLE_HYPHEN;
static final String RESERVED_FOR_EXTENSIONS = "W";
static {
new ParserRules();
}
private ParserRules() {
// nothing to do here
}
static boolean isShortOptionToken( String argument ) {
return argument.startsWith( HYPHEN )
&& !HYPHEN.equals( argument )
&& !isLongOptionToken( argument );
}
static boolean isLongOptionToken( String argument ) {
return argument.startsWith( DOUBLE_HYPHEN ) && !isOptionTerminator( argument );
}
static boolean isOptionTerminator( String argument ) {
return OPTION_TERMINATOR.equals( argument );
}
static void ensureLegalOption( String option ) {
if ( option.startsWith( HYPHEN ) )
throw new IllegalOptionSpecificationException( String.valueOf( option ) );
for ( int i = 0; i < option.length(); ++i )
ensureLegalOptionCharacter( option.charAt( i ) );
}
static void ensureLegalOptions( Collection<String> options ) {
for ( String each : options )
ensureLegalOption( each );
}
private static void ensureLegalOptionCharacter( char option ) {
if ( !( isLetterOrDigit( option ) || isAllowedPunctuation( option ) ) )
throw new IllegalOptionSpecificationException( String.valueOf( option ) );
}
private static boolean isAllowedPunctuation( char option ) {
String allowedPunctuation = "?." + HYPHEN_CHAR;
return allowedPunctuation.indexOf( option ) != -1;
}
}

View File

@ -0,0 +1,58 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import java.util.Collection;
/**
* <p>Specification of an option that accepts a required argument.</p>
*
* @param <V> represents the type of the arguments this option accepts
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: RequiredArgumentOptionSpec.java,v 1.16 2009/09/28 01:12:48 pholser Exp $
*/
class RequiredArgumentOptionSpec<V> extends ArgumentAcceptingOptionSpec<V> {
RequiredArgumentOptionSpec( String option ) {
super( option, true );
}
RequiredArgumentOptionSpec( Collection<String> options, String description ) {
super( options, true, description );
}
@Override
protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) {
if ( !arguments.hasMore() )
throw new OptionMissingRequiredArgumentException( options() );
addArguments( detectedOptions, arguments.next() );
}
@Override
void accept( OptionSpecVisitor visitor ) {
visitor.visit( this );
}
}

View File

@ -0,0 +1,47 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
import static java.util.Collections.*;
/**
* <p>Thrown when the option parser encounters an unrecognized option.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: UnrecognizedOptionException.java,v 1.10 2009/10/25 18:37:06 pholser Exp $
*/
class UnrecognizedOptionException extends OptionException {
private static final long serialVersionUID = -1L;
UnrecognizedOptionException( String option ) {
super( singletonList( option ) );
}
@Override
public String getMessage() {
return singleOptionMessage() + " is not a recognized option";
}
}

View File

@ -0,0 +1,56 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
/**
* Thrown by {@link ValueConverter}s when problems occur in converting string values to
* other Java types.
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: ValueConversionException.java,v 1.5 2009/08/13 00:34:35 pholser Exp $
*/
public class ValueConversionException extends RuntimeException {
private static final long serialVersionUID = -1L;
/**
* Creates a new exception with the specified detail message.
*
* @param message the detail message
*/
public ValueConversionException( String message ) {
this( message, null );
}
/**
* Creates a new exception with the specified detail message and cause.
*
* @param message the detail message
* @param cause the original exception
*/
public ValueConversionException( String message, Throwable cause ) {
super( message, cause );
}
}

View File

@ -0,0 +1,61 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple;
/**
* Instances of this interface are used to convert arguments of options into specific
* Java types.
*
* @param <V> constraint on the type of values being converted to
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: ValueConverter.java,v 1.9 2009/08/13 00:34:35 pholser Exp $
*/
public interface ValueConverter<V> {
/**
* Converts the given string value into a Java type.
*
* @param value the string to convert
* @return the converted value
* @throws ValueConversionException if a problem occurs while converting the value
*/
V convert( String value );
/**
* Gives the class of the type of values this converter converts to.
*
* @return the target class for conversion
*/
Class<V> valueType();
/**
* Gives a string that describes the pattern of the values this converter expects,
* if any. For example, a date converter can respond with a
* {@link java.text.SimpleDateFormat date format string}.
*
* @return a value pattern, or {@code null} if there's nothing interesting here
*/
String valuePattern();
}

View File

@ -0,0 +1,239 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.internal;
import java.util.Map;
import java.util.TreeMap;
/**
* <p>A map whose keys are strings; when a key/value pair is added to the map,
* the longest unique abbreviations of that key are added as well, and associated with
* the value. Thus:</p>
*
* <pre>
* <code>
* abbreviations.put( "good", "bye" );
* </code>
* </pre>
*
* <p>would make it such that you could retrieve the value {@code "bye"} from the map
* using the keys {@code "good"}, {@code "goo"}, {@code "go"}, and {@code "g"}.
* A subsequent invocation of:</p>
* <pre>
* <code>
* abbreviations.put( "go", "fish" );
* </code>
* </pre>
*
* <p>would make it such that you could retrieve the value {@code "bye"} using the keys
* {@code "good"} and {@code "goo"}, and the value {@code "fish"} using the key
* {@code "go"}. The key {@code "g"} would yield {@code null}, since it would no longer
* be a unique abbreviation.</p>
*
* <p>The data structure is much like a "trie".</p>
*
* @param <V> a constraint on the types of the values in the map
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: AbbreviationMap.java,v 1.14 2009/10/25 18:37:08 pholser Exp $
* @see <a href="http://www.perldoc.com/perl5.8.0/lib/Text/Abbrev.html"> Perl's
* Text::Abbrev module</a>
*/
public class AbbreviationMap<V> {
private String key;
private V value;
private final Map<Character, AbbreviationMap<V>> children = new TreeMap<Character, AbbreviationMap<V>>();
private int keysBeyond;
/**
* <p>Tells whether the given key is in the map, or whether the given key is a unique
* abbreviation of a key that is in the map.</p>
*
* @param aKey key to look up
* @return {@code true} if {@code key} is present in the map
* @throws NullPointerException if {@code key} is {@code null}
*/
public boolean contains( String aKey ) {
return get( aKey ) != null;
}
/**
* <p>Answers the value associated with the given key. The key can be a unique
* abbreviation of a key that is in the map. </p>
*
* @param aKey key to look up
* @return the value associated with {@code aKey}; or {@code null} if there is no
* such value or {@code aKey} is not a unique abbreviation of a key in the map
* @throws NullPointerException if {@code aKey} is {@code null}
*/
public V get( String aKey ) {
char[] chars = charsOf( aKey );
AbbreviationMap<V> child = this;
for ( char each : chars ) {
child = child.children.get( each );
if ( child == null )
return null;
}
return child.value;
}
/**
* <p>Associates a given value with a given key. If there was a previous
* association, the old value is replaced with the new one.</p>
*
* @param aKey key to create in the map
* @param newValue value to associate with the key
* @throws NullPointerException if {@code aKey} or {@code newValue} is {@code null}
* @throws IllegalArgumentException if {@code aKey} is a zero-length string
*/
public void put( String aKey, V newValue ) {
if ( newValue == null )
throw new NullPointerException();
if ( aKey.length() == 0 )
throw new IllegalArgumentException();
char[] chars = charsOf( aKey );
add( chars, newValue, 0, chars.length );
}
/**
* <p>Associates a given value with a given set of keys. If there was a previous
* association, the old value is replaced with the new one.</p>
*
* @param keys keys to create in the map
* @param newValue value to associate with the key
* @throws NullPointerException if {@code keys} or {@code newValue} is {@code null}
* @throws IllegalArgumentException if any of {@code keys} is a zero-length string
*/
public void putAll( Iterable<String> keys, V newValue ) {
for ( String each : keys )
put( each, newValue );
}
private boolean add( char[] chars, V newValue, int offset, int length ) {
if ( offset == length ) {
value = newValue;
boolean wasAlreadyAKey = key != null;
key = new String( chars );
return !wasAlreadyAKey;
}
char nextChar = chars[ offset ];
AbbreviationMap<V> child = children.get( nextChar );
if ( child == null ) {
child = new AbbreviationMap<V>();
children.put( nextChar, child );
}
boolean newKeyAdded = child.add( chars, newValue, offset + 1, length );
if ( newKeyAdded )
++keysBeyond;
if ( key == null )
value = keysBeyond > 1 ? null : newValue;
return newKeyAdded;
}
/**
* <p>If the map contains the given key, dissociates the key from its value.</p>
*
* @param aKey key to remove
* @throws NullPointerException if {@code aKey} is {@code null}
* @throws IllegalArgumentException if {@code aKey} is a zero-length string
*/
public void remove( String aKey ) {
if ( aKey.length() == 0 )
throw new IllegalArgumentException();
char[] keyChars = charsOf( aKey );
remove( keyChars, 0, keyChars.length );
}
private boolean remove( char[] aKey, int offset, int length ) {
if ( offset == length )
return removeAtEndOfKey();
char nextChar = aKey[ offset ];
AbbreviationMap<V> child = children.get( nextChar );
if ( child == null || !child.remove( aKey, offset + 1, length ) )
return false;
--keysBeyond;
if ( child.keysBeyond == 0 )
children.remove( nextChar );
if ( keysBeyond == 1 && key == null )
setValueToThatOfOnlyChild();
return true;
}
private void setValueToThatOfOnlyChild() {
Map.Entry<Character, AbbreviationMap<V>> entry = children.entrySet().iterator().next();
AbbreviationMap<V> onlyChild = entry.getValue();
value = onlyChild.value;
}
private boolean removeAtEndOfKey() {
if ( key == null )
return false;
key = null;
if ( keysBeyond == 1 )
setValueToThatOfOnlyChild();
else
value = null;
return true;
}
/**
* Gives a Java map representation of this abbreviation map.
*
* @return a Java map corresponding to this abbreviation map
*/
public Map<String, V> toJavaUtilMap() {
Map<String, V> mappings = new TreeMap<String, V>();
addToMappings( mappings );
return mappings;
}
private void addToMappings( Map<String, V> mappings ) {
if ( key != null )
mappings.put( key, value );
for ( AbbreviationMap<V> each : children.values() )
each.addToMappings( mappings );
}
private static char[] charsOf( String aKey ) {
char[] chars = new char[ aKey.length() ];
aKey.getChars( 0, aKey.length(), chars, 0 );
return chars;
}
}

View File

@ -0,0 +1,51 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.internal;
/**
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: Classes.java,v 1.10 2009/08/13 01:05:35 pholser Exp $
*/
public final class Classes {
static {
new Classes();
}
private Classes() {
// nothing to do here
}
/**
* Gives the "short version" of the given class name. Somewhat naive to inner
* classes.
*
* @param className class name to chew on
* @return the short name of the class
*/
public static String shortNameOf( String className ) {
return className.substring( className.lastIndexOf( '.' ) + 1 );
}
}

View File

@ -0,0 +1,132 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.internal;
import java.text.BreakIterator;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import static java.lang.System.*;
import static java.text.BreakIterator.*;
import static joptsimple.internal.Strings.*;
/**
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: Column.java,v 1.16 2009/10/25 18:37:08 pholser Exp $
*/
public class Column {
static final Comparator<Column> BY_HEIGHT = new Comparator<Column>() {
public int compare( Column first, Column second ) {
if ( first.height() < second.height() )
return -1;
return first.height() == second.height() ? 0 : 1;
}
};
private final String header;
private final List<String> data;
private final int width;
private int height;
Column( String header, int width ) {
this.header = header;
this.width = Math.max( width, header.length() );
data = new LinkedList<String>();
height = 0;
}
int addCells( Object cellCandidate ) {
int originalHeight = height;
String source = String.valueOf( cellCandidate ).trim();
for ( String eachPiece : source.split( getProperty( "line.separator" ) ) )
processNextEmbeddedLine( eachPiece );
return height - originalHeight;
}
private void processNextEmbeddedLine( String line ) {
BreakIterator words = BreakIterator.getLineInstance( Locale.US );
words.setText( line );
StringBuilder nextCell = new StringBuilder();
int start = words.first();
for ( int end = words.next(); end != DONE; start = end, end = words.next() )
nextCell = processNextWord( line, nextCell, start, end );
if ( nextCell.length() > 0 )
addCell( nextCell.toString() );
}
private StringBuilder processNextWord( String source, StringBuilder nextCell, int start, int end ) {
StringBuilder augmented = nextCell;
String word = source.substring( start, end );
if ( augmented.length() + word.length() > width ) {
addCell( augmented.toString() );
augmented = new StringBuilder( " " ).append( word );
}
else
augmented.append( word );
return augmented;
}
void addCell( String newCell ) {
data.add( newCell );
++height;
}
void writeHeaderOn( StringBuilder buffer, boolean appendSpace ) {
buffer.append( header ).append( repeat( ' ', width - header.length() ) );
if ( appendSpace )
buffer.append( ' ' );
}
void writeSeparatorOn( StringBuilder buffer, boolean appendSpace ) {
buffer.append( repeat( '-', header.length() ) ).append( repeat( ' ', width - header.length() ) );
if ( appendSpace )
buffer.append( ' ' );
}
void writeCellOn( int index, StringBuilder buffer, boolean appendSpace ) {
if ( index < data.size() ) {
String item = data.get( index );
buffer.append( item ).append( repeat( ' ', width - item.length() ) );
if ( appendSpace )
buffer.append( ' ' );
}
}
int height() {
return height;
}
}

View File

@ -0,0 +1,42 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.internal;
/**
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: ColumnWidthCalculator.java,v 1.4 2009/08/13 00:34:36 pholser Exp $
*/
class ColumnWidthCalculator {
int calculate( int totalWidth, int numberOfColumns ) {
if ( numberOfColumns == 1 )
return totalWidth;
int remainder = totalWidth % numberOfColumns;
if ( remainder == numberOfColumns - 1 )
return totalWidth / numberOfColumns;
return totalWidth / numberOfColumns - 1;
}
}

View File

@ -0,0 +1,162 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.internal;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import static java.lang.Integer.*;
import static java.lang.System.*;
import static java.util.Collections.*;
import static joptsimple.internal.Column.*;
import static joptsimple.internal.Strings.*;
/**
* <p>A means to display data in a text grid.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: ColumnarData.java,v 1.17 2009/10/25 18:37:08 pholser Exp $
*/
public class ColumnarData {
private static final String LINE_SEPARATOR = getProperty( "line.separator" );
private static final int TOTAL_WIDTH = 80;
private final ColumnWidthCalculator widthCalculator;
private final List<Column> columns;
private final String[] headers;
/**
* Creates a new grid with the given column headers.
*
* @param headers column headers
*/
public ColumnarData( String... headers ) {
this.headers = headers.clone();
widthCalculator = new ColumnWidthCalculator();
columns = new LinkedList<Column>();
clear();
}
/**
* Adds a row to the grid. The data will fall under the corresponding headers.
* There can be fewer elements in the row than headers. Any data in columns outside
* of the number of headers will not be added to the grid.
*
* @param rowData row data to add
*/
public void addRow( Object... rowData ) {
int[] numberOfCellsAddedAt = addRowCells( rowData );
addPaddingCells( numberOfCellsAddedAt );
}
/**
* Gives a string that represents the data formatted in columns.
*
* @return the formatted grid
*/
public String format() {
StringBuilder buffer = new StringBuilder();
writeHeadersOn( buffer );
writeSeparatorsOn( buffer );
writeRowsOn( buffer );
return buffer.toString();
}
/**
* Removes all data from the grid, but preserves the headers.
*/
public final void clear() {
columns.clear();
int desiredColumnWidth = widthCalculator.calculate( TOTAL_WIDTH, headers.length );
for ( String each : headers )
columns.add( new Column( each, desiredColumnWidth ) );
}
private void writeHeadersOn( StringBuilder buffer ) {
for ( Iterator<Column> iter = columns.iterator(); iter.hasNext(); )
iter.next().writeHeaderOn( buffer, iter.hasNext() );
buffer.append( LINE_SEPARATOR );
}
private void writeSeparatorsOn( StringBuilder buffer ) {
for ( Iterator<Column> iter = columns.iterator(); iter.hasNext(); )
iter.next().writeSeparatorOn( buffer, iter.hasNext() );
buffer.append( LINE_SEPARATOR );
}
private void writeRowsOn( StringBuilder buffer ) {
int maxHeight = max( columns, BY_HEIGHT ).height();
for ( int i = 0; i < maxHeight; ++i )
writeRowOn( buffer, i );
}
private void writeRowOn( StringBuilder buffer, int rowIndex ) {
for ( Iterator<Column> iter = columns.iterator(); iter.hasNext(); )
iter.next().writeCellOn( rowIndex, buffer, iter.hasNext() );
buffer.append( LINE_SEPARATOR );
}
private int arrayMax( int[] numbers ) {
int maximum = MIN_VALUE;
for ( int each : numbers )
maximum = Math.max( maximum, each );
return maximum;
}
private int[] addRowCells( Object... rowData ) {
int[] cellsAddedAt = new int[ rowData.length ];
Iterator<Column> iter = columns.iterator();
for ( int i = 0; iter.hasNext() && i < rowData.length; ++i )
cellsAddedAt[ i ] = iter.next().addCells( rowData[ i ] );
return cellsAddedAt;
}
private void addPaddingCells( int... numberOfCellsAddedAt ) {
int maxHeight = arrayMax( numberOfCellsAddedAt );
Iterator<Column> iter = columns.iterator();
for ( int i = 0; iter.hasNext() && i < numberOfCellsAddedAt.length; ++i )
addPaddingCellsForColumn( iter.next(), maxHeight, numberOfCellsAddedAt[ i ] );
}
private void addPaddingCellsForColumn( Column column, int maxHeight, int numberOfCellsAdded ) {
for ( int i = 0; i < maxHeight - numberOfCellsAdded; ++i )
column.addCell( EMPTY );
}
}

View File

@ -0,0 +1,56 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.internal;
import java.lang.reflect.Constructor;
import joptsimple.ValueConverter;
import static joptsimple.internal.Reflection.*;
/**
* @param <V> constraint on the type of values being converted to
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: ConstructorInvokingValueConverter.java,v 1.4 2009/10/25 18:37:08 pholser Exp $
*/
class ConstructorInvokingValueConverter<V> implements ValueConverter<V> {
private final Constructor<V> ctor;
ConstructorInvokingValueConverter( Constructor<V> ctor ) {
this.ctor = ctor;
}
public V convert( String value ) {
return instantiate( ctor, value );
}
public Class<V> valueType() {
return ctor.getDeclaringClass();
}
public String valuePattern() {
return null;
}
}

View File

@ -0,0 +1,58 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.internal;
import java.lang.reflect.Method;
import joptsimple.ValueConverter;
import static joptsimple.internal.Reflection.*;
/**
* @param <V> constraint on the type of values being converted to
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: MethodInvokingValueConverter.java,v 1.4 2009/10/25 18:37:08 pholser Exp $
*/
class MethodInvokingValueConverter<V> implements ValueConverter<V> {
private final Method method;
private final Class<V> clazz;
MethodInvokingValueConverter( Method method, Class<V> clazz ) {
this.method = method;
this.clazz = clazz;
}
public V convert( String value ) {
return clazz.cast( invoke( method, value ) );
}
public Class<V> valueType() {
return clazz;
}
public String valuePattern() {
return null;
}
}

View File

@ -0,0 +1,51 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.internal;
/**
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: Objects.java,v 1.2 2009/10/25 18:37:08 pholser Exp $
*/
public final class Objects {
static {
new Objects();
}
private Objects() {
// nothing to do here
}
/**
* Rejects {@code null} references.
*
* @param target reference to check
* @throws NullPointerException if {@code target} is {@code null}
*/
public static void ensureNotNull( Object target ) {
if ( target == null )
throw new NullPointerException();
}
}

View File

@ -0,0 +1,142 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.internal;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static java.lang.reflect.Modifier.*;
import joptsimple.ValueConverter;
/**
* <p>Helper methods for reflection.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: Reflection.java,v 1.20 2009/09/28 01:12:48 pholser Exp $
*/
public final class Reflection {
static {
new Reflection();
}
private Reflection() {
// nothing to do here
}
/**
* Finds an appropriate value converter for the given class.
*
* @param <V> a constraint on the class object to introspect
* @param clazz class to introspect on
* @return a converter method or constructor
*/
public static <V> ValueConverter<V> findConverter( Class<V> clazz ) {
ValueConverter<V> valueOf = valueOfConverter( clazz );
if ( valueOf != null )
return valueOf;
ValueConverter<V> constructor = constructorConverter( clazz );
if ( constructor != null )
return constructor;
throw new IllegalArgumentException( clazz + " is not a value type" );
}
private static <V> ValueConverter<V> valueOfConverter( Class<V> clazz ) {
try {
Method valueOf = clazz.getDeclaredMethod( "valueOf", String.class );
if ( !meetsConverterRequirements( valueOf, clazz ) )
return null;
return new MethodInvokingValueConverter<V>( valueOf, clazz );
}
catch ( NoSuchMethodException ignored ) {
return null;
}
}
private static <V> ValueConverter<V> constructorConverter( Class<V> clazz ) {
try {
return new ConstructorInvokingValueConverter<V>(
clazz.getConstructor( String.class ) );
}
catch ( NoSuchMethodException ignored ) {
return null;
}
}
/**
* Invokes the given constructor with the given arguments.
*
* @param <T> constraint on the type of the objects yielded by the constructor
* @param constructor constructor to invoke
* @param args arguments to hand to the constructor
* @return the result of invoking the constructor
* @throws ReflectionException in lieu of the gaggle of reflection-related exceptions
*/
public static <T> T instantiate( Constructor<T> constructor, Object... args ) {
try {
return constructor.newInstance( args );
}
catch ( Exception ex ) {
throw reflectionException( ex );
}
}
/**
* Invokes the given static method with the given arguments.
*
* @param method method to invoke
* @param args arguments to hand to the method
* @return the result of invoking the method
* @throws ReflectionException in lieu of the gaggle of reflection-related exceptions
*/
public static Object invoke( Method method, Object... args ) {
try {
return method.invoke( null, args );
}
catch ( Exception ex ) {
throw reflectionException( ex );
}
}
private static boolean meetsConverterRequirements( Method method, Class<?> expectedReturnType ) {
int modifiers = method.getModifiers();
return isPublic( modifiers ) && isStatic( modifiers ) && expectedReturnType.equals( method.getReturnType() );
}
private static RuntimeException reflectionException( Exception ex ) {
if ( ex instanceof IllegalArgumentException )
return new ReflectionException( ex );
if ( ex instanceof InvocationTargetException )
return new ReflectionException( ex.getCause() );
if ( ex instanceof RuntimeException )
return (RuntimeException) ex;
return new ReflectionException( ex );
}
}

View File

@ -0,0 +1,40 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.internal;
/**
* <p>This unchecked exception wraps reflection-oriented exceptions.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: ReflectionException.java,v 1.5 2009/08/13 00:34:36 pholser Exp $
*/
public class ReflectionException extends RuntimeException {
private static final long serialVersionUID = -2L;
ReflectionException( Throwable cause ) {
super( cause.toString() );
}
}

View File

@ -0,0 +1,124 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.internal;
import java.util.Iterator;
import java.util.List;
import static java.lang.System.*;
import static java.util.Arrays.*;
/**
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: Strings.java,v 1.16 2009/08/13 01:05:35 pholser Exp $
*/
public final class Strings {
public static final String EMPTY = "";
public static final String SINGLE_QUOTE = "'";
public static final String LINE_SEPARATOR = getProperty( "line.separator" );
static {
new Strings();
}
private Strings() {
// nothing to do here
}
/**
* <p>Gives a string consisting of the given character repeated the given number of
* times.</p>
*
* @param ch the character to repeat
* @param count how many times to repeat the character
* @return the resultant string
*/
public static String repeat( char ch, int count ) {
StringBuilder buffer = new StringBuilder();
for ( int i = 0; i < count; ++i )
buffer.append( ch );
return buffer.toString();
}
/**
* <p>Tells whether the given string is either {@code} or consists solely of
* whitespace characters.</p>
*
* @param target string to check
* @return {@code true} if the target string is null or empty
*/
public static boolean isNullOrEmpty( String target ) {
return target == null || EMPTY.equals( target );
}
/**
* <p>Gives a string consisting of a given string prepended and appended with
* surrounding characters.</p>
*
* @param target a string
* @param begin character to prepend
* @param end character to append
* @return the surrounded string
*/
public static String surround( String target, char begin, char end ) {
return begin + target + end;
}
/**
* Gives a string consisting of the elements of a given array of strings, each
* separated by a given separator string.
*
* @param pieces the strings to join
* @param separator the separator
* @return the joined string
*/
public static String join( String[] pieces, String separator ) {
return join( asList( pieces ), separator );
}
/**
* Gives a string consisting of the string representations of the elements of a
* given array of objects, each separated by a given separator string.
*
* @param pieces the elements whose string representations are to be joined
* @param separator the separator
* @return the joined string
*/
public static String join( List<String> pieces, String separator ) {
StringBuilder buffer = new StringBuilder();
for ( Iterator<String> iter = pieces.iterator(); iter.hasNext(); ) {
buffer.append( iter.next() );
if ( iter.hasNext() )
buffer.append( separator );
}
return buffer.toString();
}
}

View File

@ -0,0 +1,101 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.util;
import java.text.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import joptsimple.ValueConversionException;
import joptsimple.ValueConverter;
/**
* Converts values to {@link Date}s using a {@link DateFormat} object.
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: DateConverter.java,v 1.6 2009/10/25 18:37:09 pholser Exp $
*/
public class DateConverter implements ValueConverter<Date> {
private final DateFormat formatter;
/**
* Creates a converter that uses the given date formatter/parser.
*
* @param formatter the formatter/parser to use
* @throws NullPointerException if {@code formatter} is {@code null}
*/
public DateConverter( DateFormat formatter ) {
if ( formatter == null )
throw new NullPointerException( "illegal null formatter" );
this.formatter = formatter;
}
/**
* Creates a converter that uses a {@link SimpleDateFormat} with the given date/time
* pattern. The date formatter created is not
* {@link SimpleDateFormat#setLenient(boolean) lenient}.
*
* @param pattern expected date/time pattern
* @return the new converter
* @throws NullPointerException if {@code pattern} is {@code null}
* @throws IllegalArgumentException if {@code pattern} is invalid
*/
public static DateConverter datePattern( String pattern ) {
SimpleDateFormat formatter = new SimpleDateFormat( pattern );
formatter.setLenient( false );
return new DateConverter( formatter );
}
public Date convert( String value ) {
ParsePosition position = new ParsePosition( 0 );
Date date = formatter.parse( value, position );
if ( position.getIndex() != value.length() )
throw new ValueConversionException( message( value ) );
return date;
}
public Class<Date> valueType() {
return Date.class;
}
public String valuePattern() {
return formatter instanceof SimpleDateFormat
? ( (SimpleDateFormat) formatter ).toLocalizedPattern()
: "";
}
private String message( String value ) {
String message = "Value [" + value + "] does not match date/time pattern";
if ( formatter instanceof SimpleDateFormat )
message += " [" + ( (SimpleDateFormat) formatter ).toLocalizedPattern() + ']';
return message;
}
}

View File

@ -0,0 +1,84 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.util;
import static joptsimple.internal.Strings.*;
/**
* <p>A simple string key/string value pair.</p>
*
* <p>This is useful as an argument type for options whose values take on the form
* <kbd>key=value</kbd>, such as JVM command line system properties.</p>
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: KeyValuePair.java,v 1.10 2009/10/25 18:37:09 pholser Exp $
*/
public final class KeyValuePair {
public final String key;
public final String value;
private KeyValuePair( String key, String value ) {
this.key = key;
this.value = value;
}
/**
* Parses a string assumed to be of the form <kbd>key=value</kbd> into its parts.
*
* @param asString key-value string
* @return a key-value pair
* @throws NullPointerException if {@code stringRepresentation} is {@code null}
*/
public static KeyValuePair valueOf( String asString ) {
int equalsIndex = asString.indexOf( '=' );
if ( equalsIndex == -1 )
return new KeyValuePair( asString, EMPTY );
String aKey = asString.substring( 0, equalsIndex );
String aValue = equalsIndex == asString.length() - 1 ? EMPTY : asString.substring( equalsIndex + 1 );
return new KeyValuePair( aKey, aValue );
}
@Override
public boolean equals( Object that ) {
if ( !( that instanceof KeyValuePair ) )
return false;
KeyValuePair other = (KeyValuePair) that;
return key.equals( other.key ) && value.equals( other.value );
}
@Override
public int hashCode() {
return key.hashCode() ^ value.hashCode();
}
@Override
public String toString() {
return key + '=' + value;
}
}

View File

@ -0,0 +1,86 @@
/*
The MIT License
Copyright (c) 2009 Paul R. Holser, Jr.
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.
*/
package joptsimple.util;
import java.util.regex.Pattern;
import static java.util.regex.Pattern.*;
import joptsimple.ValueConversionException;
import joptsimple.ValueConverter;
/**
* Ensures that values entirely match a regular expression.
*
* @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
* @version $Id: RegexMatcher.java,v 1.6 2009/10/25 18:37:09 pholser Exp $
*/
public class RegexMatcher implements ValueConverter<String> {
private final Pattern pattern;
/**
* Creates a matcher that uses the given regular expression, modified by the given
* flags.
*
* @param pattern the regular expression pattern
* @param flags modifying regex flags
* @throws IllegalArgumentException if bit values other than those corresponding to
* the defined match flags are set in {@code flags}
* @throws java.util.regex.PatternSyntaxException if the expression's syntax is
* invalid
*/
public RegexMatcher( String pattern, int flags ) {
this.pattern = compile( pattern, flags );
}
/**
* Gives a matcher that uses the given regular expression.
*
* @param pattern the regular expression pattern
* @return the new converter
* @throws java.util.regex.PatternSyntaxException if the expression's syntax is
* invalid
*/
public static ValueConverter<String> regex( String pattern ) {
return new RegexMatcher( pattern, 0 );
}
public String convert( String value ) {
if ( !pattern.matcher( value ).matches() ) {
throw new ValueConversionException(
"Value [" + value + "] did not match regex [" + pattern.pattern() + ']' );
}
return value;
}
public Class<String> valueType() {
return String.class;
}
public String valuePattern() {
return pattern.pattern();
}
}

View File

@ -0,0 +1,81 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* The <code>TAG_Byte_Array</code> tag.
* @author Graham Edgecombe
*
*/
public final class ByteArrayTag extends Tag {
/**
* The value.
*/
private final byte[] value;
/**
* Creates the tag.
* @param name The name.
* @param value The value.
*/
public ByteArrayTag(String name, byte[] value) {
super(name);
this.value = value;
}
@Override
public byte[] getValue() {
return value;
}
@Override
public String toString() {
StringBuilder hex = new StringBuilder();
for(byte b : value) {
String hexDigits = Integer.toHexString(b).toUpperCase();
if(hexDigits.length() == 1) {
hex.append("0");
}
hex.append(hexDigits).append(" ");
}
String name = getName();
String append = "";
if(name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Byte_Array" + append + ": " + hex.toString();
}
}

73
src/org/jnbt/ByteTag.java Normal file
View File

@ -0,0 +1,73 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* The <code>TAG_Byte</code> tag.
* @author Graham Edgecombe
*
*/
public final class ByteTag extends Tag {
/**
* The value.
*/
private final byte value;
/**
* Creates the tag.
* @param name The name.
* @param value The value.
*/
public ByteTag(String name, byte value) {
super(name);
this.value = value;
}
@Override
public Byte getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if(name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Byte" + append + ": " + value;
}
}

View File

@ -0,0 +1,82 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
import java.util.Collections;
import java.util.Map;
/**
* The <code>TAG_Compound</code> tag.
* @author Graham Edgecombe
*
*/
public final class CompoundTag extends Tag {
/**
* The value.
*/
private final Map<String, Tag> value;
/**
* Creates the tag.
* @param name The name.
* @param value The value.
*/
public CompoundTag(String name, Map<String, Tag> value) {
super(name);
this.value = Collections.unmodifiableMap(value);
}
@Override
public Map<String, Tag> getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if(name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
StringBuilder bldr = new StringBuilder();
bldr.append("TAG_Compound" + append + ": " + value.size() + " entries\r\n{\r\n");
for(Map.Entry<String, Tag> entry : value.entrySet()) {
bldr.append(" " + entry.getValue().toString().replaceAll("\r\n", "\r\n ") + "\r\n");
}
bldr.append("}");
return bldr.toString();
}
}

View File

@ -0,0 +1,73 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* The <code>TAG_Double</code> tag.
* @author Graham Edgecombe
*
*/
public final class DoubleTag extends Tag {
/**
* The value.
*/
private final double value;
/**
* Creates the tag.
* @param name The name.
* @param value The value.
*/
public DoubleTag(String name, double value) {
super(name);
this.value = value;
}
@Override
public Double getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if(name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Double" + append + ": " + value;
}
}

60
src/org/jnbt/EndTag.java Normal file
View File

@ -0,0 +1,60 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* The <code>TAG_End</code> tag.
* @author Graham Edgecombe
*
*/
public final class EndTag extends Tag {
/**
* Creates the tag.
*/
public EndTag() {
super("");
}
@Override
public Object getValue() {
return null;
}
@Override
public String toString() {
return "TAG_End";
}
}

View File

@ -0,0 +1,73 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* The <code>TAG_Float</code> tag.
* @author Graham Edgecombe
*
*/
public final class FloatTag extends Tag {
/**
* The value.
*/
private final float value;
/**
* Creates the tag.
* @param name The name.
* @param value The value.
*/
public FloatTag(String name, float value) {
super(name);
this.value = value;
}
@Override
public Float getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if(name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Float" + append + ": " + value;
}
}

73
src/org/jnbt/IntTag.java Normal file
View File

@ -0,0 +1,73 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* The <code>TAG_Int</code> tag.
* @author Graham Edgecombe
*
*/
public final class IntTag extends Tag {
/**
* The value.
*/
private final int value;
/**
* Creates the tag.
* @param name The name.
* @param value The value.
*/
public IntTag(String name, int value) {
super(name);
this.value = value;
}
@Override
public Integer getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if(name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Int" + append + ": " + value;
}
}

97
src/org/jnbt/ListTag.java Normal file
View File

@ -0,0 +1,97 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
import java.util.Collections;
import java.util.List;
/**
* The <code>TAG_List</code> tag.
* @author Graham Edgecombe
*
*/
public final class ListTag extends Tag {
/**
* The type.
*/
private final Class<? extends Tag> type;
/**
* The value.
*/
private final List<Tag> value;
/**
* Creates the tag.
* @param name The name.
* @param type The type of item in the list.
* @param value The value.
*/
public ListTag(String name, Class<? extends Tag> type, List<Tag> value) {
super(name);
this.type = type;
this.value = Collections.unmodifiableList(value);
}
/**
* Gets the type of item in this list.
* @return The type of item in this list.
*/
public Class<? extends Tag> getType() {
return type;
}
@Override
public List<Tag> getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if(name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
StringBuilder bldr = new StringBuilder();
bldr.append("TAG_List" + append + ": " + value.size() + " entries of type " + NBTUtils.getTypeName(type) + "\r\n{\r\n");
for(Tag t : value) {
bldr.append(" " + t.toString().replaceAll("\r\n", "\r\n ") + "\r\n");
}
bldr.append("}");
return bldr.toString();
}
}

73
src/org/jnbt/LongTag.java Normal file
View File

@ -0,0 +1,73 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* The <code>TAG_Long</code> tag.
* @author Graham Edgecombe
*
*/
public final class LongTag extends Tag {
/**
* The value.
*/
private final long value;
/**
* Creates the tag.
* @param name The name.
* @param value The value.
*/
public LongTag(String name, long value) {
super(name);
this.value = value;
}
@Override
public Long getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if(name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Long" + append + ": " + value;
}
}

View File

@ -0,0 +1,72 @@
package org.jnbt;
import java.nio.charset.Charset;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* A class which holds constant values.
* @author Graham Edgecombe
*
*/
public final class NBTConstants {
/**
* The character set used by NBT (UTF-8).
*/
public static final Charset CHARSET = Charset.forName("UTF-8");
/**
* Tag type constants.
*/
public static final int TYPE_END = 0,
TYPE_BYTE = 1,
TYPE_SHORT = 2,
TYPE_INT = 3,
TYPE_LONG = 4,
TYPE_FLOAT = 5,
TYPE_DOUBLE = 6,
TYPE_BYTE_ARRAY = 7,
TYPE_STRING = 8,
TYPE_LIST = 9,
TYPE_COMPOUND = 10;
/**
* Default private constructor.
*/
private NBTConstants() {
}
}

View File

@ -0,0 +1,179 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
/**
* <p>This class reads <strong>NBT</strong>, or
* <strong>Named Binary Tag</strong> streams, and produces an object graph of
* subclasses of the <code>Tag</code> object.</p>
*
* <p>The NBT format was created by Markus Persson, and the specification may
* be found at <a href="http://www.minecraft.net/docs/NBT.txt">
* http://www.minecraft.net/docs/NBT.txt</a>.</p>
* @author Graham Edgecombe
*
*/
public final class NBTInputStream implements Closeable {
/**
* The data input stream.
*/
private final DataInputStream is;
/**
* Creates a new <code>NBTInputStream</code>, which will source its data
* from the specified input stream.
* @param is The input stream.
* @throws IOException if an I/O error occurs.
*/
public NBTInputStream(InputStream is) throws IOException {
this.is = new DataInputStream(new GZIPInputStream(is));
}
/**
* Reads an NBT tag from the stream.
* @return The tag that was read.
* @throws IOException if an I/O error occurs.
*/
public Tag readTag() throws IOException {
return readTag(0);
}
/**
* Reads an NBT from the stream.
* @param depth The depth of this tag.
* @return The tag that was read.
* @throws IOException if an I/O error occurs.
*/
private Tag readTag(int depth) throws IOException {
int type = is.readByte() & 0xFF;
String name;
if(type != NBTConstants.TYPE_END) {
int nameLength = is.readShort() & 0xFFFF;
byte[] nameBytes = new byte[nameLength];
is.readFully(nameBytes);
name = new String(nameBytes, NBTConstants.CHARSET);
} else {
name = "";
}
return readTagPayload(type, name, depth);
}
/**
* Reads the payload of a tag, given the name and type.
* @param type The type.
* @param name The name.
* @param depth The depth.
* @return The tag.
* @throws IOException if an I/O error occurs.
*/
private Tag readTagPayload(int type, String name, int depth) throws IOException {
switch(type) {
case NBTConstants.TYPE_END:
if(depth == 0) {
throw new IOException("TAG_End found without a TAG_Compound/TAG_List tag preceding it.");
} else {
return new EndTag();
}
case NBTConstants.TYPE_BYTE:
return new ByteTag(name, is.readByte());
case NBTConstants.TYPE_SHORT:
return new ShortTag(name, is.readShort());
case NBTConstants.TYPE_INT:
return new IntTag(name, is.readInt());
case NBTConstants.TYPE_LONG:
return new LongTag(name, is.readLong());
case NBTConstants.TYPE_FLOAT:
return new FloatTag(name, is.readFloat());
case NBTConstants.TYPE_DOUBLE:
return new DoubleTag(name, is.readDouble());
case NBTConstants.TYPE_BYTE_ARRAY:
int length = is.readInt();
byte[] bytes = new byte[length];
is.readFully(bytes);
return new ByteArrayTag(name, bytes);
case NBTConstants.TYPE_STRING:
length = is.readShort();
bytes = new byte[length];
is.readFully(bytes);
return new StringTag(name, new String(bytes, NBTConstants.CHARSET));
case NBTConstants.TYPE_LIST:
int childType = is.readByte();
length = is.readInt();
List<Tag> tagList = new ArrayList<Tag>();
for(int i = 0; i < length; i++) {
Tag tag = readTagPayload(childType, "", depth + 1);
if(tag instanceof EndTag) {
throw new IOException("TAG_End not permitted in a list.");
}
tagList.add(tag);
}
return new ListTag(name, NBTUtils.getTypeClass(childType), tagList);
case NBTConstants.TYPE_COMPOUND:
Map<String, Tag> tagMap = new HashMap<String, Tag>();
while(true) {
Tag tag = readTag(depth + 1);
if(tag instanceof EndTag) {
break;
} else {
tagMap.put(tag.getName(), tag);
}
}
return new CompoundTag(name, tagMap);
default:
throw new IOException("Invalid tag type: " + type + ".");
}
}
@Override
public void close() throws IOException {
is.close();
}
}

View File

@ -0,0 +1,257 @@
package org.jnbt;
import java.io.Closeable;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.GZIPOutputStream;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* <p>This class writes <strong>NBT</strong>, or
* <strong>Named Binary Tag</strong> <code>Tag</code> objects to an underlying
* <code>OutputStream</code>.</p>
*
* <p>The NBT format was created by Markus Persson, and the specification may
* be found at <a href="http://www.minecraft.net/docs/NBT.txt">
* http://www.minecraft.net/docs/NBT.txt</a>.</p>
* @author Graham Edgecombe
*
*/
public final class NBTOutputStream implements Closeable {
/**
* The output stream.
*/
private final DataOutputStream os;
/**
* Creates a new <code>NBTOutputStream</code>, which will write data to the
* specified underlying output stream.
* @param os The output stream.
* @throws IOException if an I/O error occurs.
*/
public NBTOutputStream(OutputStream os) throws IOException {
this.os = new DataOutputStream(new GZIPOutputStream(os));
}
/**
* Writes a tag.
* @param tag The tag to write.
* @throws IOException if an I/O error occurs.
*/
public void writeTag(Tag tag) throws IOException {
int type = NBTUtils.getTypeCode(tag.getClass());
String name = tag.getName();
byte[] nameBytes = name.getBytes(NBTConstants.CHARSET);
os.writeByte(type);
os.writeShort(nameBytes.length);
os.write(nameBytes);
if(type == NBTConstants.TYPE_END) {
throw new IOException("Named TAG_End not permitted.");
}
writeTagPayload(tag);
}
/**
* Writes tag payload.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeTagPayload(Tag tag) throws IOException {
int type = NBTUtils.getTypeCode(tag.getClass());
switch(type) {
case NBTConstants.TYPE_END:
writeEndTagPayload((EndTag) tag);
break;
case NBTConstants.TYPE_BYTE:
writeByteTagPayload((ByteTag) tag);
break;
case NBTConstants.TYPE_SHORT:
writeShortTagPayload((ShortTag) tag);
break;
case NBTConstants.TYPE_INT:
writeIntTagPayload((IntTag) tag);
break;
case NBTConstants.TYPE_LONG:
writeLongTagPayload((LongTag) tag);
break;
case NBTConstants.TYPE_FLOAT:
writeFloatTagPayload((FloatTag) tag);
break;
case NBTConstants.TYPE_DOUBLE:
writeDoubleTagPayload((DoubleTag) tag);
break;
case NBTConstants.TYPE_BYTE_ARRAY:
writeByteArrayTagPayload((ByteArrayTag) tag);
break;
case NBTConstants.TYPE_STRING:
writeStringTagPayload((StringTag) tag);
break;
case NBTConstants.TYPE_LIST:
writeListTagPayload((ListTag) tag);
break;
case NBTConstants.TYPE_COMPOUND:
writeCompoundTagPayload((CompoundTag) tag);
break;
default:
throw new IOException("Invalid tag type: " + type + ".");
}
}
/**
* Writes a <code>TAG_Byte</code> tag.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeByteTagPayload(ByteTag tag) throws IOException {
os.writeByte(tag.getValue());
}
/**
* Writes a <code>TAG_Byte_Array</code> tag.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeByteArrayTagPayload(ByteArrayTag tag) throws IOException {
byte[] bytes = tag.getValue();
os.writeInt(bytes.length);
os.write(bytes);
}
/**
* Writes a <code>TAG_Compound</code> tag.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeCompoundTagPayload(CompoundTag tag) throws IOException {
for(Tag childTag : tag.getValue().values()) {
writeTag(childTag);
}
os.writeByte((byte) 0); // end tag - better way?
}
/**
* Writes a <code>TAG_List</code> tag.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeListTagPayload(ListTag tag) throws IOException {
Class<? extends Tag> clazz = tag.getType();
List<Tag> tags = tag.getValue();
int size = tags.size();
os.writeByte(NBTUtils.getTypeCode(clazz));
os.writeInt(size);
for(int i = 0; i < size; i++) {
writeTagPayload(tags.get(i));
}
}
/**
* Writes a <code>TAG_String</code> tag.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeStringTagPayload(StringTag tag) throws IOException {
byte[] bytes = tag.getValue().getBytes(NBTConstants.CHARSET);
os.writeShort(bytes.length);
os.write(bytes);
}
/**
* Writes a <code>TAG_Double</code> tag.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeDoubleTagPayload(DoubleTag tag) throws IOException {
os.writeDouble(tag.getValue());
}
/**
* Writes a <code>TAG_Float</code> tag.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeFloatTagPayload(FloatTag tag) throws IOException {
os.writeFloat(tag.getValue());
}
/**
* Writes a <code>TAG_Long</code> tag.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeLongTagPayload(LongTag tag) throws IOException {
os.writeLong(tag.getValue());
}
/**
* Writes a <code>TAG_Int</code> tag.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeIntTagPayload(IntTag tag) throws IOException {
os.writeInt(tag.getValue());
}
/**
* Writes a <code>TAG_Short</code> tag.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeShortTagPayload(ShortTag tag) throws IOException {
os.writeShort(tag.getValue());
}
/**
* Writes a <code>TAG_Empty</code> tag.
* @param tag The tag.
* @throws IOException if an I/O error occurs.
*/
private void writeEndTagPayload(EndTag tag) {
/* empty */
}
@Override
public void close() throws IOException {
os.close();
}
}

152
src/org/jnbt/NBTUtils.java Normal file
View File

@ -0,0 +1,152 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* A class which contains NBT-related utility methods.
* @author Graham Edgecombe
*
*/
public final class NBTUtils {
/**
* Gets the type name of a tag.
* @param clazz The tag class.
* @return The type name.
*/
public static String getTypeName(Class<? extends Tag> clazz) {
if(clazz.equals(ByteArrayTag.class)) {
return "TAG_Byte_Array";
} else if(clazz.equals(ByteTag.class)) {
return "TAG_Byte";
} else if(clazz.equals(CompoundTag.class)) {
return "TAG_Compound";
} else if(clazz.equals(DoubleTag.class)) {
return "TAG_Double";
} else if(clazz.equals(EndTag.class)) {
return "TAG_End";
} else if(clazz.equals(FloatTag.class)) {
return "TAG_Float";
} else if(clazz.equals(IntTag.class)) {
return "TAG_Int";
} else if(clazz.equals(ListTag.class)) {
return "TAG_List";
} else if(clazz.equals(LongTag.class)) {
return "TAG_Long";
} else if(clazz.equals(ShortTag.class)) {
return "TAG_Short";
} else if(clazz.equals(StringTag.class)) {
return "TAG_String";
} else {
throw new IllegalArgumentException("Invalid tag classs (" + clazz.getName() + ").");
}
}
/**
* Gets the type code of a tag class.
* @param clazz The tag class.
* @return The type code.
* @throws IllegalArgumentException if the tag class is invalid.
*/
public static int getTypeCode(Class<? extends Tag> clazz) {
if(clazz.equals(ByteArrayTag.class)) {
return NBTConstants.TYPE_BYTE_ARRAY;
} else if(clazz.equals(ByteTag.class)) {
return NBTConstants.TYPE_BYTE;
} else if(clazz.equals(CompoundTag.class)) {
return NBTConstants.TYPE_COMPOUND;
} else if(clazz.equals(DoubleTag.class)) {
return NBTConstants.TYPE_DOUBLE;
} else if(clazz.equals(EndTag.class)) {
return NBTConstants.TYPE_END;
} else if(clazz.equals(FloatTag.class)) {
return NBTConstants.TYPE_FLOAT;
} else if(clazz.equals(IntTag.class)) {
return NBTConstants.TYPE_INT;
} else if(clazz.equals(ListTag.class)) {
return NBTConstants.TYPE_LIST;
} else if(clazz.equals(LongTag.class)) {
return NBTConstants.TYPE_LONG;
} else if(clazz.equals(ShortTag.class)) {
return NBTConstants.TYPE_SHORT;
} else if(clazz.equals(StringTag.class)) {
return NBTConstants.TYPE_STRING;
} else {
throw new IllegalArgumentException("Invalid tag classs (" + clazz.getName() + ").");
}
}
/**
* Gets the class of a type of tag.
* @param type The type.
* @return The class.
* @throws IllegalArgumentException if the tag type is invalid.
*/
public static Class<? extends Tag> getTypeClass(int type) {
switch(type) {
case NBTConstants.TYPE_END:
return EndTag.class;
case NBTConstants.TYPE_BYTE:
return ByteTag.class;
case NBTConstants.TYPE_SHORT:
return ShortTag.class;
case NBTConstants.TYPE_INT:
return IntTag.class;
case NBTConstants.TYPE_LONG:
return LongTag.class;
case NBTConstants.TYPE_FLOAT:
return FloatTag.class;
case NBTConstants.TYPE_DOUBLE:
return DoubleTag.class;
case NBTConstants.TYPE_BYTE_ARRAY:
return ByteArrayTag.class;
case NBTConstants.TYPE_STRING:
return StringTag.class;
case NBTConstants.TYPE_LIST:
return ListTag.class;
case NBTConstants.TYPE_COMPOUND:
return CompoundTag.class;
default:
throw new IllegalArgumentException("Invalid tag type : " + type + ".");
}
}
/**
* Default private constructor.
*/
private NBTUtils() {
}
}

View File

@ -0,0 +1,73 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* The <code>TAG_Short</code> tag.
* @author Graham Edgecombe
*
*/
public final class ShortTag extends Tag {
/**
* The value.
*/
private final short value;
/**
* Creates the tag.
* @param name The name.
* @param value The value.
*/
public ShortTag(String name, short value) {
super(name);
this.value = value;
}
@Override
public Short getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if(name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_Short" + append + ": " + value;
}
}

View File

@ -0,0 +1,73 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* The <code>TAG_String</code> tag.
* @author Graham Edgecombe
*
*/
public final class StringTag extends Tag {
/**
* The value.
*/
private final String value;
/**
* Creates the tag.
* @param name The name.
* @param value The value.
*/
public StringTag(String name, String value) {
super(name);
this.value = value;
}
@Override
public String getValue() {
return value;
}
@Override
public String toString() {
String name = getName();
String append = "";
if(name != null && !name.equals("")) {
append = "(\"" + this.getName() + "\")";
}
return "TAG_String" + append + ": " + value;
}
}

70
src/org/jnbt/Tag.java Normal file
View File

@ -0,0 +1,70 @@
package org.jnbt;
/*
* JNBT License
*
* Copyright (c) 2010 Graham Edgecombe
* 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 JNBT team 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 HOLDER 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.
*/
/**
* Represents a single NBT tag.
* @author Graham Edgecombe
*
*/
public abstract class Tag {
/**
* The name of this tag.
*/
private final String name;
/**
* Creates the tag with the specified name.
* @param name The name.
*/
public Tag(String name) {
this.name = name;
}
/**
* Gets the name of this tag.
* @return The name of this tag.
*/
public final String getName() {
return name;
}
/**
* Gets the value of this tag.
* @return The value of this tag.
*/
public abstract Object getValue();
}