This commit is contained in:
Daniel Mills 2020-07-27 05:15:21 -04:00
parent e5e46f3239
commit e1067aeb83
14 changed files with 511 additions and 141 deletions

View File

@ -27,13 +27,17 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.zeroturnaround.zip.ZipUtil;
import com.google.gson.Gson; import com.google.gson.Gson;
import ninja.bytecode.iris.generator.IrisChunkGenerator; import ninja.bytecode.iris.generator.IrisChunkGenerator;
import ninja.bytecode.iris.object.IrisBiome; import ninja.bytecode.iris.object.IrisBiome;
import ninja.bytecode.iris.object.IrisDimension; import ninja.bytecode.iris.object.IrisDimension;
import ninja.bytecode.iris.object.IrisGenerator;
import ninja.bytecode.iris.object.IrisObject; import ninja.bytecode.iris.object.IrisObject;
import ninja.bytecode.iris.object.IrisObjectPlacement;
import ninja.bytecode.iris.object.IrisRegion;
import ninja.bytecode.iris.util.BiomeResult; import ninja.bytecode.iris.util.BiomeResult;
import ninja.bytecode.iris.util.BlockDataTools; import ninja.bytecode.iris.util.BlockDataTools;
import ninja.bytecode.iris.util.BoardManager; import ninja.bytecode.iris.util.BoardManager;
@ -51,10 +55,12 @@ import ninja.bytecode.iris.util.ScoreDirection;
import ninja.bytecode.iris.wand.WandController; import ninja.bytecode.iris.wand.WandController;
import ninja.bytecode.shuriken.collections.KList; import ninja.bytecode.shuriken.collections.KList;
import ninja.bytecode.shuriken.collections.KMap; import ninja.bytecode.shuriken.collections.KMap;
import ninja.bytecode.shuriken.collections.KSet;
import ninja.bytecode.shuriken.execution.J; import ninja.bytecode.shuriken.execution.J;
import ninja.bytecode.shuriken.format.Form; import ninja.bytecode.shuriken.format.Form;
import ninja.bytecode.shuriken.json.JSONException; import ninja.bytecode.shuriken.json.JSONException;
import ninja.bytecode.shuriken.json.JSONObject; import ninja.bytecode.shuriken.json.JSONObject;
import ninja.bytecode.shuriken.logging.L;
import ninja.bytecode.shuriken.math.RollingSequence; import ninja.bytecode.shuriken.math.RollingSequence;
import ninja.bytecode.shuriken.reaction.O; import ninja.bytecode.shuriken.reaction.O;
import ninja.bytecode.shuriken.tools.JarScanner; import ninja.bytecode.shuriken.tools.JarScanner;
@ -587,6 +593,114 @@ public class Iris extends JavaPlugin implements BoardProvider
} }
} }
if(args[0].equalsIgnoreCase("package") || args[0].equalsIgnoreCase("pkg"))
{
String dim = "overworld";
if(args.length > 1)
{
dim = args[1];
}
boolean obfuscate = false;
for(String i : args)
{
if(i.equalsIgnoreCase("-o"))
{
obfuscate = true;
}
}
String dimm = dim;
IrisDimension dimension = data.getDimensionLoader().load(dimm);
File folder = new File(getDataFolder(), "exports/" + dimension.getLoadKey());
folder.mkdirs();
Iris.info("Packaging Dimension " + dimension.getName());
KSet<IrisRegion> regions = new KSet<>();
KSet<IrisBiome> biomes = new KSet<>();
KSet<IrisGenerator> generators = new KSet<>();
dimension.getRegions().forEach((i) -> regions.add(data.getRegionLoader().load(i)));
regions.forEach((i) -> biomes.addAll(i.getAllBiomes()));
biomes.forEach((i) -> i.getGenerators().forEach((j) -> generators.add(j.getCachedGenerator())));
KMap<String, String> renameObjects = new KMap<>();
for(IrisBiome i : biomes)
{
for(IrisObjectPlacement j : i.getObjects())
{
KList<String> newNames = new KList<>();
for(String k : j.getPlace())
{
if(renameObjects.containsKey(k))
{
newNames.add(renameObjects.get(k));
continue;
}
String name = obfuscate ? UUID.randomUUID().toString().replaceAll("-", "") : k;
newNames.add(name);
renameObjects.put(k, name);
}
if(obfuscate)
{
j.setPlace(newNames);
}
}
}
KMap<String, KList<String>> lookupObjects = renameObjects.flip();
biomes.forEach((i) -> i.getObjects().forEach((j) -> j.getPlace().forEach((k) ->
{
try
{
Iris.info("- " + k + " (Object)");
IO.copyFile(Iris.data.getObjectLoader().findFile(lookupObjects.get(k).get(0)), new File(folder, "objects/" + k + ".iob"));
}
catch(Throwable e)
{
}
})));
try
{
IO.writeAll(new File(folder, "dimensions/" + dimension.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(dimension)).toString(0));
for(IrisGenerator i : generators)
{
Iris.info("- " + i.getLoadKey() + " (Generator)");
IO.writeAll(new File(folder, "generators/" + i.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(i)).toString(0));
}
for(IrisRegion i : regions)
{
Iris.info("- " + i.getName() + " (Region)");
IO.writeAll(new File(folder, "regions/" + i.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(i)).toString(0));
}
for(IrisBiome i : biomes)
{
Iris.info("- " + i.getName() + " (Biome)");
IO.writeAll(new File(folder, "biomes/" + i.getLoadKey() + ".json"), new JSONObject(new Gson().toJson(i)).toString(0));
}
ZipUtil.pack(folder, new File(getDataFolder(), "exports/" + dimension.getLoadKey() + ".iris"));
IO.delete(folder);
}
catch(Throwable e)
{
L.ex(e);
}
sender.sendMessage("Done!");
}
if(args[0].equalsIgnoreCase("dev")) if(args[0].equalsIgnoreCase("dev"))
{ {
String dim = "overworld"; String dim = "overworld";

View File

@ -9,14 +9,17 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import ninja.bytecode.iris.Iris; import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.IrisContext; import ninja.bytecode.iris.IrisContext;
import ninja.bytecode.iris.object.IrisBiome;
import ninja.bytecode.iris.object.IrisRegion; import ninja.bytecode.iris.object.IrisRegion;
import ninja.bytecode.iris.util.BiomeResult; import ninja.bytecode.iris.util.BiomeResult;
import ninja.bytecode.shuriken.collections.KMap;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class IrisChunkGenerator extends CeilingChunkGenerator implements IrisContext public class IrisChunkGenerator extends CeilingChunkGenerator implements IrisContext
{ {
private Method initLighting; private Method initLighting;
private KMap<Player, IrisBiome> b = new KMap<>();
public IrisChunkGenerator(String dimensionName, int threads) public IrisChunkGenerator(String dimensionName, int threads)
{ {

View File

@ -8,6 +8,8 @@ import org.bukkit.block.data.BlockData;
import ninja.bytecode.iris.Iris; import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.layer.post.PostNippleSmoother; import ninja.bytecode.iris.layer.post.PostNippleSmoother;
import ninja.bytecode.iris.layer.post.PostPotholeFiller; import ninja.bytecode.iris.layer.post.PostPotholeFiller;
import ninja.bytecode.iris.layer.post.PostSlabber;
import ninja.bytecode.iris.layer.post.PostWallPatcher;
import ninja.bytecode.iris.object.IrisDimension; import ninja.bytecode.iris.object.IrisDimension;
import ninja.bytecode.iris.util.IPostBlockAccess; import ninja.bytecode.iris.util.IPostBlockAccess;
import ninja.bytecode.iris.util.IrisPostBlockFilter; import ninja.bytecode.iris.util.IrisPostBlockFilter;
@ -40,12 +42,20 @@ public abstract class PostBlockChunkGenerator extends ParallaxChunkGenerator imp
super.onInit(world, rng); super.onInit(world, rng);
filters.add(new PostNippleSmoother(this)); filters.add(new PostNippleSmoother(this));
filters.add(new PostPotholeFiller(this)); filters.add(new PostPotholeFiller(this));
filters.add(new PostWallPatcher(this));
filters.add(new PostSlabber(this));
} }
@Override @Override
protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid) protected void onGenerate(RNG random, int x, int z, ChunkData data, BiomeGrid grid)
{ {
super.onGenerate(random, x, z, data, grid); super.onGenerate(random, x, z, data, grid);
if(!getDimension().isPostProcess())
{
return;
}
currentData = data; currentData = data;
currentPostX = x; currentPostX = x;
currentPostZ = z; currentPostZ = z;
@ -64,7 +74,10 @@ public abstract class PostBlockChunkGenerator extends ParallaxChunkGenerator imp
{ {
for(IrisPostBlockFilter f : filters) for(IrisPostBlockFilter f : filters)
{ {
f.onPost(rxx, rzz); int rxxx = rxx;
int rzzx = rzz;
f.onPost(rxxx, rzzx);
} }
}); });
} }

View File

@ -17,6 +17,7 @@ import ninja.bytecode.iris.object.IrisRegion;
import ninja.bytecode.iris.object.atomics.AtomicSliver; import ninja.bytecode.iris.object.atomics.AtomicSliver;
import ninja.bytecode.iris.util.BiomeMap; import ninja.bytecode.iris.util.BiomeMap;
import ninja.bytecode.iris.util.BiomeResult; import ninja.bytecode.iris.util.BiomeResult;
import ninja.bytecode.iris.util.BlockDataTools;
import ninja.bytecode.iris.util.HeightMap; import ninja.bytecode.iris.util.HeightMap;
import ninja.bytecode.iris.util.RNG; import ninja.bytecode.iris.util.RNG;
import ninja.bytecode.shuriken.collections.KList; import ninja.bytecode.shuriken.collections.KList;
@ -132,11 +133,24 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
} }
} }
if(onto.equals(Material.ACACIA_LEAVES) || onto.equals(Material.BIRCH_LEAVES) || onto.equals(Material.DARK_OAK_LEAVES) || onto.equals(Material.JUNGLE_LEAVES) || onto.equals(Material.OAK_LEAVES) || onto.equals(Material.SPRUCE_LEAVES))
{
if(!mat.isSolid())
{
return false;
}
}
return true; return true;
} }
private void decorateLand(IrisBiome biome, AtomicSliver sliver, double wx, int k, double wz, int rx, int rz, BlockData block) private void decorateLand(IrisBiome biome, AtomicSliver sliver, double wx, int k, double wz, int rx, int rz, BlockData block)
{ {
if(!getDimension().isDecorate())
{
return;
}
int j = 0; int j = 0;
for(IrisBiomeDecorator i : biome.getDecorators()) for(IrisBiomeDecorator i : biome.getDecorators())
@ -155,6 +169,14 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
continue; continue;
} }
if(d.getMaterial().equals(Material.CACTUS))
{
if(!block.getMaterial().equals(Material.SAND) && !block.getMaterial().equals(Material.RED_SAND))
{
sliver.set(k, BlockDataTools.getBlockData("RED_SAND"));
}
}
if(d instanceof Bisected && k < 254) if(d instanceof Bisected && k < 254)
{ {
Bisected t = ((Bisected) d.clone()); Bisected t = ((Bisected) d.clone());
@ -190,6 +212,11 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
private void decorateUnderwater(IrisBiome biome, AtomicSliver sliver, double wx, int y, double wz, int rx, int rz, BlockData block) private void decorateUnderwater(IrisBiome biome, AtomicSliver sliver, double wx, int y, double wz, int rx, int rz, BlockData block)
{ {
if(!getDimension().isDecorate())
{
return;
}
int j = 0; int j = 0;
for(IrisBiomeDecorator i : biome.getDecorators()) for(IrisBiomeDecorator i : biome.getDecorators())
@ -257,7 +284,7 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
double wx = getModifiedX(x, z); double wx = getModifiedX(x, z);
double wz = getModifiedZ(x, z); double wz = getModifiedZ(x, z);
IrisRegion region = sampleRegion(x, z); IrisRegion region = sampleRegion(x, z);
int height = sampleHeight(x, z); int height = (int) Math.round(getTerrainHeight(x, z));
double sh = region.getShoreHeight(wx, wz); double sh = region.getShoreHeight(wx, wz);
IrisBiome current = sampleBiome(x, z).getBiome(); IrisBiome current = sampleBiome(x, z).getBiome();

View File

@ -29,9 +29,9 @@ public class GenLayerCave extends GenLayer
{ {
//@builder //@builder
super(iris, rng); super(iris, rng);
shuffle = CNG.signature(rng.nextParallelRNG(2348566)); shuffle = CNG.signature(rng.nextParallelRNG(1348566));
gincline = new CNG(rng.nextParallelRNG(1112), 1D, 3).scale(0.00452); gincline = new CNG(rng.nextParallelRNG(26512), 1D, 3).scale(0.00452);
gg = new FastNoise(324895 * rng.nextParallelRNG(45678).imax()); gg = new FastNoise(324895 * rng.nextParallelRNG(49678).imax());
//@done //@done
} }

View File

@ -0,0 +1,50 @@
package ninja.bytecode.iris.layer.post;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import ninja.bytecode.iris.generator.PostBlockChunkGenerator;
import ninja.bytecode.iris.util.IrisPostBlockFilter;
import ninja.bytecode.iris.util.RNG;
public class PostSlabber extends IrisPostBlockFilter
{
public static final Material AIR = Material.AIR;
public static final Material WATER = Material.WATER;
private RNG rng;
public PostSlabber(PostBlockChunkGenerator gen)
{
super(gen);
rng = gen.getMasterRandom().nextParallelRNG(1239456);
}
@Override
public void onPost(int x, int z)
{
int h = highestTerrainBlock(x, z);
if(highestTerrainBlock(x + 1, z) == h + 1 || highestTerrainBlock(x, z + 1) == h + 1 || highestTerrainBlock(x - 1, z) == h + 1 || highestTerrainBlock(x, z - 1) == h + 1)
{
BlockData d = gen.sampleTrueBiome(x, z).getBiome().getSlab().get(rng, x, h, z);
if(d != null)
{
if(d.getMaterial().equals(AIR))
{
return;
}
if(d instanceof Waterlogged)
{
((Waterlogged) d).setWaterlogged(getPostBlock(x, h + 1, z).getMaterial().equals(Material.WATER));
}
if(getPostBlock(x, h + 2, z).getMaterial().equals(AIR) || getPostBlock(x, h + 2, z).getMaterial().equals(WATER))
{
setPostBlock(x, h + 1, z, d);
}
}
}
}
}

View File

@ -0,0 +1,56 @@
package ninja.bytecode.iris.layer.post;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import ninja.bytecode.iris.generator.PostBlockChunkGenerator;
import ninja.bytecode.iris.object.IrisBiome;
import ninja.bytecode.iris.util.IrisPostBlockFilter;
import ninja.bytecode.iris.util.RNG;
public class PostWallPatcher extends IrisPostBlockFilter
{
public static final Material AIR = Material.AIR;
private RNG rng;
public PostWallPatcher(PostBlockChunkGenerator gen)
{
super(gen);
rng = gen.getMasterRandom().nextParallelRNG(1239456);
}
@Override
public void onPost(int x, int z)
{
IrisBiome biome = gen.sampleTrueBiome(x, z).getBiome();
if(!biome.getWall().getPalette().isEmpty())
{
int h = highestTerrainBlock(x, z);
int ha = highestTerrainBlock(x + 1, z);
int hb = highestTerrainBlock(x, z + 1);
int hc = highestTerrainBlock(x - 1, z);
int hd = highestTerrainBlock(x, z - 1);
if(ha < h - 2 || hb < h - 2 || hc < h - 2 || hd < h - 2)
{
int max = Math.abs(Math.max(h - ha, Math.max(h - hb, Math.max(h - hc, h - hd))));
for(int i = h; i > h - max; i--)
{
BlockData d = biome.getWall().get(rng, x + i, i + h, z + i);
if(d != null)
{
if(d.getMaterial().equals(AIR))
{
continue;
}
setPostBlock(x, i, z, d);
}
}
}
}
}
}

View File

@ -49,6 +49,12 @@ public class IrisBiome extends IrisRegistrant
@Desc("List any biome names (file names without.json) here as children. Portions of this biome can sometimes morph into their children. Iris supports cyclic relationships such as A > B > A > B. Iris will stop checking 9 biomes down the tree.") @Desc("List any biome names (file names without.json) here as children. Portions of this biome can sometimes morph into their children. Iris supports cyclic relationships such as A > B > A > B. Iris will stop checking 9 biomes down the tree.")
private KList<String> children = new KList<>(); private KList<String> children = new KList<>();
@Desc("The default slab if iris decides to place a slab in this biome. Default is no slab.")
private IrisBiomePaletteLayer slab = new IrisBiomePaletteLayer().zero();
@Desc("The default wall if iris decides to place a wall higher than 2 blocks (steep hills or possibly cliffs)")
private IrisBiomePaletteLayer wall = new IrisBiomePaletteLayer().zero();
@Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.") @Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.")
private KList<IrisBiomePaletteLayer> layers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer()); private KList<IrisBiomePaletteLayer> layers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer());

View File

@ -65,6 +65,11 @@ public class IrisBiomePaletteLayer
} }
} }
if(getBlockData().isEmpty())
{
return null;
}
return getBlockData().get(0); return getBlockData().get(0);
} }
@ -109,4 +114,10 @@ public class IrisBiomePaletteLayer
return blockData; return blockData;
} }
public IrisBiomePaletteLayer zero()
{
palette.clear();
return this;
}
} }

View File

@ -39,6 +39,15 @@ public class IrisDimension extends IrisRegistrant
@Desc("Generate caves or not.") @Desc("Generate caves or not.")
private boolean caves = true; private boolean caves = true;
@Desc("Carve terrain or not")
private boolean carving = true;
@Desc("Generate decorations or not")
private boolean decorate = true;
@Desc("Use post processing features. Usually for production only as there is a gen speed cost.")
private boolean postProcess = true;
@Desc("The ceiling dimension. Leave blank for normal sky.") @Desc("The ceiling dimension. Leave blank for normal sky.")
private String ceiling = ""; private String ceiling = "";

View File

@ -4,10 +4,13 @@ import java.util.concurrent.locks.ReentrantLock;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.util.CNG; import ninja.bytecode.iris.util.CNG;
import ninja.bytecode.iris.util.Desc; import ninja.bytecode.iris.util.Desc;
import ninja.bytecode.iris.util.RNG; import ninja.bytecode.iris.util.RNG;
import ninja.bytecode.shuriken.collections.KList; import ninja.bytecode.shuriken.collections.KList;
import ninja.bytecode.shuriken.collections.KMap;
import ninja.bytecode.shuriken.collections.KSet;
@Desc("Represents an iris region") @Desc("Represents an iris region")
@Data @Data
@ -91,4 +94,34 @@ public class IrisRegion extends IrisRegistrant
return shoreHeightGenerator.fitDoubleD(shoreHeightMin, shoreHeightMax, x / shoreHeightZoom, z / shoreHeightZoom); return shoreHeightGenerator.fitDoubleD(shoreHeightMin, shoreHeightMax, x / shoreHeightZoom, z / shoreHeightZoom);
} }
public KList<IrisBiome> getAllBiomes()
{
KMap<String, IrisBiome> b = new KMap<>();
KSet<String> names = new KSet<>();
names.addAll(landBiomes);
names.addAll(seaBiomes);
names.addAll(shoreBiomes);
spotBiomes.forEach((i) -> names.add(i.getBiome()));
ridgeBiomes.forEach((i) -> names.add(i.getBiome()));
while(!names.isEmpty())
{
for(String i : new KList<>(names))
{
if(b.containsKey(i))
{
names.remove(i);
continue;
}
IrisBiome biome = Iris.data.getBiomeLoader().load(i);
b.put(biome.getLoadKey(), biome);
names.remove(i);
names.addAll(biome.getChildren());
}
}
return b.v();
}
} }

View File

@ -7,6 +7,7 @@ import java.io.IOException;
import org.bukkit.World; import org.bukkit.World;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.util.ChronoLatch; import ninja.bytecode.iris.util.ChronoLatch;
import ninja.bytecode.iris.util.ChunkPosition; import ninja.bytecode.iris.util.ChunkPosition;
import ninja.bytecode.shuriken.collections.KMap; import ninja.bytecode.shuriken.collections.KMap;
@ -18,6 +19,7 @@ public class AtomicWorldData
private KMap<ChunkPosition, AtomicSliverMap> loadedChunks; private KMap<ChunkPosition, AtomicSliverMap> loadedChunks;
private KMap<ChunkPosition, AtomicRegionData> loadedSections; private KMap<ChunkPosition, AtomicRegionData> loadedSections;
private KMap<ChunkPosition, Long> lastRegion; private KMap<ChunkPosition, Long> lastRegion;
private KMap<ChunkPosition, Long> lastChunk;
private String prefix; private String prefix;
private ChronoLatch cl = new ChronoLatch(15000); private ChronoLatch cl = new ChronoLatch(15000);
@ -27,6 +29,7 @@ public class AtomicWorldData
loadedSections = new KMap<>(); loadedSections = new KMap<>();
loadedChunks = new KMap<>(); loadedChunks = new KMap<>();
lastRegion = new KMap<>(); lastRegion = new KMap<>();
lastChunk = new KMap<>();
this.prefix = prefix; this.prefix = prefix;
getSubregionFolder().mkdirs(); getSubregionFolder().mkdirs();
} }
@ -165,7 +168,7 @@ public class AtomicWorldData
public AtomicSliverMap loadChunk(int x, int z) throws IOException public AtomicSliverMap loadChunk(int x, int z) throws IOException
{ {
ChunkPosition pos = new ChunkPosition(x, z); ChunkPosition pos = new ChunkPosition(x, z);
lastChunk.put(pos, M.ms());
if(loadedChunks.containsKey(pos)) if(loadedChunks.containsKey(pos))
{ {
return loadedChunks.get(pos); return loadedChunks.get(pos);
@ -262,5 +265,21 @@ public class AtomicWorldData
} }
} }
} }
for(ChunkPosition i : lastChunk.k())
{
if(M.ms() - lastChunk.get(i) > 60000)
{
try
{
saveChunk(i);
}
catch(IOException e)
{
Iris.warn("Failed to save chunk");
}
}
}
} }
} }

View File

@ -61,7 +61,7 @@ public class IO
* The system line separator string. * The system line separator string.
*/ */
public static final String LINE_SEPARATOR; public static final String LINE_SEPARATOR;
/** /**
* The default buffer size to use. * The default buffer size to use.
*/ */
@ -128,7 +128,7 @@ public class IO
return new String(hexChars).toUpperCase(); return new String(hexChars).toUpperCase();
} }
/** /**
* Transfers the length of the buffer amount of data from the input stream to * Transfers the length of the buffer amount of data from the input stream to
* the output stream * the output stream
@ -378,6 +378,7 @@ public class IO
public static void writeAll(File f, Object c) throws IOException public static void writeAll(File f, Object c) throws IOException
{ {
f.getParentFile().mkdirs();
PrintWriter pw = new PrintWriter(new FileWriter(f)); PrintWriter pw = new PrintWriter(new FileWriter(f));
pw.println(c.toString()); pw.println(c.toString());
pw.close(); pw.close();
@ -567,13 +568,13 @@ public class IO
destFile.setLastModified(srcFile.lastModified()); destFile.setLastModified(srcFile.lastModified());
} }
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
* Unconditionally close an <code>Reader</code>. * Unconditionally close an <code>Reader</code>.
* <p> * <p>
* Equivalent to {@link Reader#close()}, except any exceptions will be * Equivalent to {@link Reader#close()}, except any exceptions will be ignored.
* ignored. This is typically used in finally blocks. * This is typically used in finally blocks.
* *
* @param input * @param input
* the Reader to close, may be null or already closed * the Reader to close, may be null or already closed
@ -586,17 +587,18 @@ public class IO
{ {
input.close(); input.close();
} }
} catch(IOException ioe) }
catch(IOException ioe)
{ {
// ignore // ignore
} }
} }
/** /**
* Unconditionally close a <code>Writer</code>. * Unconditionally close a <code>Writer</code>.
* <p> * <p>
* Equivalent to {@link Writer#close()}, except any exceptions will be * Equivalent to {@link Writer#close()}, except any exceptions will be ignored.
* ignored. This is typically used in finally blocks. * This is typically used in finally blocks.
* *
* @param output * @param output
* the Writer to close, may be null or already closed * the Writer to close, may be null or already closed
@ -609,12 +611,13 @@ public class IO
{ {
output.close(); output.close();
} }
} catch(IOException ioe) }
catch(IOException ioe)
{ {
// ignore // ignore
} }
} }
/** /**
* Unconditionally close an <code>InputStream</code>. * Unconditionally close an <code>InputStream</code>.
* <p> * <p>
@ -632,12 +635,13 @@ public class IO
{ {
input.close(); input.close();
} }
} catch(IOException ioe) }
catch(IOException ioe)
{ {
// ignore // ignore
} }
} }
/** /**
* Unconditionally close an <code>OutputStream</code>. * Unconditionally close an <code>OutputStream</code>.
* <p> * <p>
@ -655,12 +659,13 @@ public class IO
{ {
output.close(); output.close();
} }
} catch(IOException ioe) }
catch(IOException ioe)
{ {
// ignore // ignore
} }
} }
// read toByteArray // read toByteArray
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
@ -683,10 +688,10 @@ public class IO
copy(input, output); copy(input, output);
return output.toByteArray(); return output.toByteArray();
} }
/** /**
* Get the contents of a <code>Reader</code> as a <code>byte[]</code> using * Get the contents of a <code>Reader</code> as a <code>byte[]</code> using the
* the default character encoding of the platform. * default character encoding of the platform.
* <p> * <p>
* This method buffers the input internally, so there is no need to use a * This method buffers the input internally, so there is no need to use a
* <code>BufferedReader</code>. * <code>BufferedReader</code>.
@ -705,10 +710,10 @@ public class IO
copy(input, output); copy(input, output);
return output.toByteArray(); return output.toByteArray();
} }
/** /**
* Get the contents of a <code>Reader</code> as a <code>byte[]</code> using * Get the contents of a <code>Reader</code> as a <code>byte[]</code> using the
* the specified character encoding. * specified character encoding.
* <p> * <p>
* Character encoding names can be found at * Character encoding names can be found at
* <a href="http://www.iana.org/assignments/character-sets">IANA</a>. * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
@ -733,10 +738,10 @@ public class IO
copy(input, output, encoding); copy(input, output, encoding);
return output.toByteArray(); return output.toByteArray();
} }
/** /**
* Get the contents of a <code>String</code> as a <code>byte[]</code> using * Get the contents of a <code>String</code> as a <code>byte[]</code> using the
* the default character encoding of the platform. * default character encoding of the platform.
* <p> * <p>
* This is the same as {@link String#getBytes()}. * This is the same as {@link String#getBytes()}.
* *
@ -753,12 +758,12 @@ public class IO
{ {
return input.getBytes(); return input.getBytes();
} }
// read char[] // read char[]
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
* Get the contents of an <code>InputStream</code> as a character array * Get the contents of an <code>InputStream</code> as a character array using
* using the default character encoding of the platform. * the default character encoding of the platform.
* <p> * <p>
* This method buffers the input internally, so there is no need to use a * This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>. * <code>BufferedInputStream</code>.
@ -778,10 +783,10 @@ public class IO
copy(is, output); copy(is, output);
return output.toCharArray(); return output.toCharArray();
} }
/** /**
* Get the contents of an <code>InputStream</code> as a character array * Get the contents of an <code>InputStream</code> as a character array using
* using the specified character encoding. * the specified character encoding.
* <p> * <p>
* Character encoding names can be found at * Character encoding names can be found at
* <a href="http://www.iana.org/assignments/character-sets">IANA</a>. * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
@ -806,7 +811,7 @@ public class IO
copy(is, output, encoding); copy(is, output, encoding);
return output.toCharArray(); return output.toCharArray();
} }
/** /**
* Get the contents of a <code>Reader</code> as a character array. * Get the contents of a <code>Reader</code> as a character array.
* <p> * <p>
@ -828,12 +833,12 @@ public class IO
copy(input, sw); copy(input, sw);
return sw.toCharArray(); return sw.toCharArray();
} }
// read toString // read toString
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
* Get the contents of an <code>InputStream</code> as a String using the * Get the contents of an <code>InputStream</code> as a String using the default
* default character encoding of the platform. * character encoding of the platform.
* <p> * <p>
* This method buffers the input internally, so there is no need to use a * This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>. * <code>BufferedInputStream</code>.
@ -852,7 +857,7 @@ public class IO
copy(input, sw); copy(input, sw);
return sw.toString(); return sw.toString();
} }
/** /**
* Get the contents of an <code>InputStream</code> as a String using the * Get the contents of an <code>InputStream</code> as a String using the
* specified character encoding. * specified character encoding.
@ -879,7 +884,7 @@ public class IO
copy(input, sw, encoding); copy(input, sw, encoding);
return sw.toString(); return sw.toString();
} }
/** /**
* Get the contents of a <code>Reader</code> as a String. * Get the contents of a <code>Reader</code> as a String.
* <p> * <p>
@ -900,7 +905,7 @@ public class IO
copy(input, sw); copy(input, sw);
return sw.toString(); return sw.toString();
} }
/** /**
* Get the contents of a <code>byte[]</code> as a String using the default * Get the contents of a <code>byte[]</code> as a String using the default
* character encoding of the platform. * character encoding of the platform.
@ -918,7 +923,7 @@ public class IO
{ {
return new String(input); return new String(input);
} }
/** /**
* Get the contents of a <code>byte[]</code> as a String using the specified * Get the contents of a <code>byte[]</code> as a String using the specified
* character encoding. * character encoding.
@ -942,12 +947,13 @@ public class IO
if(encoding == null) if(encoding == null)
{ {
return new String(input); return new String(input);
} else }
else
{ {
return new String(input, encoding); return new String(input, encoding);
} }
} }
// readLines // readLines
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
@ -971,7 +977,7 @@ public class IO
InputStreamReader reader = new InputStreamReader(input); InputStreamReader reader = new InputStreamReader(input);
return readLines(reader); return readLines(reader);
} }
/** /**
* Get the contents of an <code>InputStream</code> as a list of Strings, one * Get the contents of an <code>InputStream</code> as a list of Strings, one
* entry per line, using the specified character encoding. * entry per line, using the specified character encoding.
@ -998,16 +1004,17 @@ public class IO
if(encoding == null) if(encoding == null)
{ {
return readLines(input); return readLines(input);
} else }
else
{ {
InputStreamReader reader = new InputStreamReader(input, encoding); InputStreamReader reader = new InputStreamReader(input, encoding);
return readLines(reader); return readLines(reader);
} }
} }
/** /**
* Get the contents of a <code>Reader</code> as a list of Strings, one entry * Get the contents of a <code>Reader</code> as a list of Strings, one entry per
* per line. * line.
* <p> * <p>
* This method buffers the input internally, so there is no need to use a * This method buffers the input internally, so there is no need to use a
* <code>BufferedReader</code>. * <code>BufferedReader</code>.
@ -1033,11 +1040,11 @@ public class IO
} }
return list; return list;
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
* Convert the specified string to an input stream, encoded as bytes using * Convert the specified string to an input stream, encoded as bytes using the
* the default character encoding of the platform. * default character encoding of the platform.
* *
* @param input * @param input
* the string to convert * the string to convert
@ -1049,10 +1056,10 @@ public class IO
byte[] bytes = input.getBytes(); byte[] bytes = input.getBytes();
return new ByteArrayInputStream(bytes); return new ByteArrayInputStream(bytes);
} }
/** /**
* Convert the specified string to an input stream, encoded as bytes using * Convert the specified string to an input stream, encoded as bytes using the
* the specified character encoding. * specified character encoding.
* <p> * <p>
* Character encoding names can be found at * Character encoding names can be found at
* <a href="http://www.iana.org/assignments/character-sets">IANA</a>. * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
@ -1071,15 +1078,14 @@ public class IO
byte[] bytes = encoding != null ? input.getBytes(encoding) : input.getBytes(); byte[] bytes = encoding != null ? input.getBytes(encoding) : input.getBytes();
return new ByteArrayInputStream(bytes); return new ByteArrayInputStream(bytes);
} }
// write byte[] // write byte[]
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
* Writes bytes from a <code>byte[]</code> to an <code>OutputStream</code>. * Writes bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
* *
* @param data * @param data
* the byte array to write, do not modify during output, null * the byte array to write, do not modify during output, null ignored
* ignored
* @param output * @param output
* the <code>OutputStream</code> to write to * the <code>OutputStream</code> to write to
* @throws NullPointerException * @throws NullPointerException
@ -1095,7 +1101,7 @@ public class IO
output.write(data); output.write(data);
} }
} }
/** /**
* Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code> * Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code>
* using the default character encoding of the platform. * using the default character encoding of the platform.
@ -1103,8 +1109,7 @@ public class IO
* This method uses {@link String#String(byte[])}. * This method uses {@link String#String(byte[])}.
* *
* @param data * @param data
* the byte array to write, do not modify during output, null * the byte array to write, do not modify during output, null ignored
* ignored
* @param output * @param output
* the <code>Writer</code> to write to * the <code>Writer</code> to write to
* @throws NullPointerException * @throws NullPointerException
@ -1120,7 +1125,7 @@ public class IO
output.write(new String(data)); output.write(new String(data));
} }
} }
/** /**
* Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code> * Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code>
* using the specified character encoding. * using the specified character encoding.
@ -1131,8 +1136,7 @@ public class IO
* This method uses {@link String#String(byte[], String)}. * This method uses {@link String#String(byte[], String)}.
* *
* @param data * @param data
* the byte array to write, do not modify during output, null * the byte array to write, do not modify during output, null ignored
* ignored
* @param output * @param output
* the <code>Writer</code> to write to * the <code>Writer</code> to write to
* @param encoding * @param encoding
@ -1150,22 +1154,22 @@ public class IO
if(encoding == null) if(encoding == null)
{ {
write(data, output); write(data, output);
} else }
else
{ {
output.write(new String(data, encoding)); output.write(new String(data, encoding));
} }
} }
} }
// write char[] // write char[]
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
* Writes chars from a <code>char[]</code> to a <code>Writer</code> using * Writes chars from a <code>char[]</code> to a <code>Writer</code> using the
* the default character encoding of the platform. * default character encoding of the platform.
* *
* @param data * @param data
* the char array to write, do not modify during output, null * the char array to write, do not modify during output, null ignored
* ignored
* @param output * @param output
* the <code>Writer</code> to write to * the <code>Writer</code> to write to
* @throws NullPointerException * @throws NullPointerException
@ -1181,17 +1185,15 @@ public class IO
output.write(data); output.write(data);
} }
} }
/** /**
* Writes chars from a <code>char[]</code> to bytes on an * Writes chars from a <code>char[]</code> to bytes on an
* <code>OutputStream</code>. * <code>OutputStream</code>.
* <p> * <p>
* This method uses {@link String#String(char[])} and * This method uses {@link String#String(char[])} and {@link String#getBytes()}.
* {@link String#getBytes()}.
* *
* @param data * @param data
* the char array to write, do not modify during output, null * the char array to write, do not modify during output, null ignored
* ignored
* @param output * @param output
* the <code>OutputStream</code> to write to * the <code>OutputStream</code> to write to
* @throws NullPointerException * @throws NullPointerException
@ -1207,7 +1209,7 @@ public class IO
output.write(new String(data).getBytes()); output.write(new String(data).getBytes());
} }
} }
/** /**
* Writes chars from a <code>char[]</code> to bytes on an * Writes chars from a <code>char[]</code> to bytes on an
* <code>OutputStream</code> using the specified character encoding. * <code>OutputStream</code> using the specified character encoding.
@ -1219,8 +1221,7 @@ public class IO
* {@link String#getBytes(String)}. * {@link String#getBytes(String)}.
* *
* @param data * @param data
* the char array to write, do not modify during output, null * the char array to write, do not modify during output, null ignored
* ignored
* @param output * @param output
* the <code>OutputStream</code> to write to * the <code>OutputStream</code> to write to
* @param encoding * @param encoding
@ -1238,13 +1239,14 @@ public class IO
if(encoding == null) if(encoding == null)
{ {
write(data, output); write(data, output);
} else }
else
{ {
output.write(new String(data).getBytes(encoding)); output.write(new String(data).getBytes(encoding));
} }
} }
} }
// write String // write String
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
@ -1267,7 +1269,7 @@ public class IO
output.write(data); output.write(data);
} }
} }
/** /**
* Writes chars from a <code>String</code> to bytes on an * Writes chars from a <code>String</code> to bytes on an
* <code>OutputStream</code> using the default character encoding of the * <code>OutputStream</code> using the default character encoding of the
@ -1292,7 +1294,7 @@ public class IO
output.write(data.getBytes()); output.write(data.getBytes());
} }
} }
/** /**
* Writes chars from a <code>String</code> to bytes on an * Writes chars from a <code>String</code> to bytes on an
* <code>OutputStream</code> using the specified character encoding. * <code>OutputStream</code> using the specified character encoding.
@ -1321,13 +1323,14 @@ public class IO
if(encoding == null) if(encoding == null)
{ {
write(data, output); write(data, output);
} else }
else
{ {
output.write(data.getBytes(encoding)); output.write(data.getBytes(encoding));
} }
} }
} }
// write StringBuffer // write StringBuffer
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
@ -1350,7 +1353,7 @@ public class IO
output.write(data.toString()); output.write(data.toString());
} }
} }
/** /**
* Writes chars from a <code>StringBuffer</code> to bytes on an * Writes chars from a <code>StringBuffer</code> to bytes on an
* <code>OutputStream</code> using the default character encoding of the * <code>OutputStream</code> using the default character encoding of the
@ -1375,7 +1378,7 @@ public class IO
output.write(data.toString().getBytes()); output.write(data.toString().getBytes());
} }
} }
/** /**
* Writes chars from a <code>StringBuffer</code> to bytes on an * Writes chars from a <code>StringBuffer</code> to bytes on an
* <code>OutputStream</code> using the specified character encoding. * <code>OutputStream</code> using the specified character encoding.
@ -1404,27 +1407,27 @@ public class IO
if(encoding == null) if(encoding == null)
{ {
write(data, output); write(data, output);
} else }
else
{ {
output.write(data.toString().getBytes(encoding)); output.write(data.toString().getBytes(encoding));
} }
} }
} }
// writeLines // writeLines
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
* Writes the <code>toString()</code> value of each item in a collection to * Writes the <code>toString()</code> value of each item in a collection to an
* an <code>OutputStream</code> line by line, using the default character * <code>OutputStream</code> line by line, using the default character encoding
* encoding of the platform and the specified line ending. * of the platform and the specified line ending.
* *
* @param lines * @param lines
* the lines to write, null entries produce blank lines * the lines to write, null entries produce blank lines
* @param lineEnding * @param lineEnding
* the line separator to use, null is system default * the line separator to use, null is system default
* @param output * @param output
* the <code>OutputStream</code> to write to, not null, not * the <code>OutputStream</code> to write to, not null, not closed
* closed
* @throws NullPointerException * @throws NullPointerException
* if the output is null * if the output is null
* @throws IOException * @throws IOException
@ -1451,10 +1454,10 @@ public class IO
output.write(lineEnding.getBytes()); output.write(lineEnding.getBytes());
} }
} }
/** /**
* Writes the <code>toString()</code> value of each item in a collection to * Writes the <code>toString()</code> value of each item in a collection to an
* an <code>OutputStream</code> line by line, using the specified character * <code>OutputStream</code> line by line, using the specified character
* encoding and the specified line ending. * encoding and the specified line ending.
* <p> * <p>
* Character encoding names can be found at * Character encoding names can be found at
@ -1465,8 +1468,7 @@ public class IO
* @param lineEnding * @param lineEnding
* the line separator to use, null is system default * the line separator to use, null is system default
* @param output * @param output
* the <code>OutputStream</code> to write to, not null, not * the <code>OutputStream</code> to write to, not null, not closed
* closed
* @param encoding * @param encoding
* the encoding to use, null means platform default * the encoding to use, null means platform default
* @throws NullPointerException * @throws NullPointerException
@ -1480,7 +1482,8 @@ public class IO
if(encoding == null) if(encoding == null)
{ {
writeLines(lines, lineEnding, output); writeLines(lines, lineEnding, output);
} else }
else
{ {
if(lines == null) if(lines == null)
{ {
@ -1501,10 +1504,10 @@ public class IO
} }
} }
} }
/** /**
* Writes the <code>toString()</code> value of each item in a collection to * Writes the <code>toString()</code> value of each item in a collection to a
* a <code>Writer</code> line by line, using the specified line ending. * <code>Writer</code> line by line, using the specified line ending.
* *
* @param lines * @param lines
* the lines to write, null entries produce blank lines * the lines to write, null entries produce blank lines
@ -1538,19 +1541,18 @@ public class IO
writer.write(lineEnding); writer.write(lineEnding);
} }
} }
// copy from InputStream // copy from InputStream
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
* Copy bytes from an <code>InputStream</code> to an * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
* <code>OutputStream</code>.
* <p> * <p>
* This method buffers the input internally, so there is no need to use a * This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>. * <code>BufferedInputStream</code>.
* <p> * <p>
* Large streams (over 2GB) will return a bytes copied value of * Large streams (over 2GB) will return a bytes copied value of <code>-1</code>
* <code>-1</code> after the copy has completed since the correct number of * after the copy has completed since the correct number of bytes cannot be
* bytes cannot be returned as an int. For large streams use the * returned as an int. For large streams use the
* <code>copyLarge(InputStream, OutputStream)</code> method. * <code>copyLarge(InputStream, OutputStream)</code> method.
* *
* @param input * @param input
@ -1575,7 +1577,7 @@ public class IO
} }
return (int) count; return (int) count;
} }
/** /**
* Copy bytes from a large (over 2GB) <code>InputStream</code> to an * Copy bytes from a large (over 2GB) <code>InputStream</code> to an
* <code>OutputStream</code>. * <code>OutputStream</code>.
@ -1606,10 +1608,10 @@ public class IO
} }
return count; return count;
} }
/** /**
* Copy bytes from an <code>InputStream</code> to chars on a * Copy bytes from an <code>InputStream</code> to chars on a <code>Writer</code>
* <code>Writer</code> using the default character encoding of the platform. * using the default character encoding of the platform.
* <p> * <p>
* This method buffers the input internally, so there is no need to use a * This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>. * <code>BufferedInputStream</code>.
@ -1631,10 +1633,10 @@ public class IO
InputStreamReader in = new InputStreamReader(input); InputStreamReader in = new InputStreamReader(input);
copy(in, output); copy(in, output);
} }
/** /**
* Copy bytes from an <code>InputStream</code> to chars on a * Copy bytes from an <code>InputStream</code> to chars on a <code>Writer</code>
* <code>Writer</code> using the specified character encoding. * using the specified character encoding.
* <p> * <p>
* This method buffers the input internally, so there is no need to use a * This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>. * <code>BufferedInputStream</code>.
@ -1661,13 +1663,14 @@ public class IO
if(encoding == null) if(encoding == null)
{ {
copy(input, output); copy(input, output);
} else }
else
{ {
InputStreamReader in = new InputStreamReader(input, encoding); InputStreamReader in = new InputStreamReader(input, encoding);
copy(in, output); copy(in, output);
} }
} }
// copy from Reader // copy from Reader
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
@ -1676,9 +1679,9 @@ public class IO
* This method buffers the input internally, so there is no need to use a * This method buffers the input internally, so there is no need to use a
* <code>BufferedReader</code>. * <code>BufferedReader</code>.
* <p> * <p>
* Large streams (over 2GB) will return a chars copied value of * Large streams (over 2GB) will return a chars copied value of <code>-1</code>
* <code>-1</code> after the copy has completed since the correct number of * after the copy has completed since the correct number of chars cannot be
* chars cannot be returned as an int. For large streams use the * returned as an int. For large streams use the
* <code>copyLarge(Reader, Writer)</code> method. * <code>copyLarge(Reader, Writer)</code> method.
* *
* @param input * @param input
@ -1703,7 +1706,7 @@ public class IO
} }
return (int) count; return (int) count;
} }
/** /**
* Copy chars from a large (over 2GB) <code>Reader</code> to a * Copy chars from a large (over 2GB) <code>Reader</code> to a
* <code>Writer</code>. * <code>Writer</code>.
@ -1734,7 +1737,7 @@ public class IO
} }
return count; return count;
} }
/** /**
* Copy chars from a <code>Reader</code> to bytes on an * Copy chars from a <code>Reader</code> to bytes on an
* <code>OutputStream</code> using the default character encoding of the * <code>OutputStream</code> using the default character encoding of the
@ -1765,11 +1768,11 @@ public class IO
// have to flush here. // have to flush here.
out.flush(); out.flush();
} }
/** /**
* Copy chars from a <code>Reader</code> to bytes on an * Copy chars from a <code>Reader</code> to bytes on an
* <code>OutputStream</code> using the specified character encoding, and * <code>OutputStream</code> using the specified character encoding, and calling
* calling flush. * flush.
* <p> * <p>
* This method buffers the input internally, so there is no need to use a * This method buffers the input internally, so there is no need to use a
* <code>BufferedReader</code>. * <code>BufferedReader</code>.
@ -1799,7 +1802,8 @@ public class IO
if(encoding == null) if(encoding == null)
{ {
copy(input, output); copy(input, output);
} else }
else
{ {
OutputStreamWriter out = new OutputStreamWriter(output, encoding); OutputStreamWriter out = new OutputStreamWriter(output, encoding);
copy(input, out); copy(input, out);
@ -1807,12 +1811,11 @@ public class IO
out.flush(); out.flush();
} }
} }
// content equals // content equals
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
/** /**
* Compare the contents of two Streams to determine if they are equal or * Compare the contents of two Streams to determine if they are equal or not.
* not.
* <p> * <p>
* This method buffers the input internally using * This method buffers the input internally using
* <code>BufferedInputStream</code> if they are not already buffered. * <code>BufferedInputStream</code> if they are not already buffered.
@ -1838,7 +1841,7 @@ public class IO
{ {
input2 = new BufferedInputStream(input2); input2 = new BufferedInputStream(input2);
} }
int ch = input1.read(); int ch = input1.read();
while(-1 != ch) while(-1 != ch)
{ {
@ -1849,17 +1852,16 @@ public class IO
} }
ch = input1.read(); ch = input1.read();
} }
int ch2 = input2.read(); int ch2 = input2.read();
return (ch2 == -1); return (ch2 == -1);
} }
/** /**
* Compare the contents of two Readers to determine if they are equal or * Compare the contents of two Readers to determine if they are equal or not.
* not.
* <p> * <p>
* This method buffers the input internally using * This method buffers the input internally using <code>BufferedReader</code> if
* <code>BufferedReader</code> if they are not already buffered. * they are not already buffered.
* *
* @param input1 * @param input1
* the first reader * the first reader
@ -1883,7 +1885,7 @@ public class IO
{ {
input2 = new BufferedReader(input2); input2 = new BufferedReader(input2);
} }
int ch = input1.read(); int ch = input1.read();
while(-1 != ch) while(-1 != ch)
{ {
@ -1894,11 +1896,11 @@ public class IO
} }
ch = input1.read(); ch = input1.read();
} }
int ch2 = input2.read(); int ch2 = input2.read();
return (ch2 == -1); return (ch2 == -1);
} }
static static
{ {
// avoid security issues // avoid security issues

View File

@ -149,6 +149,33 @@ public class ObjectResourceLoader extends ResourceLoader<IrisObject>
} }
} }
public File findFile(String name)
{
lock.lock();
for(File i : getFolders(name))
{
for(File j : i.listFiles())
{
if(j.isFile() && j.getName().endsWith(".iob") && j.getName().split("\\Q.\\E")[0].equals(name))
{
return j;
}
}
File file = new File(i, name + ".iob");
if(file.exists())
{
return file;
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
lock.unlock();
return null;
}
public IrisObject load(String name) public IrisObject load(String name)
{ {
String key = name + "-" + objectClass.getCanonicalName(); String key = name + "-" + objectClass.getCanonicalName();