Merged with released L2J-Unity files.
This commit is contained in:
@ -26,7 +26,7 @@ import com.mchange.v2.c3p0.ComboPooledDataSource;
|
||||
|
||||
/**
|
||||
* Database Factory implementation.
|
||||
* @author Zoey76
|
||||
* @author Zoey76, Mobius
|
||||
*/
|
||||
public class DatabaseFactory
|
||||
{
|
||||
|
@ -1,162 +1,189 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.geodriver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel.MapMode;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
import com.l2jmobius.commons.geodriver.regions.NullRegion;
|
||||
import com.l2jmobius.commons.geodriver.regions.Region;
|
||||
|
||||
/**
|
||||
* @author HorridoJoho
|
||||
*/
|
||||
public final class GeoDriver
|
||||
{
|
||||
// world dimensions: 1048576 * 1048576 = 1099511627776
|
||||
private static final int WORLD_MIN_X = -655360;
|
||||
private static final int WORLD_MAX_X = 393215;
|
||||
private static final int WORLD_MIN_Y = -589824;
|
||||
private static final int WORLD_MAX_Y = 458751;
|
||||
|
||||
/** Regions in the world on the x axis */
|
||||
public static final int GEO_REGIONS_X = 32;
|
||||
/** Regions in the world on the y axis */
|
||||
public static final int GEO_REGIONS_Y = 32;
|
||||
/** Region in the world */
|
||||
public static final int GEO_REGIONS = GEO_REGIONS_X * GEO_REGIONS_Y;
|
||||
|
||||
/** Blocks in the world on the x axis */
|
||||
public static final int GEO_BLOCKS_X = GEO_REGIONS_X * IRegion.REGION_BLOCKS_X;
|
||||
/** Blocks in the world on the y axis */
|
||||
public static final int GEO_BLOCKS_Y = GEO_REGIONS_Y * IRegion.REGION_BLOCKS_Y;
|
||||
/** Blocks in the world */
|
||||
public static final int GEO_BLOCKS = GEO_REGIONS * IRegion.REGION_BLOCKS;
|
||||
|
||||
/** Cells in the world on the x axis */
|
||||
public static final int GEO_CELLS_X = GEO_BLOCKS_X * IBlock.BLOCK_CELLS_X;
|
||||
/** Cells in the world in the y axis */
|
||||
public static final int GEO_CELLS_Y = GEO_BLOCKS_Y * IBlock.BLOCK_CELLS_Y;
|
||||
|
||||
/** The regions array */
|
||||
private final AtomicReferenceArray<IRegion> _regions = new AtomicReferenceArray<>(GEO_REGIONS);
|
||||
|
||||
public GeoDriver()
|
||||
{
|
||||
for (int i = 0; i < _regions.length(); i++)
|
||||
{
|
||||
_regions.set(i, NullRegion.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkGeoX(int geoX)
|
||||
{
|
||||
if ((geoX < 0) || (geoX >= GEO_CELLS_X))
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkGeoY(int geoY)
|
||||
{
|
||||
if ((geoY < 0) || (geoY >= GEO_CELLS_Y))
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private IRegion getRegion(int geoX, int geoY)
|
||||
{
|
||||
checkGeoX(geoX);
|
||||
checkGeoY(geoY);
|
||||
return _regions.get(((geoX / IRegion.REGION_CELLS_X) * GEO_REGIONS_Y) + (geoY / IRegion.REGION_CELLS_Y));
|
||||
}
|
||||
|
||||
public void loadRegion(Path filePath, int regionX, int regionY) throws IOException
|
||||
{
|
||||
final int regionOffset = (regionX * GEO_REGIONS_Y) + regionY;
|
||||
|
||||
try (RandomAccessFile raf = new RandomAccessFile(filePath.toFile(), "r"))
|
||||
{
|
||||
_regions.set(regionOffset, new Region(raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length()).order(ByteOrder.LITTLE_ENDIAN)));
|
||||
}
|
||||
}
|
||||
|
||||
public void unloadRegion(int regionX, int regionY)
|
||||
{
|
||||
_regions.set((regionX * GEO_REGIONS_Y) + regionY, NullRegion.INSTANCE);
|
||||
}
|
||||
|
||||
public boolean hasGeoPos(int geoX, int geoY)
|
||||
{
|
||||
return getRegion(geoX, geoY).hasGeo();
|
||||
}
|
||||
|
||||
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
|
||||
{
|
||||
return getRegion(geoX, geoY).checkNearestNswe(geoX, geoY, worldZ, nswe);
|
||||
}
|
||||
|
||||
public int getNearestZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return getRegion(geoX, geoY).getNearestZ(geoX, geoY, worldZ);
|
||||
}
|
||||
|
||||
public int getNextLowerZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return getRegion(geoX, geoY).getNextLowerZ(geoX, geoY, worldZ);
|
||||
}
|
||||
|
||||
public int getNextHigherZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return getRegion(geoX, geoY).getNextHigherZ(geoX, geoY, worldZ);
|
||||
}
|
||||
|
||||
public int getGeoX(int worldX)
|
||||
{
|
||||
if ((worldX < WORLD_MIN_X) || (worldX > WORLD_MAX_X))
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return (worldX - WORLD_MIN_X) / 16;
|
||||
}
|
||||
|
||||
public int getGeoY(int worldY)
|
||||
{
|
||||
if ((worldY < WORLD_MIN_Y) || (worldY > WORLD_MAX_Y))
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return (worldY - WORLD_MIN_Y) / 16;
|
||||
}
|
||||
|
||||
public int getWorldX(int geoX)
|
||||
{
|
||||
checkGeoX(geoX);
|
||||
return (geoX * 16) + WORLD_MIN_X + 8;
|
||||
}
|
||||
|
||||
public int getWorldY(int geoY)
|
||||
{
|
||||
checkGeoY(geoY);
|
||||
return (geoY * 16) + WORLD_MIN_Y + 8;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.geodriver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel.MapMode;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
import com.l2jmobius.commons.geodriver.regions.NullRegion;
|
||||
import com.l2jmobius.commons.geodriver.regions.Region;
|
||||
|
||||
/**
|
||||
* @author HorridoJoho
|
||||
*/
|
||||
public final class GeoDriver
|
||||
{
|
||||
// world dimensions: 1048576 * 1048576 = 1099511627776
|
||||
private static final int WORLD_MIN_X = -655360;
|
||||
private static final int WORLD_MAX_X = 393215;
|
||||
private static final int WORLD_MIN_Y = -589824;
|
||||
private static final int WORLD_MAX_Y = 458751;
|
||||
private static final int WORLD_MIN_Z = -16384;
|
||||
private static final int WORLD_MAX_Z = 16384;
|
||||
|
||||
/** Regions in the world on the x axis */
|
||||
public static final int GEO_REGIONS_X = 32;
|
||||
/** Regions in the world on the y axis */
|
||||
public static final int GEO_REGIONS_Y = 32;
|
||||
/** Region in the world */
|
||||
public static final int GEO_REGIONS = GEO_REGIONS_X * GEO_REGIONS_Y;
|
||||
|
||||
/** Blocks in the world on the x axis */
|
||||
public static final int GEO_BLOCKS_X = GEO_REGIONS_X * IRegion.REGION_BLOCKS_X;
|
||||
/** Blocks in the world on the y axis */
|
||||
public static final int GEO_BLOCKS_Y = GEO_REGIONS_Y * IRegion.REGION_BLOCKS_Y;
|
||||
/** Blocks in the world */
|
||||
public static final int GEO_BLOCKS = GEO_REGIONS * IRegion.REGION_BLOCKS;
|
||||
|
||||
/** Cells in the world on the x axis */
|
||||
public static final int GEO_CELLS_X = GEO_BLOCKS_X * IBlock.BLOCK_CELLS_X;
|
||||
/** Cells in the world in the y axis */
|
||||
public static final int GEO_CELLS_Y = GEO_BLOCKS_Y * IBlock.BLOCK_CELLS_Y;
|
||||
/** Cells in the world in the z axis */
|
||||
public static final int GEO_CELLS_Z = (Math.abs(WORLD_MIN_Z) + Math.abs(WORLD_MAX_Z)) / 16;
|
||||
|
||||
/** The regions array */
|
||||
private final AtomicReferenceArray<IRegion> _regions = new AtomicReferenceArray<>(GEO_REGIONS);
|
||||
|
||||
public GeoDriver()
|
||||
{
|
||||
for (int i = 0; i < _regions.length(); i++)
|
||||
{
|
||||
_regions.set(i, NullRegion.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkGeoX(int geoX)
|
||||
{
|
||||
if ((geoX < 0) || (geoX >= GEO_CELLS_X))
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkGeoY(int geoY)
|
||||
{
|
||||
if ((geoY < 0) || (geoY >= GEO_CELLS_Y))
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkGeoZ(int geoZ)
|
||||
{
|
||||
if ((geoZ < 0) || (geoZ >= GEO_CELLS_Z))
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private IRegion getRegion(int geoX, int geoY)
|
||||
{
|
||||
checkGeoX(geoX);
|
||||
checkGeoY(geoY);
|
||||
return _regions.get(((geoX / IRegion.REGION_CELLS_X) * GEO_REGIONS_Y) + (geoY / IRegion.REGION_CELLS_Y));
|
||||
}
|
||||
|
||||
public void loadRegion(Path filePath, int regionX, int regionY) throws IOException
|
||||
{
|
||||
final int regionOffset = (regionX * GEO_REGIONS_Y) + regionY;
|
||||
|
||||
try (RandomAccessFile raf = new RandomAccessFile(filePath.toFile(), "r"))
|
||||
{
|
||||
_regions.set(regionOffset, new Region(raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length()).load().order(ByteOrder.LITTLE_ENDIAN)));
|
||||
}
|
||||
}
|
||||
|
||||
public void unloadRegion(int regionX, int regionY)
|
||||
{
|
||||
_regions.set((regionX * GEO_REGIONS_Y) + regionY, NullRegion.INSTANCE);
|
||||
}
|
||||
|
||||
public boolean hasGeoPos(int geoX, int geoY)
|
||||
{
|
||||
return getRegion(geoX, geoY).hasGeo();
|
||||
}
|
||||
|
||||
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
|
||||
{
|
||||
return getRegion(geoX, geoY).checkNearestNswe(geoX, geoY, worldZ, nswe);
|
||||
}
|
||||
|
||||
public int getNearestZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return getRegion(geoX, geoY).getNearestZ(geoX, geoY, worldZ);
|
||||
}
|
||||
|
||||
public int getNextLowerZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return getRegion(geoX, geoY).getNextLowerZ(geoX, geoY, worldZ);
|
||||
}
|
||||
|
||||
public int getNextHigherZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return getRegion(geoX, geoY).getNextHigherZ(geoX, geoY, worldZ);
|
||||
}
|
||||
|
||||
public int getGeoX(int worldX)
|
||||
{
|
||||
if ((worldX < WORLD_MIN_X) || (worldX > WORLD_MAX_X))
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return (worldX - WORLD_MIN_X) / 16;
|
||||
}
|
||||
|
||||
public int getGeoY(int worldY)
|
||||
{
|
||||
if ((worldY < WORLD_MIN_Y) || (worldY > WORLD_MAX_Y))
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return (worldY - WORLD_MIN_Y) / 16;
|
||||
}
|
||||
|
||||
public int getGeoZ(int worldZ)
|
||||
{
|
||||
if ((worldZ < WORLD_MIN_Z) || (worldZ > WORLD_MAX_Z))
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return (worldZ - WORLD_MIN_Z) / 16;
|
||||
}
|
||||
|
||||
public int getWorldX(int geoX)
|
||||
{
|
||||
checkGeoX(geoX);
|
||||
return (geoX * 16) + WORLD_MIN_X + 8;
|
||||
}
|
||||
|
||||
public int getWorldY(int geoY)
|
||||
{
|
||||
checkGeoY(geoY);
|
||||
return (geoY * 16) + WORLD_MIN_Y + 8;
|
||||
}
|
||||
|
||||
public int getWorldZ(int geoZ)
|
||||
{
|
||||
checkGeoZ(geoZ);
|
||||
return (geoZ * 16) + WORLD_MIN_Z + 8;
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* 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 Sun Microsystems nor the names of
|
||||
* is contributors may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.l2jmobius.commons.javaengine;
|
||||
|
||||
public class CompilationException extends Exception
|
||||
{
|
||||
public CompilationException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* 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 Sun Microsystems nor the names of
|
||||
* is contributors may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.l2jmobius.commons.javaengine;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.DiagnosticCollector;
|
||||
import javax.tools.JavaCompiler.CompilationTask;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler;
|
||||
|
||||
/**
|
||||
* Simple interface to Java compiler using JSR 199 Compiler API.
|
||||
* @author A. Sundararajan
|
||||
*/
|
||||
public class JavaCompiler
|
||||
{
|
||||
private final javax.tools.JavaCompiler tool;
|
||||
|
||||
public JavaCompiler()
|
||||
{
|
||||
tool = new EclipseCompiler();
|
||||
}
|
||||
|
||||
public Map<String, byte[]> compile(String source, String fileName)
|
||||
{
|
||||
return compile(source, fileName, new PrintWriter(System.err), null, null);
|
||||
}
|
||||
|
||||
public Map<String, byte[]> compile(String fileName, String source, Writer err)
|
||||
{
|
||||
return compile(fileName, source, err, null, null);
|
||||
}
|
||||
|
||||
public Map<String, byte[]> compile(String fileName, String source, Writer err, String sourcePath)
|
||||
{
|
||||
return compile(fileName, source, err, sourcePath, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* compile given String source and return bytecodes as a Map.
|
||||
* @param fileName source fileName to be used for error messages etc.
|
||||
* @param source Java source as String
|
||||
* @param err error writer where diagnostic messages are written
|
||||
* @param sourcePath location of additional .java source files
|
||||
* @param classPath location of additional .class files
|
||||
* @return
|
||||
*/
|
||||
public Map<String, byte[]> compile(String fileName, String source, Writer err, String sourcePath, String classPath)
|
||||
{
|
||||
// to collect errors, warnings etc.
|
||||
final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
|
||||
|
||||
// create a new memory JavaFileManager
|
||||
final MemoryJavaFileManager manager = new MemoryJavaFileManager();
|
||||
|
||||
// prepare the compilation unit
|
||||
final List<JavaFileObject> compUnits = new ArrayList<>(1);
|
||||
compUnits.add(MemoryJavaFileManager.makeStringSource(fileName, source));
|
||||
|
||||
// javac options
|
||||
final List<String> options = new ArrayList<>();
|
||||
options.add("-warn:-enumSwitch");
|
||||
options.add("-g");
|
||||
options.add("-deprecation");
|
||||
options.add("-1.8");
|
||||
if (sourcePath != null)
|
||||
{
|
||||
options.add("-sourcepath");
|
||||
options.add(sourcePath);
|
||||
}
|
||||
if (classPath != null)
|
||||
{
|
||||
options.add("-classpath");
|
||||
options.add(classPath);
|
||||
}
|
||||
|
||||
// create a compilation task
|
||||
final CompilationTask task = tool.getTask(err, manager, diagnostics, options, null, compUnits);
|
||||
|
||||
if (!task.call())
|
||||
{
|
||||
final PrintWriter perr = new PrintWriter(err);
|
||||
for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics())
|
||||
{
|
||||
perr.println(diagnostic.getMessage(Locale.getDefault()));
|
||||
}
|
||||
perr.flush();
|
||||
return null;
|
||||
}
|
||||
|
||||
final Map<String, byte[]> classBytes = manager.getClassBytes();
|
||||
manager.close();
|
||||
return classBytes;
|
||||
}
|
||||
}
|
@ -1,447 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* 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 Sun Microsystems nor the names of
|
||||
* is contributors may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.l2jmobius.commons.javaengine;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Serializable;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.script.AbstractScriptEngine;
|
||||
import javax.script.Bindings;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
|
||||
/**
|
||||
* This is script engine for Java programming language.
|
||||
* @author A. Sundararajan
|
||||
*/
|
||||
public class JavaScriptEngine extends AbstractScriptEngine implements Compilable
|
||||
{
|
||||
// Java compiler
|
||||
private final JavaCompiler compiler;
|
||||
|
||||
public JavaScriptEngine()
|
||||
{
|
||||
compiler = new JavaCompiler();
|
||||
}
|
||||
|
||||
// my factory, may be null
|
||||
private ScriptEngineFactory factory;
|
||||
|
||||
// my implementation for CompiledScript
|
||||
private static class JavaCompiledScript extends CompiledScript implements Serializable
|
||||
{
|
||||
private final transient JavaScriptEngine _engine;
|
||||
private transient Class<?> _class;
|
||||
private final Map<String, byte[]> _classBytes;
|
||||
private final String _classPath;
|
||||
|
||||
JavaCompiledScript(JavaScriptEngine engine, Map<String, byte[]> classBytes, String classPath)
|
||||
{
|
||||
_engine = engine;
|
||||
_classBytes = classBytes;
|
||||
_classPath = classPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngine getEngine()
|
||||
{
|
||||
return _engine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(ScriptContext ctx) throws ScriptException
|
||||
{
|
||||
if (_class == null)
|
||||
{
|
||||
final Map<String, byte[]> classBytesCopy = new HashMap<>();
|
||||
classBytesCopy.putAll(_classBytes);
|
||||
_class = JavaScriptEngine.parseMain(new MemoryClassLoader(classBytesCopy, _classPath, JavaScriptEngine.getParentLoader(ctx)), ctx);
|
||||
}
|
||||
return JavaScriptEngine.evalClass(_class, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompiledScript compile(String script) throws ScriptException
|
||||
{
|
||||
return compile(script, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompiledScript compile(Reader reader) throws ScriptException
|
||||
{
|
||||
return compile(readFully(reader));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(String str, ScriptContext ctx) throws ScriptException
|
||||
{
|
||||
return evalClass(parse(str, ctx), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(Reader reader, ScriptContext ctx) throws ScriptException
|
||||
{
|
||||
return eval(readFully(reader), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngineFactory getFactory()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (factory == null)
|
||||
{
|
||||
factory = new JavaScriptEngineFactory();
|
||||
}
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bindings createBindings()
|
||||
{
|
||||
return new SimpleBindings();
|
||||
}
|
||||
|
||||
void setFactory(ScriptEngineFactory factory)
|
||||
{
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
// Internals only below this point
|
||||
|
||||
private Class<?> parse(String str, ScriptContext ctx) throws ScriptException
|
||||
{
|
||||
final String fileName = getFileName(ctx);
|
||||
final String sourcePath = getSourcePath(ctx);
|
||||
final String classPath = getClassPath(ctx);
|
||||
|
||||
final Writer err = ctx.getErrorWriter() == null ? new StringWriter() : ctx.getErrorWriter();
|
||||
|
||||
final Map<String, byte[]> classBytes = compiler.compile(fileName, str, err, sourcePath, classPath);
|
||||
|
||||
if (classBytes == null)
|
||||
{
|
||||
throw err instanceof StringWriter ? new ScriptException(((StringWriter) err).toString()) : new ScriptException("compilation failed");
|
||||
}
|
||||
|
||||
// create a ClassLoader to load classes from MemoryJavaFileManager
|
||||
return parseMain(new MemoryClassLoader(classBytes, classPath, getParentLoader(ctx)), ctx);
|
||||
}
|
||||
|
||||
protected static Class<?> parseMain(MemoryClassLoader loader, ScriptContext ctx) throws ScriptException
|
||||
{
|
||||
final String mainClassName = getMainClassName(ctx);
|
||||
if (mainClassName != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
final Class<?> clazz = loader.load(mainClassName);
|
||||
final Method mainMethod = findMainMethod(clazz);
|
||||
if (mainMethod == null)
|
||||
{
|
||||
throw new ScriptException("no main method in " + mainClassName);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
catch (ClassNotFoundException cnfe)
|
||||
{
|
||||
cnfe.printStackTrace();
|
||||
throw new ScriptException(cnfe);
|
||||
}
|
||||
}
|
||||
|
||||
// no main class configured - load all compiled classes
|
||||
Iterable<Class<?>> classes;
|
||||
try
|
||||
{
|
||||
classes = loader.loadAll();
|
||||
}
|
||||
catch (ClassNotFoundException exp)
|
||||
{
|
||||
throw new ScriptException(exp);
|
||||
}
|
||||
|
||||
// search for class with main method
|
||||
final Class<?> c = findMainClass(classes);
|
||||
if (c != null)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
// if class with "main" method, then
|
||||
// return first class
|
||||
final Iterator<Class<?>> itr = classes.iterator();
|
||||
return itr.hasNext() ? itr.next() : null;
|
||||
}
|
||||
|
||||
private JavaCompiledScript compile(String str, ScriptContext ctx) throws ScriptException
|
||||
{
|
||||
final String fileName = getFileName(ctx);
|
||||
final String sourcePath = getSourcePath(ctx);
|
||||
final String classPath = getClassPath(ctx);
|
||||
|
||||
final Writer err = ctx.getErrorWriter() == null ? new StringWriter() : ctx.getErrorWriter();
|
||||
final Map<String, byte[]> classBytes = compiler.compile(fileName, str, err, sourcePath, classPath);
|
||||
if (classBytes == null)
|
||||
{
|
||||
throw err instanceof StringWriter ? new ScriptException(((StringWriter) err).toString()) : new ScriptException("compilation failed");
|
||||
}
|
||||
|
||||
return new JavaCompiledScript(this, classBytes, classPath);
|
||||
}
|
||||
|
||||
private static Class<?> findMainClass(Iterable<Class<?>> classes)
|
||||
{
|
||||
// find a public class with public static main method
|
||||
for (Class<?> clazz : classes)
|
||||
{
|
||||
if (Modifier.isPublic(clazz.getModifiers()) && (findMainMethod(clazz) != null))
|
||||
{
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
|
||||
// okay, try to find package private class that
|
||||
// has public static main method
|
||||
for (Class<?> clazz : classes)
|
||||
{
|
||||
if (findMainMethod(clazz) != null)
|
||||
{
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
|
||||
// no main class found!
|
||||
return null;
|
||||
}
|
||||
|
||||
// find public static void main(String[]) method, if any
|
||||
private static Method findMainMethod(Class<?> clazz)
|
||||
{
|
||||
try
|
||||
{
|
||||
final Method mainMethod = clazz.getMethod("main", new Class[]
|
||||
{
|
||||
String[].class
|
||||
});
|
||||
final int modifiers = mainMethod.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers))
|
||||
{
|
||||
return mainMethod;
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException nsme)
|
||||
{
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// find public static void setScriptContext(ScriptContext) method, if any
|
||||
private static Method findSetScriptContextMethod(Class<?> clazz)
|
||||
{
|
||||
try
|
||||
{
|
||||
final Method setCtxMethod = clazz.getMethod("setScriptContext", new Class[]
|
||||
{
|
||||
ScriptContext.class
|
||||
});
|
||||
final int modifiers = setCtxMethod.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers))
|
||||
{
|
||||
return setCtxMethod;
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException nsme)
|
||||
{
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getFileName(ScriptContext ctx)
|
||||
{
|
||||
final int scope = ctx.getAttributesScope("javax.script.filename");
|
||||
return scope != -1 ? ctx.getAttribute("javax.script.filename", scope).toString() : "$unnamed.java";
|
||||
}
|
||||
|
||||
// for certain variables, we look for System properties. This is
|
||||
// the prefix used for such System properties
|
||||
private static final String SYSPROP_PREFIX = "com.sun.script.java.";
|
||||
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
private static final String ARGUMENTS = "arguments";
|
||||
|
||||
private static String[] getArguments(ScriptContext ctx)
|
||||
{
|
||||
final int scope = ctx.getAttributesScope(ARGUMENTS);
|
||||
if (scope != -1)
|
||||
{
|
||||
final Object obj = ctx.getAttribute(ARGUMENTS, scope);
|
||||
if (obj instanceof String[])
|
||||
{
|
||||
return (String[]) obj;
|
||||
}
|
||||
}
|
||||
// return zero length array
|
||||
return EMPTY_STRING_ARRAY;
|
||||
}
|
||||
|
||||
private static final String SOURCEPATH = "sourcepath";
|
||||
|
||||
private static String getSourcePath(ScriptContext ctx)
|
||||
{
|
||||
return ctx.getAttributesScope(SOURCEPATH) != -1 ? ctx.getAttribute(SOURCEPATH).toString() : System.getProperty(SYSPROP_PREFIX + SOURCEPATH);
|
||||
}
|
||||
|
||||
private static final String CLASSPATH = "classpath";
|
||||
|
||||
private static String getClassPath(ScriptContext ctx)
|
||||
{
|
||||
final int scope = ctx.getAttributesScope(CLASSPATH);
|
||||
if (scope != -1)
|
||||
{
|
||||
return ctx.getAttribute(CLASSPATH).toString();
|
||||
}
|
||||
|
||||
// look for "com.sun.script.java.classpath"
|
||||
String res = System.getProperty(SYSPROP_PREFIX + CLASSPATH);
|
||||
if (res == null)
|
||||
{
|
||||
res = System.getProperty("java.class.path");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static final String MAINCLASS = "mainClass";
|
||||
|
||||
private static String getMainClassName(ScriptContext ctx)
|
||||
{
|
||||
return ctx.getAttributesScope(MAINCLASS) != -1 ? ctx.getAttribute(MAINCLASS).toString() : System.getProperty("com.sun.script.java.mainClass");
|
||||
}
|
||||
|
||||
private static final String PARENTLOADER = "parentLoader";
|
||||
|
||||
protected static ClassLoader getParentLoader(ScriptContext ctx)
|
||||
{
|
||||
final int scope = ctx.getAttributesScope(PARENTLOADER);
|
||||
if (scope != -1)
|
||||
{
|
||||
final Object loader = ctx.getAttribute(PARENTLOADER);
|
||||
if (loader instanceof ClassLoader)
|
||||
{
|
||||
return (ClassLoader) loader;
|
||||
}
|
||||
}
|
||||
return ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
|
||||
protected static Object evalClass(Class<?> clazz, ScriptContext ctx) throws ScriptException
|
||||
{
|
||||
// JSR-223 requirement
|
||||
ctx.setAttribute("context", ctx, 100);
|
||||
if (clazz == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
final boolean isPublicClazz = Modifier.isPublic(clazz.getModifiers());
|
||||
|
||||
// find the setScriptContext method
|
||||
final Method setCtxMethod = findSetScriptContextMethod(clazz);
|
||||
// call setScriptContext and pass current ctx variable
|
||||
if (setCtxMethod != null)
|
||||
{
|
||||
if (!isPublicClazz)
|
||||
{
|
||||
// try to relax access
|
||||
setCtxMethod.setAccessible(true);
|
||||
}
|
||||
setCtxMethod.invoke(null, new Object[]
|
||||
{
|
||||
ctx
|
||||
});
|
||||
}
|
||||
|
||||
// find the main method
|
||||
final Method mainMethod = findMainMethod(clazz);
|
||||
if (mainMethod != null)
|
||||
{
|
||||
if (!isPublicClazz)
|
||||
{
|
||||
// try to relax access
|
||||
mainMethod.setAccessible(true);
|
||||
}
|
||||
|
||||
// call main method
|
||||
mainMethod.invoke(null, new Object[]
|
||||
{
|
||||
getArguments(ctx)
|
||||
});
|
||||
}
|
||||
|
||||
// return main class as eval's result
|
||||
return clazz;
|
||||
}
|
||||
catch (Exception exp)
|
||||
{
|
||||
exp.printStackTrace();
|
||||
throw new ScriptException(exp);
|
||||
}
|
||||
}
|
||||
|
||||
// read a Reader fully and return the content as string
|
||||
private String readFully(Reader reader) throws ScriptException
|
||||
{
|
||||
final char[] arr = new char[8 * 1024]; // 8K at a time
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
int numChars;
|
||||
try
|
||||
{
|
||||
while ((numChars = reader.read(arr, 0, arr.length)) > 0)
|
||||
{
|
||||
buf.append(arr, 0, numChars);
|
||||
}
|
||||
}
|
||||
catch (IOException exp)
|
||||
{
|
||||
throw new ScriptException(exp);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
@ -1,221 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* 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 Sun Microsystems nor the names of
|
||||
* is contributors may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.l2jmobius.commons.javaengine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
|
||||
/**
|
||||
* This is script engine factory for "Java" script engine.
|
||||
* @author A. Sundararajan
|
||||
*/
|
||||
public class JavaScriptEngineFactory implements ScriptEngineFactory
|
||||
{
|
||||
@Override
|
||||
public String getEngineName()
|
||||
{
|
||||
return "java";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEngineVersion()
|
||||
{
|
||||
return "1.8";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getExtensions()
|
||||
{
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLanguageName()
|
||||
{
|
||||
return "java";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLanguageVersion()
|
||||
{
|
||||
return "1.8";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodCallSyntax(String obj, String m, String... args)
|
||||
{
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
buf.append(obj);
|
||||
buf.append('.');
|
||||
buf.append(m);
|
||||
buf.append('(');
|
||||
if (args.length != 0)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < (args.length - 1); i++)
|
||||
{
|
||||
buf.append(args[i] + ", ");
|
||||
}
|
||||
buf.append(args[i]);
|
||||
}
|
||||
buf.append(')');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMimeTypes()
|
||||
{
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getNames()
|
||||
{
|
||||
return names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOutputStatement(String toDisplay)
|
||||
{
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
buf.append("System.out.print(\"");
|
||||
final int len = toDisplay.length();
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
final char ch = toDisplay.charAt(i);
|
||||
switch (ch)
|
||||
{
|
||||
case 34: // '"'
|
||||
{
|
||||
buf.append("\\\"");
|
||||
break;
|
||||
}
|
||||
case 92: // '\\'
|
||||
{
|
||||
buf.append("\\\\");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
buf.append(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.append("\");");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter(String key)
|
||||
{
|
||||
if (key.equals("javax.script.engine"))
|
||||
{
|
||||
return getEngineName();
|
||||
}
|
||||
if (key.equals("javax.script.engine_version"))
|
||||
{
|
||||
return getEngineVersion();
|
||||
}
|
||||
if (key.equals("javax.script.name"))
|
||||
{
|
||||
return getEngineName();
|
||||
}
|
||||
if (key.equals("javax.script.language"))
|
||||
{
|
||||
return getLanguageName();
|
||||
}
|
||||
if (key.equals("javax.script.language_version"))
|
||||
{
|
||||
return getLanguageVersion();
|
||||
}
|
||||
if (key.equals("THREADING"))
|
||||
{
|
||||
return "MULTITHREADED";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProgram(String... statements)
|
||||
{
|
||||
// we generate a Main class with main method
|
||||
// that contains all the given statements
|
||||
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
buf.append("class ");
|
||||
buf.append(getClassName());
|
||||
buf.append(" {\n");
|
||||
buf.append(" public static void main(String[] args) {\n");
|
||||
if (statements.length != 0)
|
||||
{
|
||||
for (String statement : statements)
|
||||
{
|
||||
buf.append(" ");
|
||||
buf.append(statement);
|
||||
buf.append(";\n");
|
||||
}
|
||||
}
|
||||
buf.append(" }\n");
|
||||
buf.append("}\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngine getScriptEngine()
|
||||
{
|
||||
final JavaScriptEngine engine = new JavaScriptEngine();
|
||||
engine.setFactory(this);
|
||||
return engine;
|
||||
}
|
||||
|
||||
// used to generate a unique class name in getProgram
|
||||
private String getClassName()
|
||||
{
|
||||
return "com_sun_script_java_Main$" + getNextClassNumber();
|
||||
}
|
||||
|
||||
private static synchronized long getNextClassNumber()
|
||||
{
|
||||
return nextClassNum++;
|
||||
}
|
||||
|
||||
private static long nextClassNum = 0L;
|
||||
private static List<String> names;
|
||||
private static List<String> extensions;
|
||||
private static List<String> mimeTypes;
|
||||
static
|
||||
{
|
||||
names = new ArrayList<>(1);
|
||||
names.add("java");
|
||||
names = Collections.unmodifiableList(names);
|
||||
extensions = names;
|
||||
mimeTypes = new ArrayList<>(0);
|
||||
mimeTypes = Collections.unmodifiableList(mimeTypes);
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* 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 Sun Microsystems nor the names of
|
||||
* is contributors may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.l2jmobius.commons.javaengine;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* ClassLoader that loads .class bytes from memory.
|
||||
* @author A. Sundararajan
|
||||
*/
|
||||
public final class MemoryClassLoader extends URLClassLoader
|
||||
{
|
||||
private final Map<String, byte[]> classBytes;
|
||||
|
||||
public MemoryClassLoader(Map<String, byte[]> classBytes, String classPath, ClassLoader parent)
|
||||
{
|
||||
super(toURLs(classPath), parent);
|
||||
this.classBytes = classBytes;
|
||||
}
|
||||
|
||||
public MemoryClassLoader(Map<String, byte[]> classBytes, String classPath)
|
||||
{
|
||||
this(classBytes, classPath, null);
|
||||
}
|
||||
|
||||
public Class<?> load(String className) throws ClassNotFoundException
|
||||
{
|
||||
return loadClass(className);
|
||||
}
|
||||
|
||||
public Iterable<Class<?>> loadAll() throws ClassNotFoundException
|
||||
{
|
||||
final List<Class<?>> classes = new ArrayList<>(classBytes.size());
|
||||
for (String name : classBytes.keySet())
|
||||
{
|
||||
classes.add(loadClass(name));
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String className) throws ClassNotFoundException
|
||||
{
|
||||
final byte buf[] = classBytes.get(className);
|
||||
if (buf != null)
|
||||
{
|
||||
// clear the bytes in map -- we don't need it anymore
|
||||
classBytes.put(className, null);
|
||||
return defineClass(className, buf, 0, buf.length);
|
||||
}
|
||||
return super.findClass(className);
|
||||
}
|
||||
|
||||
private static URL[] toURLs(String classPath)
|
||||
{
|
||||
if (classPath == null)
|
||||
{
|
||||
return new URL[0];
|
||||
}
|
||||
|
||||
final List<URL> list = new ArrayList<>();
|
||||
final StringTokenizer st = new StringTokenizer(classPath, File.pathSeparator);
|
||||
while (st.hasMoreTokens())
|
||||
{
|
||||
final String token = st.nextToken();
|
||||
final File file = new File(token);
|
||||
if (file.exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
list.add(file.toURI().toURL());
|
||||
}
|
||||
catch (MalformedURLException mue)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
list.add(new URL(token));
|
||||
}
|
||||
catch (MalformedURLException mue)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final URL res[] = new URL[list.size()];
|
||||
list.toArray(res);
|
||||
return res;
|
||||
}
|
||||
}
|
@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* 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 Sun Microsystems nor the names of
|
||||
* is contributors may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.l2jmobius.commons.javaengine;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.JavaFileObject.Kind;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.tool.EclipseFileManager;
|
||||
|
||||
/**
|
||||
* JavaFileManager that keeps compiled .class bytes in memory.
|
||||
* @author A. Sundararajan
|
||||
*/
|
||||
public final class MemoryJavaFileManager extends EclipseFileManager
|
||||
{
|
||||
private static final String EXT = ".java";
|
||||
protected Map<String, byte[]> classBytes;
|
||||
|
||||
public MemoryJavaFileManager()
|
||||
{
|
||||
super(null, null);
|
||||
classBytes = new HashMap<>();
|
||||
}
|
||||
|
||||
public Map<String, byte[]> getClassBytes()
|
||||
{
|
||||
return classBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
classBytes = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* A file object used to represent Java source coming from a string.
|
||||
*/
|
||||
private static class StringInputBuffer extends SimpleJavaFileObject
|
||||
{
|
||||
final String code;
|
||||
|
||||
StringInputBuffer(String name, String code)
|
||||
{
|
||||
super(toURI(name), Kind.SOURCE);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharBuffer getCharContent(boolean ignoreEncodingErrors)
|
||||
{
|
||||
return CharBuffer.wrap(code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A file object that stores Java bytecode into the classBytes map.
|
||||
*/
|
||||
private class ClassOutputBuffer extends SimpleJavaFileObject
|
||||
{
|
||||
protected final String name;
|
||||
|
||||
ClassOutputBuffer(String name)
|
||||
{
|
||||
super(toURI(name), Kind.CLASS);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream openOutputStream()
|
||||
{
|
||||
return new FilterOutputStream(new ByteArrayOutputStream())
|
||||
{
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
out.close();
|
||||
classBytes.put(name, ((ByteArrayOutputStream) out).toByteArray());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, Kind kind, FileObject sibling) throws IOException
|
||||
{
|
||||
if (kind == Kind.CLASS)
|
||||
{
|
||||
return new ClassOutputBuffer(className.replace('/', '.'));
|
||||
}
|
||||
return super.getJavaFileForOutput(location, className, kind, sibling);
|
||||
}
|
||||
|
||||
static JavaFileObject makeStringSource(String name, String code)
|
||||
{
|
||||
return new StringInputBuffer(name, code);
|
||||
}
|
||||
|
||||
static URI toURI(String name)
|
||||
{
|
||||
final File file = new File(name);
|
||||
if (file.exists())
|
||||
{
|
||||
return file.toURI();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
final StringBuilder newUri = new StringBuilder();
|
||||
newUri.append("file:///");
|
||||
newUri.append(name.replace('.', '/'));
|
||||
if (name.endsWith(EXT))
|
||||
{
|
||||
newUri.replace(newUri.length() - EXT.length(), newUri.length(), EXT);
|
||||
}
|
||||
return URI.create(newUri.toString());
|
||||
}
|
||||
catch (Exception exp)
|
||||
{
|
||||
return URI.create("file:///com/sun/script/java/java_source");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
* @param <T>
|
||||
*/
|
||||
public abstract class ChannelInboundHandler<T extends ChannelInboundHandler<?>>extends SimpleChannelInboundHandler<IIncomingPacket<T>>
|
||||
{
|
||||
private Channel _channel;
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx)
|
||||
{
|
||||
_channel = ctx.channel();
|
||||
}
|
||||
|
||||
public void setConnectionState(IConnectionState connectionState)
|
||||
{
|
||||
_channel.attr(IConnectionState.ATTRIBUTE_KEY).set(connectionState);
|
||||
}
|
||||
|
||||
public IConnectionState getConnectionState()
|
||||
{
|
||||
return _channel != null ? _channel.attr(IConnectionState.ATTRIBUTE_KEY).get() : null;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network;
|
||||
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
*/
|
||||
public interface IConnectionState
|
||||
{
|
||||
AttributeKey<IConnectionState> ATTRIBUTE_KEY = AttributeKey.valueOf(IConnectionState.class, "");
|
||||
}
|
29
trunk/java/com/l2jmobius/commons/network/ICrypt.java
Normal file
29
trunk/java/com/l2jmobius/commons/network/ICrypt.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
*/
|
||||
public interface ICrypt
|
||||
{
|
||||
void encrypt(ByteBuf buf);
|
||||
|
||||
void decrypt(ByteBuf buf);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
* @param <T>
|
||||
*/
|
||||
public interface IIncomingPacket<T>
|
||||
{
|
||||
/**
|
||||
* Reads a packet.
|
||||
* @param client the client
|
||||
* @param packet the packet reader
|
||||
* @return {@code true} if packet was read successfully, {@code false} otherwise.
|
||||
*/
|
||||
boolean read(T client, PacketReader packet);
|
||||
|
||||
void run(T client) throws Exception;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
* @param <T>
|
||||
*/
|
||||
public interface IIncomingPackets<T>extends IConnectionState
|
||||
{
|
||||
int getPacketId();
|
||||
|
||||
IIncomingPacket<T> newIncomingPacket();
|
||||
|
||||
Set<IConnectionState> getConnectionStates();
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
*/
|
||||
public interface IOutgoingPacket
|
||||
{
|
||||
/**
|
||||
* @param packet the packet writer
|
||||
* @return {@code true} if packet was writen successfully, {@code false} otherwise.
|
||||
*/
|
||||
boolean write(PacketWriter packet);
|
||||
}
|
76
trunk/java/com/l2jmobius/commons/network/NetworkManager.java
Normal file
76
trunk/java/com/l2jmobius/commons/network/NetworkManager.java
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
*/
|
||||
public class NetworkManager
|
||||
{
|
||||
private final Logger LOGGER = Logger.getLogger(getClass().getName());
|
||||
|
||||
private final ServerBootstrap _serverBootstrap;
|
||||
private final String _host;
|
||||
private final int _port;
|
||||
|
||||
private ChannelFuture _channelFuture;
|
||||
|
||||
public NetworkManager(EventLoopGroup bossGroup, EventLoopGroup workerGroup, ChannelInitializer<SocketChannel> clientInitializer, String host, int port)
|
||||
{
|
||||
// @formatter:off
|
||||
_serverBootstrap = new ServerBootstrap()
|
||||
.group(bossGroup, workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.childHandler(clientInitializer)
|
||||
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||
// @formatter:on
|
||||
_host = host;
|
||||
_port = port;
|
||||
}
|
||||
|
||||
public ChannelFuture getChannelFuture()
|
||||
{
|
||||
return _channelFuture;
|
||||
}
|
||||
|
||||
public void start() throws InterruptedException
|
||||
{
|
||||
if ((_channelFuture != null) && !_channelFuture.isDone())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_channelFuture = _serverBootstrap.bind(_host, _port).sync();
|
||||
LOGGER.info(getClass().getSimpleName() + ": Listening on " + _host + ":" + _port);
|
||||
}
|
||||
|
||||
public void stop() throws InterruptedException
|
||||
{
|
||||
_channelFuture.channel().close().sync();
|
||||
}
|
||||
}
|
163
trunk/java/com/l2jmobius/commons/network/PacketReader.java
Normal file
163
trunk/java/com/l2jmobius/commons/network/PacketReader.java
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
*/
|
||||
public final class PacketReader
|
||||
{
|
||||
private final ByteBuf _buf;
|
||||
|
||||
public PacketReader(ByteBuf buf)
|
||||
{
|
||||
_buf = buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the readable bytes.
|
||||
* @return the readable bytes
|
||||
*/
|
||||
public int getReadableBytes()
|
||||
{
|
||||
return _buf.readableBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an unsigned byte.
|
||||
* @return the unsigned byte
|
||||
* @throws IndexOutOfBoundsException if {@code readableBytes} is less than {@code 1}
|
||||
*/
|
||||
public short readC()
|
||||
{
|
||||
return _buf.readUnsignedByte();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an unsigned short.
|
||||
* @return the unsigned short
|
||||
* @throws IndexOutOfBoundsException if {@code readableBytes} is less than {@code 2}
|
||||
*/
|
||||
public int readH()
|
||||
{
|
||||
return _buf.readUnsignedShort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an integer.
|
||||
* @return the integer
|
||||
* @throws IndexOutOfBoundsException if {@code readableBytes} is less than {@code 4}
|
||||
*/
|
||||
public int readD()
|
||||
{
|
||||
return _buf.readInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a long.
|
||||
* @return the long
|
||||
* @throws IndexOutOfBoundsException if {@code readableBytes} is less than {@code 8}
|
||||
*/
|
||||
public long readQ()
|
||||
{
|
||||
return _buf.readLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a float.
|
||||
* @return the float
|
||||
* @throws IndexOutOfBoundsException if {@code readableBytes} is less than {@code 4}
|
||||
*/
|
||||
public float readE()
|
||||
{
|
||||
return _buf.readFloat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a double.
|
||||
* @return the double
|
||||
* @throws IndexOutOfBoundsException if {@code readableBytes} is less than {@code 8}
|
||||
*/
|
||||
public double readF()
|
||||
{
|
||||
return _buf.readDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a string.
|
||||
* @return the string
|
||||
* @throws IndexOutOfBoundsException if string {@code null} terminator is not found within {@code readableBytes}
|
||||
*/
|
||||
public String readS()
|
||||
{
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
char chr;
|
||||
while ((chr = _buf.readChar()) != 0)
|
||||
{
|
||||
sb.append(chr);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a fixed length string.
|
||||
* @return the string
|
||||
* @throws IndexOutOfBoundsException if {@code readableBytes} is less than {@code 2 + String.length * 2}
|
||||
*/
|
||||
public String readString()
|
||||
{
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final int stringLength = _buf.readShort();
|
||||
if ((stringLength * 2) > getReadableBytes())
|
||||
{
|
||||
throw new IndexOutOfBoundsException("readerIndex(" + _buf.readerIndex() + ") + length(" + (stringLength * 2) + ") exceeds writerIndex(" + _buf.writerIndex() + "): " + _buf);
|
||||
}
|
||||
|
||||
for (int i = 0; i < stringLength; i++)
|
||||
{
|
||||
sb.append(_buf.readChar());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte array.
|
||||
* @param length the length
|
||||
* @return the byte array
|
||||
* @throws IndexOutOfBoundsException if {@code readableBytes} is less than {@code length}
|
||||
*/
|
||||
public byte[] readB(int length)
|
||||
{
|
||||
final byte[] result = new byte[length];
|
||||
_buf.readBytes(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte array.
|
||||
* @param dst the destination
|
||||
* @param dstIndex the destination index to start writing the bytes from
|
||||
* @param length the length
|
||||
* @throws IndexOutOfBoundsException if {@code readableBytes} is less than {@code length}, if the specified dstIndex is less than 0 or if {@code dstIndex + length} is greater than {@code dst.length}
|
||||
*/
|
||||
public void readB(byte[] dst, int dstIndex, int length)
|
||||
{
|
||||
_buf.readBytes(dst, dstIndex, length);
|
||||
}
|
||||
}
|
141
trunk/java/com/l2jmobius/commons/network/PacketWriter.java
Normal file
141
trunk/java/com/l2jmobius/commons/network/PacketWriter.java
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
*/
|
||||
public final class PacketWriter
|
||||
{
|
||||
private final ByteBuf _buf;
|
||||
|
||||
public PacketWriter(ByteBuf buf)
|
||||
{
|
||||
_buf = buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the writable bytes.
|
||||
* @return the writable bytes
|
||||
*/
|
||||
public int getWritableBytes()
|
||||
{
|
||||
return _buf.writableBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte.
|
||||
* @param value the byte (The 24 high-order bits are ignored)
|
||||
*/
|
||||
public void writeC(int value)
|
||||
{
|
||||
_buf.writeByte(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a short.
|
||||
* @param value the short (The 16 high-order bits are ignored)
|
||||
*/
|
||||
public void writeH(int value)
|
||||
{
|
||||
_buf.writeShort(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an integer.
|
||||
* @param value the integer
|
||||
*/
|
||||
public void writeD(int value)
|
||||
{
|
||||
_buf.writeInt(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a long.
|
||||
* @param value the long
|
||||
*/
|
||||
public void writeQ(long value)
|
||||
{
|
||||
_buf.writeLong(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a float.
|
||||
* @param value the float
|
||||
*/
|
||||
public void writeE(float value)
|
||||
{
|
||||
_buf.writeFloat(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a double.
|
||||
* @param value the double
|
||||
*/
|
||||
public void writeF(double value)
|
||||
{
|
||||
_buf.writeDouble(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a string.
|
||||
* @param value the string
|
||||
*/
|
||||
public void writeS(String value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
for (int i = 0; i < value.length(); i++)
|
||||
{
|
||||
_buf.writeChar(value.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
_buf.writeChar(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a string with fixed length specified as [short length, char[length] data].
|
||||
* @param value the string
|
||||
*/
|
||||
public void writeString(String value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
_buf.writeShort(value.length());
|
||||
for (int i = 0; i < value.length(); i++)
|
||||
{
|
||||
_buf.writeChar(value.charAt(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_buf.writeShort(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte array.
|
||||
* @param bytes the byte array
|
||||
*/
|
||||
public void writeB(byte[] bytes)
|
||||
{
|
||||
_buf.writeBytes(bytes);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network.codecs;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.l2jmobius.commons.network.ICrypt;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageCodec;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
*/
|
||||
public class CryptCodec extends ByteToMessageCodec<ByteBuf>
|
||||
{
|
||||
private final ICrypt _crypt;
|
||||
|
||||
public CryptCodec(ICrypt crypt)
|
||||
{
|
||||
super();
|
||||
_crypt = crypt;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.netty.handler.codec.ByteToMessageCodec#encode(io.netty.channel.ChannelHandlerContext, java.lang.Object, io.netty.buffer.ByteBuf)
|
||||
*/
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out)
|
||||
{
|
||||
// Check if there are any data to encrypt.
|
||||
if (!msg.isReadable())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
msg.resetReaderIndex();
|
||||
_crypt.encrypt(msg);
|
||||
msg.resetReaderIndex();
|
||||
out.writeBytes(msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.netty.handler.codec.ByteToMessageCodec#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)
|
||||
*/
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
|
||||
{
|
||||
in.resetReaderIndex();
|
||||
_crypt.decrypt(in);
|
||||
in.readerIndex(in.writerIndex());
|
||||
out.add(in.copy(0, in.writerIndex()));
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network.codecs;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.List;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
*/
|
||||
@Sharable
|
||||
public class LengthFieldBasedFrameEncoder extends MessageToMessageEncoder<ByteBuf>
|
||||
{
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out)
|
||||
{
|
||||
final ByteBuf buf = ctx.alloc().buffer(2);
|
||||
final short length = (short) (msg.readableBytes() + 2);
|
||||
buf.writeShort(buf.order() != ByteOrder.LITTLE_ENDIAN ? Short.reverseBytes(length) : length);
|
||||
out.add(buf);
|
||||
out.add(msg.retain());
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network.codecs;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jmobius.commons.network.IConnectionState;
|
||||
import com.l2jmobius.commons.network.IIncomingPacket;
|
||||
import com.l2jmobius.commons.network.IIncomingPackets;
|
||||
import com.l2jmobius.commons.network.PacketReader;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
* @param <T>
|
||||
*/
|
||||
public class PacketDecoder<T>extends ByteToMessageDecoder
|
||||
{
|
||||
private static final Logger LOGGER = Logger.getLogger(PacketDecoder.class.getName());
|
||||
|
||||
private final ByteOrder _byteOrder;
|
||||
private final IIncomingPackets<T>[] _incomingPackets;
|
||||
private final T _client;
|
||||
|
||||
public PacketDecoder(ByteOrder byteOrder, IIncomingPackets<T>[] incomingPackets, T client)
|
||||
{
|
||||
_byteOrder = byteOrder;
|
||||
_incomingPackets = incomingPackets;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
|
||||
{
|
||||
if ((in == null) || !in.isReadable())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (in.order() != _byteOrder)
|
||||
{
|
||||
in = in.order(_byteOrder);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
final short packetId = in.readUnsignedByte();
|
||||
if (packetId >= _incomingPackets.length)
|
||||
{
|
||||
LOGGER.finer("Unknown packet: " + Integer.toHexString(packetId));
|
||||
return;
|
||||
}
|
||||
|
||||
final IIncomingPackets<T> incomingPacket = _incomingPackets[packetId];
|
||||
if (incomingPacket == null)
|
||||
{
|
||||
LOGGER.finer("Unknown packet: " + Integer.toHexString(packetId));
|
||||
return;
|
||||
}
|
||||
|
||||
final IConnectionState connectionState = ctx.channel().attr(IConnectionState.ATTRIBUTE_KEY).get();
|
||||
if ((connectionState == null) || !incomingPacket.getConnectionStates().contains(connectionState))
|
||||
{
|
||||
// LOGGER.warning(incomingPacket + ": Connection at invalid state: " + connectionState + " Required States: " + incomingPacket.getConnectionStates());
|
||||
return;
|
||||
}
|
||||
|
||||
final IIncomingPacket<T> packet = incomingPacket.newIncomingPacket();
|
||||
if ((packet != null) && packet.read(_client, new PacketReader(in)))
|
||||
{
|
||||
out.add(packet);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// We always consider that we read whole packet.
|
||||
in.readerIndex(in.writerIndex());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.network.codecs;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jmobius.commons.network.IOutgoingPacket;
|
||||
import com.l2jmobius.commons.network.PacketWriter;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
|
||||
/**
|
||||
* @author Nos
|
||||
*/
|
||||
@Sharable
|
||||
public class PacketEncoder extends MessageToByteEncoder<IOutgoingPacket>
|
||||
{
|
||||
private static final Logger LOGGER = Logger.getLogger(PacketEncoder.class.getName());
|
||||
|
||||
private final ByteOrder _byteOrder;
|
||||
private final int _maxPacketSize;
|
||||
|
||||
public PacketEncoder(ByteOrder byteOrder, int maxPacketSize)
|
||||
{
|
||||
super();
|
||||
_byteOrder = byteOrder;
|
||||
_maxPacketSize = maxPacketSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, IOutgoingPacket packet, ByteBuf out)
|
||||
{
|
||||
if (out.order() != _byteOrder)
|
||||
{
|
||||
out = out.order(_byteOrder);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (packet.write(new PacketWriter(out)))
|
||||
{
|
||||
if (out.writerIndex() > _maxPacketSize)
|
||||
{
|
||||
throw new IllegalStateException("Packet (" + packet + ") size (" + out.writerIndex() + ") is bigger than the limit (" + _maxPacketSize + ")");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Avoid sending the packet
|
||||
out.clear();
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "Failed sending Packet(" + packet + ")", e);
|
||||
// Avoid sending the packet if some exception happened
|
||||
out.clear();
|
||||
}
|
||||
}
|
||||
}
|
564
trunk/java/com/l2jmobius/commons/util/CommonUtil.java
Normal file
564
trunk/java/com/l2jmobius/commons/util/CommonUtil.java
Normal file
@ -0,0 +1,564 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import com.l2jmobius.Config;
|
||||
|
||||
public final class CommonUtil
|
||||
{
|
||||
private static final char[] ILLEGAL_CHARACTERS =
|
||||
{
|
||||
'/',
|
||||
'\n',
|
||||
'\r',
|
||||
'\t',
|
||||
'\0',
|
||||
'\f',
|
||||
'`',
|
||||
'?',
|
||||
'*',
|
||||
'\\',
|
||||
'<',
|
||||
'>',
|
||||
'|',
|
||||
'\"',
|
||||
':'
|
||||
};
|
||||
|
||||
/**
|
||||
* Method to generate the hexadecimal representation of a byte array.<br>
|
||||
* 16 bytes per row, while ascii chars or "." is shown at the end of the line.
|
||||
* @param data the byte array to be represented in hexadecimal representation
|
||||
* @param len the number of bytes to represent in hexadecimal representation
|
||||
* @return byte array represented in hexadecimal format
|
||||
*/
|
||||
public static String printData(byte[] data, int len)
|
||||
{
|
||||
return new String(HexUtils.bArr2HexEdChars(data, len));
|
||||
}
|
||||
|
||||
/**
|
||||
* This call is equivalent to Util.printData(data, data.length)
|
||||
* @see CommonUtil#printData(byte[],int)
|
||||
* @param data data to represent in hexadecimal
|
||||
* @return byte array represented in hexadecimal format
|
||||
*/
|
||||
public static String printData(byte[] data)
|
||||
{
|
||||
return printData(data, data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to represent the remaining bytes of a ByteBuffer as hexadecimal
|
||||
* @param buf ByteBuffer to represent the remaining bytes of as hexadecimal
|
||||
* @return hexadecimal representation of remaining bytes of the ByteBuffer
|
||||
*/
|
||||
public static String printData(ByteBuffer buf)
|
||||
{
|
||||
final byte[] data = new byte[buf.remaining()];
|
||||
buf.get(data);
|
||||
final String hex = CommonUtil.printData(data, data.length);
|
||||
buf.position(buf.position() - data.length);
|
||||
return hex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate a random sequence of bytes returned as byte array
|
||||
* @param size number of random bytes to generate
|
||||
* @return byte array with sequence of random bytes
|
||||
*/
|
||||
public static byte[] generateHex(int size)
|
||||
{
|
||||
final byte[] array = new byte[size];
|
||||
Rnd.nextBytes(array);
|
||||
|
||||
// Don't allow 0s inside the array!
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
while (array[i] == 0)
|
||||
{
|
||||
array[i] = (byte) Rnd.get(Byte.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces most invalid characters for the given string with an underscore.
|
||||
* @param str the string that may contain invalid characters
|
||||
* @return the string with invalid character replaced by underscores
|
||||
*/
|
||||
public static String replaceIllegalCharacters(String str)
|
||||
{
|
||||
String valid = str;
|
||||
for (char c : ILLEGAL_CHARACTERS)
|
||||
{
|
||||
valid = valid.replace(c, '_');
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if a file name is valid.
|
||||
* @param name the name of the file
|
||||
* @return {@code true} if the file name is valid, {@code false} otherwise
|
||||
*/
|
||||
public static boolean isValidFileName(String name)
|
||||
{
|
||||
final File f = new File(name);
|
||||
try
|
||||
{
|
||||
f.getCanonicalPath();
|
||||
return true;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Split words with a space.
|
||||
* @param input the string to split
|
||||
* @return the split string
|
||||
*/
|
||||
public static String splitWords(String input)
|
||||
{
|
||||
return input.replaceAll("(\\p{Ll})(\\p{Lu})", "$1 $2");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next or same closest date from the specified days in {@code daysOfWeek Array} at specified {@code hour} and {@code min}.
|
||||
* @param daysOfWeek the days of week
|
||||
* @param hour the hour
|
||||
* @param min the min
|
||||
* @return the next or same date from the days of week at specified time
|
||||
* @throws IllegalArgumentException if the {@code daysOfWeek Array} is empty.
|
||||
*/
|
||||
public static LocalDateTime getNextClosestDateTime(DayOfWeek[] daysOfWeek, int hour, int min) throws IllegalArgumentException
|
||||
{
|
||||
return getNextClosestDateTime(Arrays.asList(daysOfWeek), hour, min);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next or same closest date from the specified days in {@code daysOfWeek List} at specified {@code hour} and {@code min}.
|
||||
* @param daysOfWeek the days of week
|
||||
* @param hour the hour
|
||||
* @param min the min
|
||||
* @return the next or same date from the days of week at specified time
|
||||
* @throws IllegalArgumentException if the {@code daysOfWeek List} is empty.
|
||||
*/
|
||||
public static LocalDateTime getNextClosestDateTime(List<DayOfWeek> daysOfWeek, int hour, int min) throws IllegalArgumentException
|
||||
{
|
||||
if (daysOfWeek.isEmpty())
|
||||
{
|
||||
throw new IllegalArgumentException("daysOfWeek should not be empty.");
|
||||
}
|
||||
|
||||
final LocalDateTime dateNow = LocalDateTime.now();
|
||||
final LocalDateTime dateNowWithDifferentTime = dateNow.withHour(hour).withMinute(min).withSecond(0);
|
||||
|
||||
// @formatter:off
|
||||
return daysOfWeek.stream()
|
||||
.map(d -> dateNowWithDifferentTime.with(TemporalAdjusters.nextOrSame(d)))
|
||||
.filter(d -> d.isAfter(dateNow))
|
||||
.min(Comparator.naturalOrder())
|
||||
.orElse(dateNowWithDifferentTime.with(TemporalAdjusters.next(daysOfWeek.get(0))));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the stack trace of a Throwable into a String
|
||||
* @param t Throwable to get the stacktrace from
|
||||
* @return stack trace from Throwable as String
|
||||
*/
|
||||
public static String getStackTrace(Throwable t)
|
||||
{
|
||||
final StringWriter sw = new StringWriter();
|
||||
t.printStackTrace(new PrintWriter(sw));
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
public static String getTraceString(StackTraceElement[] stackTraceElements)
|
||||
{
|
||||
final StringJoiner sj = new StringJoiner(Config.EOL);
|
||||
for (StackTraceElement stackTraceElement : stackTraceElements)
|
||||
{
|
||||
sj.add(stackTraceElement.toString());
|
||||
}
|
||||
return sj.toString();
|
||||
}
|
||||
|
||||
public static int min(int value1, int value2, int... values)
|
||||
{
|
||||
int min = Math.min(value1, value2);
|
||||
for (int value : values)
|
||||
{
|
||||
if (min > value)
|
||||
{
|
||||
min = value;
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
public static int max(int value1, int value2, int... values)
|
||||
{
|
||||
int max = Math.max(value1, value2);
|
||||
for (int value : values)
|
||||
{
|
||||
if (max < value)
|
||||
{
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public static long min(long value1, long value2, long... values)
|
||||
{
|
||||
long min = Math.min(value1, value2);
|
||||
for (long value : values)
|
||||
{
|
||||
if (min > value)
|
||||
{
|
||||
min = value;
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
public static long max(long value1, long value2, long... values)
|
||||
{
|
||||
long max = Math.max(value1, value2);
|
||||
for (long value : values)
|
||||
{
|
||||
if (max < value)
|
||||
{
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public static float min(float value1, float value2, float... values)
|
||||
{
|
||||
float min = Math.min(value1, value2);
|
||||
for (float value : values)
|
||||
{
|
||||
if (min > value)
|
||||
{
|
||||
min = value;
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
public static float max(float value1, float value2, float... values)
|
||||
{
|
||||
float max = Math.max(value1, value2);
|
||||
for (float value : values)
|
||||
{
|
||||
if (max < value)
|
||||
{
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public static double min(double value1, double value2, double... values)
|
||||
{
|
||||
double min = Math.min(value1, value2);
|
||||
for (double value : values)
|
||||
{
|
||||
if (min > value)
|
||||
{
|
||||
min = value;
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
public static double max(double value1, double value2, double... values)
|
||||
{
|
||||
double max = Math.max(value1, value2);
|
||||
for (double value : values)
|
||||
{
|
||||
if (max < value)
|
||||
{
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public static int getIndexOfMaxValue(int... array)
|
||||
{
|
||||
int index = 0;
|
||||
for (int i = 1; i < array.length; i++)
|
||||
{
|
||||
if (array[i] > array[index])
|
||||
{
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public static int getIndexOfMinValue(int... array)
|
||||
{
|
||||
int index = 0;
|
||||
for (int i = 1; i < array.length; i++)
|
||||
{
|
||||
if (array[i] < array[index])
|
||||
{
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-Maps a value from one range to another.
|
||||
* @param input
|
||||
* @param inputMin
|
||||
* @param inputMax
|
||||
* @param outputMin
|
||||
* @param outputMax
|
||||
* @return The mapped value
|
||||
*/
|
||||
public static int map(int input, int inputMin, int inputMax, int outputMin, int outputMax)
|
||||
{
|
||||
input = constrain(input, inputMin, inputMax);
|
||||
return (((input - inputMin) * (outputMax - outputMin)) / (inputMax - inputMin)) + outputMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-Maps a value from one range to another.
|
||||
* @param input
|
||||
* @param inputMin
|
||||
* @param inputMax
|
||||
* @param outputMin
|
||||
* @param outputMax
|
||||
* @return The mapped value
|
||||
*/
|
||||
public static long map(long input, long inputMin, long inputMax, long outputMin, long outputMax)
|
||||
{
|
||||
input = constrain(input, inputMin, inputMax);
|
||||
return (((input - inputMin) * (outputMax - outputMin)) / (inputMax - inputMin)) + outputMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-Maps a value from one range to another.
|
||||
* @param input
|
||||
* @param inputMin
|
||||
* @param inputMax
|
||||
* @param outputMin
|
||||
* @param outputMax
|
||||
* @return The mapped value
|
||||
*/
|
||||
public static double map(double input, double inputMin, double inputMax, double outputMin, double outputMax)
|
||||
{
|
||||
input = constrain(input, inputMin, inputMax);
|
||||
return (((input - inputMin) * (outputMax - outputMin)) / (inputMax - inputMin)) + outputMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constrains a number to be within a range.
|
||||
* @param input the number to constrain, all data types
|
||||
* @param min the lower end of the range, all data types
|
||||
* @param max the upper end of the range, all data types
|
||||
* @return input: if input is between min and max, min: if input is less than min, max: if input is greater than max
|
||||
*/
|
||||
public static int constrain(int input, int min, int max)
|
||||
{
|
||||
return (input < min) ? min : (input > max) ? max : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constrains a number to be within a range.
|
||||
* @param input the number to constrain, all data types
|
||||
* @param min the lower end of the range, all data types
|
||||
* @param max the upper end of the range, all data types
|
||||
* @return input: if input is between min and max, min: if input is less than min, max: if input is greater than max
|
||||
*/
|
||||
public static long constrain(long input, long min, long max)
|
||||
{
|
||||
return (input < min) ? min : (input > max) ? max : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constrains a number to be within a range.
|
||||
* @param input the number to constrain, all data types
|
||||
* @param min the lower end of the range, all data types
|
||||
* @param max the upper end of the range, all data types
|
||||
* @return input: if input is between min and max, min: if input is less than min, max: if input is greater than max
|
||||
*/
|
||||
public static double constrain(double input, double min, double max)
|
||||
{
|
||||
return (input < min) ? min : (input > max) ? max : input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array - the array to look into
|
||||
* @param obj - the object to search for
|
||||
* @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise.
|
||||
*/
|
||||
public static boolean startsWith(String[] array, String obj)
|
||||
{
|
||||
for (String element : array)
|
||||
{
|
||||
if (element.startsWith(obj))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @param array - the array to look into
|
||||
* @param obj - the object to search for
|
||||
* @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise.
|
||||
*/
|
||||
public static <T> boolean contains(T[] array, T obj)
|
||||
{
|
||||
for (T element : array)
|
||||
{
|
||||
if (element == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array - the array to look into
|
||||
* @param obj - the integer to search for
|
||||
* @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise
|
||||
*/
|
||||
public static boolean contains(int[] array, int obj)
|
||||
{
|
||||
for (int element : array)
|
||||
{
|
||||
if (element == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array - the array to look into
|
||||
* @param obj - the object to search for
|
||||
* @param ignoreCase
|
||||
* @return {@code true} if the {@code array} contains the {@code obj}, {@code false} otherwise.
|
||||
*/
|
||||
public static boolean contains(String[] array, String obj, boolean ignoreCase)
|
||||
{
|
||||
for (String element : array)
|
||||
{
|
||||
if (element.equals(obj) || (ignoreCase && element.equalsIgnoreCase(obj)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int parseNextInt(StringTokenizer st, int defaultVal)
|
||||
{
|
||||
try
|
||||
{
|
||||
final String value = st.nextToken().trim();
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str - the string whose first letter to capitalize
|
||||
* @return a string with the first letter of the {@code str} capitalized
|
||||
*/
|
||||
public static String capitalizeFirst(String str)
|
||||
{
|
||||
if ((str == null) || str.isEmpty())
|
||||
{
|
||||
return str;
|
||||
}
|
||||
final char[] arr = str.toCharArray();
|
||||
final char c = arr[0];
|
||||
|
||||
if (Character.isLetter(c))
|
||||
{
|
||||
arr[0] = Character.toUpperCase(c);
|
||||
}
|
||||
return new String(arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on implode() in PHP
|
||||
* @param <T>
|
||||
* @param iteratable
|
||||
* @param delim
|
||||
* @return a delimited string for a given array of string elements.
|
||||
*/
|
||||
public static <T> String implode(Iterable<T> iteratable, String delim)
|
||||
{
|
||||
final StringJoiner sj = new StringJoiner(delim);
|
||||
iteratable.forEach(o -> sj.add(o.toString()));
|
||||
return sj.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on implode() in PHP
|
||||
* @param <T>
|
||||
* @param array
|
||||
* @param delim
|
||||
* @return a delimited string for a given array of string elements.
|
||||
*/
|
||||
public static <T> String implode(T[] array, String delim)
|
||||
{
|
||||
final StringJoiner sj = new StringJoiner(delim);
|
||||
for (T o : array)
|
||||
{
|
||||
sj.add(o.toString());
|
||||
}
|
||||
return sj.toString();
|
||||
}
|
||||
}
|
121
trunk/java/com/l2jmobius/commons/util/DeadLockDetector.java
Normal file
121
trunk/java/com/l2jmobius/commons/util/DeadLockDetector.java
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import java.lang.management.LockInfo;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MonitorInfo;
|
||||
import java.lang.management.ThreadInfo;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.time.Duration;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jmobius.Config;
|
||||
|
||||
/**
|
||||
* Thread to check for deadlocked threads.
|
||||
* @author -Nemesiss- L2M
|
||||
*/
|
||||
public class DeadLockDetector extends Thread
|
||||
{
|
||||
private static Logger LOGGER = Logger.getLogger(DeadLockDetector.class.getName());
|
||||
|
||||
private final Duration _checkInterval;
|
||||
private final Runnable _deadLockCallback;
|
||||
private final ThreadMXBean tmx;
|
||||
|
||||
public DeadLockDetector(Duration checkInterval, Runnable deadLockCallback)
|
||||
{
|
||||
super("DeadLockDetector");
|
||||
_checkInterval = checkInterval;
|
||||
_deadLockCallback = deadLockCallback;
|
||||
tmx = ManagementFactory.getThreadMXBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void run()
|
||||
{
|
||||
boolean deadlock = false;
|
||||
while (!deadlock)
|
||||
{
|
||||
try
|
||||
{
|
||||
final long[] ids = tmx.findDeadlockedThreads();
|
||||
|
||||
if (ids != null)
|
||||
{
|
||||
deadlock = true;
|
||||
final ThreadInfo[] tis = tmx.getThreadInfo(ids, true, true);
|
||||
final StringBuilder info = new StringBuilder();
|
||||
info.append("DeadLock Found!");
|
||||
info.append(Config.EOL);
|
||||
for (ThreadInfo ti : tis)
|
||||
{
|
||||
info.append(ti.toString());
|
||||
}
|
||||
|
||||
for (ThreadInfo ti : tis)
|
||||
{
|
||||
final LockInfo[] locks = ti.getLockedSynchronizers();
|
||||
final MonitorInfo[] monitors = ti.getLockedMonitors();
|
||||
if ((locks.length == 0) && (monitors.length == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ThreadInfo dl = ti;
|
||||
info.append("Java-level deadlock:");
|
||||
info.append(Config.EOL);
|
||||
info.append('\t');
|
||||
info.append(dl.getThreadName());
|
||||
info.append(" is waiting to lock ");
|
||||
info.append(dl.getLockInfo().toString());
|
||||
info.append(" which is held by ");
|
||||
info.append(dl.getLockOwnerName());
|
||||
info.append(Config.EOL);
|
||||
while ((dl = tmx.getThreadInfo(new long[]
|
||||
{
|
||||
dl.getLockOwnerId()
|
||||
}, true, true)[0]).getThreadId() != ti.getThreadId())
|
||||
{
|
||||
info.append('\t');
|
||||
info.append(dl.getThreadName());
|
||||
info.append(" is waiting to lock ");
|
||||
info.append(dl.getLockInfo().toString());
|
||||
info.append(" which is held by ");
|
||||
info.append(dl.getLockOwnerName());
|
||||
info.append(Config.EOL);
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.warning(info.toString());
|
||||
|
||||
if (_deadLockCallback != null)
|
||||
{
|
||||
_deadLockCallback.run();
|
||||
}
|
||||
}
|
||||
Thread.sleep(_checkInterval.toMillis());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
145
trunk/java/com/l2jmobius/commons/util/EmptyQueue.java
Normal file
145
trunk/java/com/l2jmobius/commons/util/EmptyQueue.java
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
* @param <E>
|
||||
*/
|
||||
public final class EmptyQueue<E> implements Queue<E>
|
||||
{
|
||||
private static final Queue<Object> EMPTY_QUEUE = new EmptyQueue<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <E> Queue<E> emptyQueue()
|
||||
{
|
||||
return (Queue<E>) EMPTY_QUEUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator()
|
||||
{
|
||||
return Collections.<E> emptyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray()
|
||||
{
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> c)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offer(E e)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E poll()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E element()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E peek()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
260
trunk/java/com/l2jmobius/commons/util/HexUtils.java
Normal file
260
trunk/java/com/l2jmobius/commons/util/HexUtils.java
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author HorridoJoho
|
||||
*/
|
||||
public class HexUtils
|
||||
{
|
||||
// lookup table for hex characters
|
||||
private static final char[] _NIBBLE_CHAR_LOOKUP =
|
||||
{
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'F'
|
||||
};
|
||||
private static final char[] _NEW_LINE_CHARS = System.getProperty("line.separator").toCharArray();
|
||||
|
||||
/**
|
||||
* Method to generate the hexadecimal character presentation of a byte<br>
|
||||
* This call is equivalent to {@link HexUtils#b2HexChars(byte, char[], int)} with parameters (data, null, 0)
|
||||
* @param data byte to generate the hexadecimal character presentation from
|
||||
* @return a new char array with exactly 2 elements
|
||||
*/
|
||||
public static char[] b2HexChars(byte data)
|
||||
{
|
||||
return b2HexChars(data, null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate the hexadecimal character presentation of a byte
|
||||
* @param data byte to generate the hexadecimal character presentation from
|
||||
* @param dstHexChars the char array the hexadecimal character presentation should be copied to, if this is null, dstOffset is ignored and a new char array with 2 elements is created
|
||||
* @param dstOffset offset at which the hexadecimal character presentation is copied to dstHexChars
|
||||
* @return the char array the hexadecimal character presentation was copied to
|
||||
*/
|
||||
public static char[] b2HexChars(byte data, char[] dstHexChars, int dstOffset)
|
||||
{
|
||||
if (dstHexChars == null)
|
||||
{
|
||||
dstHexChars = new char[2];
|
||||
dstOffset = 0;
|
||||
}
|
||||
|
||||
// /////////////////////////////
|
||||
// NIBBLE LOOKUP
|
||||
dstHexChars[dstOffset] = _NIBBLE_CHAR_LOOKUP[(data & 0xF0) >> 4];
|
||||
dstHexChars[dstOffset + 1] = _NIBBLE_CHAR_LOOKUP[data & 0x0F];
|
||||
|
||||
return dstHexChars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate the hexadecimal character presentation of an integer This call is equivalent to {@link HexUtils#int2HexChars(int, char[], int)} with parameters (data, null, 0)
|
||||
* @param data integer to generate the hexadecimal character presentation from
|
||||
* @return new char array with 8 elements
|
||||
*/
|
||||
public static char[] int2HexChars(int data)
|
||||
{
|
||||
return int2HexChars(data, new char[8], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate the hexadecimal character presentation of an integer
|
||||
* @param data integer to generate the hexadecimal character presentation from
|
||||
* @param dstHexChars the char array the hexadecimal character presentation should be copied to, if this is null, dstOffset is ignored and a new char array with 8 elements is created
|
||||
* @param dstOffset offset at which the hexadecimal character presentation is copied to dstHexChars
|
||||
* @return the char array the hexadecimal character presentation was copied to
|
||||
*/
|
||||
public static char[] int2HexChars(int data, char[] dstHexChars, int dstOffset)
|
||||
{
|
||||
if (dstHexChars == null)
|
||||
{
|
||||
dstHexChars = new char[8];
|
||||
dstOffset = 0;
|
||||
}
|
||||
|
||||
b2HexChars((byte) ((data & 0xFF000000) >> 24), dstHexChars, dstOffset);
|
||||
b2HexChars((byte) ((data & 0x00FF0000) >> 16), dstHexChars, dstOffset + 2);
|
||||
b2HexChars((byte) ((data & 0x0000FF00) >> 8), dstHexChars, dstOffset + 4);
|
||||
b2HexChars((byte) (data & 0x000000FF), dstHexChars, dstOffset + 6);
|
||||
return dstHexChars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate the hexadecimal character presentation of a byte array<br>
|
||||
* This call is equivalent to {@link HexUtils#bArr2HexChars(byte[], int, int, char[], int)} with parameters (data, offset, len, null, 0)
|
||||
* @param data byte array to generate the hexadecimal character presentation from
|
||||
* @param offset offset where to start in data array
|
||||
* @param len number of bytes to generate the hexadecimal character presentation from
|
||||
* @return a new char array with len*2 elements
|
||||
*/
|
||||
public static char[] bArr2HexChars(byte[] data, int offset, int len)
|
||||
{
|
||||
return bArr2HexChars(data, offset, len, null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate the hexadecimal character presentation of a byte array
|
||||
* @param data byte array to generate the hexadecimal character presentation from
|
||||
* @param offset offset where to start in data array
|
||||
* @param len number of bytes to generate the hexadecimal character presentation from
|
||||
* @param dstHexChars the char array the hexadecimal character presentation should be copied to, if this is null, dstOffset is ignored and a new char array with len*2 elements is created
|
||||
* @param dstOffset offset at which the hexadecimal character presentation is copied to dstHexChars
|
||||
* @return the char array the hexadecimal character presentation was copied to
|
||||
*/
|
||||
public static char[] bArr2HexChars(byte[] data, int offset, int len, char[] dstHexChars, int dstOffset)
|
||||
{
|
||||
if (dstHexChars == null)
|
||||
{
|
||||
dstHexChars = new char[len * 2];
|
||||
dstOffset = 0;
|
||||
}
|
||||
|
||||
for (int dataIdx = offset, charsIdx = dstOffset; dataIdx < (len + offset); ++dataIdx, ++charsIdx)
|
||||
{
|
||||
// /////////////////////////////
|
||||
// NIBBLE LOOKUP, we duplicate the code from b2HexChars here, we want to save a few cycles(for charsIdx increment)
|
||||
dstHexChars[charsIdx] = _NIBBLE_CHAR_LOOKUP[(data[dataIdx] & 0xF0) >> 4];
|
||||
dstHexChars[++charsIdx] = _NIBBLE_CHAR_LOOKUP[data[dataIdx] & 0x0F];
|
||||
}
|
||||
|
||||
return dstHexChars;
|
||||
}
|
||||
|
||||
public static char[] bArr2AsciiChars(byte[] data, int offset, int len)
|
||||
{
|
||||
return bArr2AsciiChars(data, offset, len, new char[len], 0);
|
||||
}
|
||||
|
||||
public static char[] bArr2AsciiChars(byte[] data, int offset, int len, char[] dstAsciiChars, int dstOffset)
|
||||
{
|
||||
if (dstAsciiChars == null)
|
||||
{
|
||||
dstAsciiChars = new char[len];
|
||||
dstOffset = 0;
|
||||
}
|
||||
|
||||
for (int dataIdx = offset, charsIdx = dstOffset; dataIdx < (len + offset); ++dataIdx, ++charsIdx)
|
||||
{
|
||||
if ((data[dataIdx] > 0x1f) && (data[dataIdx] < 0x80))
|
||||
{
|
||||
dstAsciiChars[charsIdx] = (char) data[dataIdx];
|
||||
}
|
||||
else
|
||||
{
|
||||
dstAsciiChars[charsIdx] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
return dstAsciiChars;
|
||||
}
|
||||
|
||||
private static final int _HEX_ED_BPL = 16;
|
||||
private static final int _HEX_ED_CPB = 2;
|
||||
|
||||
/**
|
||||
* Method to generate the hexadecimal character representation of a byte array like in a hex editor<br>
|
||||
* Line Format: {OFFSET} {HEXADECIMAL} {ASCII}({NEWLINE})<br>
|
||||
* {OFFSET} = offset of the first byte in line(8 chars)<br>
|
||||
* {HEXADECIMAL} = hexadecimal character representation({@link #_HEX_ED_BPL}*2 chars)<br>
|
||||
* {ASCII} = ascii character presentation({@link #_HEX_ED_BPL} chars)
|
||||
* @param data byte array to generate the hexadecimal character representation
|
||||
* @param len the number of bytes to generate the hexadecimal character representation from
|
||||
* @return byte array which contains the hexadecimal character representation of the given byte array
|
||||
*/
|
||||
public static char[] bArr2HexEdChars(byte[] data, int len)
|
||||
{
|
||||
// {OFFSET} {HEXADECIMAL} {ASCII}{NEWLINE}
|
||||
final int lineLength = 9 + (_HEX_ED_BPL * _HEX_ED_CPB) + 1 + _HEX_ED_BPL + _NEW_LINE_CHARS.length;
|
||||
final int lenBplMod = len % _HEX_ED_BPL;
|
||||
// create text buffer
|
||||
// 1. don't allocate a full last line if not _HEX_ED_BPL bytes are shown in last line
|
||||
// 2. no new line at end of buffer
|
||||
// BUG: when the length is multiple of _HEX_ED_BPL we erase the whole ascii space with this
|
||||
// char[] textData = new char[lineLength * numLines - (_HEX_ED_BPL - (len % _HEX_ED_BPL)) - _NEW_LINE_CHARS.length];
|
||||
// FIXED HERE
|
||||
int numLines;
|
||||
char[] textData;
|
||||
if (lenBplMod == 0)
|
||||
{
|
||||
numLines = len / _HEX_ED_BPL;
|
||||
textData = new char[(lineLength * numLines) - _NEW_LINE_CHARS.length];
|
||||
}
|
||||
else
|
||||
{
|
||||
numLines = (len / _HEX_ED_BPL) + 1;
|
||||
textData = new char[(lineLength * numLines) - (_HEX_ED_BPL - (lenBplMod)) - _NEW_LINE_CHARS.length];
|
||||
}
|
||||
|
||||
// performance penalty, only doing space filling in the loop is faster
|
||||
// Arrays.fill(textData, ' ');
|
||||
|
||||
int dataOffset;
|
||||
int dataLen;
|
||||
int lineStart;
|
||||
int lineHexDataStart;
|
||||
int lineAsciiDataStart;
|
||||
for (int i = 0; i < numLines; ++i)
|
||||
{
|
||||
dataOffset = i * _HEX_ED_BPL;
|
||||
dataLen = Math.min(len - dataOffset, _HEX_ED_BPL);
|
||||
lineStart = i * lineLength;
|
||||
lineHexDataStart = lineStart + 9;
|
||||
lineAsciiDataStart = lineHexDataStart + (_HEX_ED_BPL * _HEX_ED_CPB) + 1;
|
||||
|
||||
int2HexChars(dataOffset, textData, lineStart); // the offset of this line
|
||||
textData[lineHexDataStart - 1] = ' '; // separate
|
||||
bArr2HexChars(data, dataOffset, dataLen, textData, lineHexDataStart); // the data in hex
|
||||
bArr2AsciiChars(data, dataOffset, dataLen, textData, lineAsciiDataStart); // the data in ascii
|
||||
|
||||
if (i < (numLines - 1))
|
||||
{
|
||||
textData[lineAsciiDataStart - 1] = ' '; // separate
|
||||
System.arraycopy(_NEW_LINE_CHARS, 0, textData, lineAsciiDataStart + _HEX_ED_BPL, _NEW_LINE_CHARS.length); // the new line
|
||||
}
|
||||
else if (dataLen < _HEX_ED_BPL)
|
||||
{
|
||||
// last line which shows less than _HEX_ED_BPL bytes
|
||||
final int lineHexDataEnd = lineHexDataStart + (dataLen * _HEX_ED_CPB);
|
||||
Arrays.fill(textData, lineHexDataEnd, lineHexDataEnd + ((_HEX_ED_BPL - dataLen) * _HEX_ED_CPB) + 1, ' '); // spaces, for the last line if there are not _HEX_ED_BPL bytes
|
||||
}
|
||||
else
|
||||
{
|
||||
// last line which shows _HEX_ED_BPL bytes
|
||||
textData[lineAsciiDataStart - 1] = ' '; // separate
|
||||
}
|
||||
}
|
||||
return textData;
|
||||
}
|
||||
}
|
118
trunk/java/com/l2jmobius/commons/util/IGameXmlReader.java
Normal file
118
trunk/java/com/l2jmobius/commons/util/IGameXmlReader.java
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import com.l2jmobius.Config;
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.holders.MinionHolder;
|
||||
import com.l2jmobius.gameserver.model.holders.SkillHolder;
|
||||
|
||||
/**
|
||||
* Interface for XML parsers.
|
||||
* @author Zoey76
|
||||
*/
|
||||
public interface IGameXmlReader extends IXmlReader
|
||||
{
|
||||
/**
|
||||
* Wrapper for {@link #parseFile(File)} method.
|
||||
* @param path the relative path to the datapack root of the XML file to parse.
|
||||
*/
|
||||
default void parseDatapackFile(String path)
|
||||
{
|
||||
parseFile(new File(Config.DATAPACK_ROOT, path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for {@link #parseDirectory(File, boolean)}.
|
||||
* @param path the path to the directory where the XML files are
|
||||
* @param recursive parses all sub folders if there is
|
||||
* @return {@code false} if it fails to find the directory, {@code true} otherwise
|
||||
*/
|
||||
default boolean parseDatapackDirectory(String path, boolean recursive)
|
||||
{
|
||||
return parseDirectory(new File(Config.DATAPACK_ROOT, path), recursive);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param n
|
||||
* @return a map of parameters
|
||||
*/
|
||||
default Map<String, Object> parseParameters(Node n)
|
||||
{
|
||||
final Map<String, Object> parameters = new HashMap<>();
|
||||
for (Node parameters_node = n.getFirstChild(); parameters_node != null; parameters_node = parameters_node.getNextSibling())
|
||||
{
|
||||
NamedNodeMap attrs = parameters_node.getAttributes();
|
||||
switch (parameters_node.getNodeName().toLowerCase())
|
||||
{
|
||||
case "param":
|
||||
{
|
||||
parameters.put(parseString(attrs, "name"), parseString(attrs, "value"));
|
||||
break;
|
||||
}
|
||||
case "skill":
|
||||
{
|
||||
parameters.put(parseString(attrs, "name"), new SkillHolder(parseInteger(attrs, "id"), parseInteger(attrs, "level")));
|
||||
break;
|
||||
}
|
||||
case "location":
|
||||
{
|
||||
parameters.put(parseString(attrs, "name"), new Location(parseInteger(attrs, "x"), parseInteger(attrs, "y"), parseInteger(attrs, "z"), parseInteger(attrs, "heading", 0)));
|
||||
break;
|
||||
}
|
||||
case "minions":
|
||||
{
|
||||
final List<MinionHolder> minions = new ArrayList<>(1);
|
||||
for (Node minions_node = parameters_node.getFirstChild(); minions_node != null; minions_node = minions_node.getNextSibling())
|
||||
{
|
||||
if (minions_node.getNodeName().equalsIgnoreCase("npc"))
|
||||
{
|
||||
attrs = minions_node.getAttributes();
|
||||
minions.add(new MinionHolder(parseInteger(attrs, "id"), parseInteger(attrs, "count"), parseInteger(attrs, "respawnTime"), parseInteger(attrs, "weightPoint")));
|
||||
}
|
||||
}
|
||||
|
||||
if (!minions.isEmpty())
|
||||
{
|
||||
parameters.put(parseString(parameters_node.getAttributes(), "name"), minions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
default Location parseLocation(Node n)
|
||||
{
|
||||
final NamedNodeMap attrs = n.getAttributes();
|
||||
final int x = parseInteger(attrs, "x");
|
||||
final int y = parseInteger(attrs, "y");
|
||||
final int z = parseInteger(attrs, "z");
|
||||
final int heading = parseInteger(attrs, "heading", 0);
|
||||
return new Location(x, y, z, heading);
|
||||
}
|
||||
}
|
167
trunk/java/com/l2jmobius/commons/util/IPSubnet.java
Normal file
167
trunk/java/com/l2jmobius/commons/util/IPSubnet.java
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
public class IPSubnet
|
||||
{
|
||||
final byte[] _addr;
|
||||
final byte[] _mask;
|
||||
final boolean _isIPv4;
|
||||
|
||||
public IPSubnet(String input) throws UnknownHostException, NumberFormatException, ArrayIndexOutOfBoundsException
|
||||
{
|
||||
final int idx = input.indexOf("/");
|
||||
if (idx > 0)
|
||||
{
|
||||
_addr = InetAddress.getByName(input.substring(0, idx)).getAddress();
|
||||
_mask = getMask(Integer.parseInt(input.substring(idx + 1)), _addr.length);
|
||||
_isIPv4 = _addr.length == 4;
|
||||
|
||||
if (!applyMask(_addr))
|
||||
{
|
||||
throw new UnknownHostException(input);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_addr = InetAddress.getByName(input).getAddress();
|
||||
_mask = getMask(_addr.length * 8, _addr.length); // host, no need to check mask
|
||||
_isIPv4 = _addr.length == 4;
|
||||
}
|
||||
}
|
||||
|
||||
public IPSubnet(InetAddress addr, int mask) throws UnknownHostException
|
||||
{
|
||||
_addr = addr.getAddress();
|
||||
_isIPv4 = _addr.length == 4;
|
||||
_mask = getMask(mask, _addr.length);
|
||||
if (!applyMask(_addr))
|
||||
{
|
||||
throw new UnknownHostException(addr.toString() + "/" + mask);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getAddress()
|
||||
{
|
||||
return _addr;
|
||||
}
|
||||
|
||||
public boolean applyMask(byte[] addr)
|
||||
{
|
||||
// V4 vs V4 or V6 vs V6 checks
|
||||
if (_isIPv4 == (addr.length == 4))
|
||||
{
|
||||
for (int i = 0; i < _addr.length; i++)
|
||||
{
|
||||
if ((addr[i] & _mask[i]) != _addr[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// check for embedded v4 in v6 addr (not done !)
|
||||
if (_isIPv4)
|
||||
{
|
||||
// my V4 vs V6
|
||||
for (int i = 0; i < _addr.length; i++)
|
||||
{
|
||||
if ((addr[i + 12] & _mask[i]) != _addr[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// my V6 vs V4
|
||||
for (int i = 0; i < _addr.length; i++)
|
||||
{
|
||||
if ((addr[i] & _mask[i + 12]) != _addr[i + 12])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
int size = 0;
|
||||
for (byte element : _mask)
|
||||
{
|
||||
size += Integer.bitCount((element & 0xFF));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return InetAddress.getByAddress(_addr).toString() + "/" + size;
|
||||
}
|
||||
catch (UnknownHostException e)
|
||||
{
|
||||
return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (o instanceof IPSubnet)
|
||||
{
|
||||
return applyMask(((IPSubnet) o).getAddress());
|
||||
}
|
||||
else if (o instanceof InetAddress)
|
||||
{
|
||||
return applyMask(((InetAddress) o).getAddress());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final byte[] getMask(int n, int maxLength) throws UnknownHostException
|
||||
{
|
||||
if ((n > (maxLength << 3)) || (n < 0))
|
||||
{
|
||||
throw new UnknownHostException("Invalid netmask: " + n);
|
||||
}
|
||||
|
||||
final byte[] result = new byte[maxLength];
|
||||
for (int i = 0; i < maxLength; i++)
|
||||
{
|
||||
result[i] = (byte) 0xFF;
|
||||
}
|
||||
|
||||
for (int i = (maxLength << 3) - 1; i >= n; i--)
|
||||
{
|
||||
result[i >> 3] = (byte) (result[i >> 3] << 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
152
trunk/java/com/l2jmobius/commons/util/IPv4Filter.java
Normal file
152
trunk/java/com/l2jmobius/commons/util/IPv4Filter.java
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jmobius.commons.mmocore.IAcceptFilter;
|
||||
|
||||
/**
|
||||
* IPv4 filter.
|
||||
* @author Forsaiken
|
||||
*/
|
||||
public class IPv4Filter implements IAcceptFilter, Runnable
|
||||
{
|
||||
protected final Logger _log = Logger.getLogger(getClass().getName());
|
||||
|
||||
private final HashMap<Integer, Flood> _ipFloodMap;
|
||||
private static final long SLEEP_TIME = 5000;
|
||||
|
||||
public IPv4Filter()
|
||||
{
|
||||
_ipFloodMap = new HashMap<>();
|
||||
final Thread t = new Thread(this, getClass().getSimpleName());
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ip
|
||||
* @return
|
||||
*/
|
||||
private static final int hash(byte[] ip)
|
||||
{
|
||||
return (ip[0] & 0xFF) | ((ip[1] << 8) & 0xFF00) | ((ip[2] << 16) & 0xFF0000) | ((ip[3] << 24) & 0xFF000000);
|
||||
}
|
||||
|
||||
protected static final class Flood
|
||||
{
|
||||
long lastAccess;
|
||||
int trys;
|
||||
|
||||
Flood()
|
||||
{
|
||||
lastAccess = System.currentTimeMillis();
|
||||
trys = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(SocketChannel sc)
|
||||
{
|
||||
final InetAddress addr = sc.socket().getInetAddress();
|
||||
if (!(addr instanceof Inet4Address))
|
||||
{
|
||||
_log.info("Someone tried to connect from something other than IPv4: " + addr.getHostAddress());
|
||||
return false;
|
||||
}
|
||||
|
||||
final int h = hash(addr.getAddress());
|
||||
|
||||
final long current = System.currentTimeMillis();
|
||||
Flood f;
|
||||
synchronized (_ipFloodMap)
|
||||
{
|
||||
f = _ipFloodMap.get(h);
|
||||
}
|
||||
if (f != null)
|
||||
{
|
||||
if (f.trys == -1)
|
||||
{
|
||||
f.lastAccess = current;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((f.lastAccess + 1000) > current)
|
||||
{
|
||||
f.lastAccess = current;
|
||||
|
||||
if (f.trys >= 3)
|
||||
{
|
||||
f.trys = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
f.trys++;
|
||||
}
|
||||
else
|
||||
{
|
||||
f.lastAccess = current;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
synchronized (_ipFloodMap)
|
||||
{
|
||||
_ipFloodMap.put(h, new Flood());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
final long reference = System.currentTimeMillis() - (1000 * 300);
|
||||
synchronized (_ipFloodMap)
|
||||
{
|
||||
final Iterator<Entry<Integer, Flood>> it = _ipFloodMap.entrySet().iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
final Flood f = it.next().getValue();
|
||||
if (f.lastAccess < reference)
|
||||
{
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(SLEEP_TIME);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
706
trunk/java/com/l2jmobius/commons/util/IXmlReader.java
Normal file
706
trunk/java/com/l2jmobius/commons/util/IXmlReader.java
Normal file
@ -0,0 +1,706 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import com.l2jmobius.commons.util.file.filter.XMLFilter;
|
||||
|
||||
/**
|
||||
* Interface for XML parsers.
|
||||
* @author Zoey76
|
||||
*/
|
||||
public interface IXmlReader
|
||||
{
|
||||
Logger LOGGER = Logger.getLogger(IXmlReader.class.getName());
|
||||
|
||||
String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
|
||||
String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
|
||||
/** The default file filter, ".xml" files only. */
|
||||
XMLFilter XML_FILTER = new XMLFilter();
|
||||
|
||||
/**
|
||||
* This method can be used to load/reload the data.<br>
|
||||
* It's highly recommended to clear the data storage, either the list or map.
|
||||
*/
|
||||
void load();
|
||||
|
||||
/**
|
||||
* Parses a single XML file.<br>
|
||||
* If the file was successfully parsed, call {@link #parseDocument(Document, File)} for the parsed document.<br>
|
||||
* <b>Validation is enforced.</b>
|
||||
* @param f the XML file to parse.
|
||||
*/
|
||||
default void parseFile(File f)
|
||||
{
|
||||
if (!getCurrentFileFilter().accept(f))
|
||||
{
|
||||
LOGGER.warning("Could not parse " + f.getName() + " is not a file or it doesn't exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
dbf.setNamespaceAware(true);
|
||||
dbf.setValidating(isValidating());
|
||||
dbf.setIgnoringComments(isIgnoringComments());
|
||||
try
|
||||
{
|
||||
dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
|
||||
final DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
db.setErrorHandler(new XMLErrorHandler());
|
||||
parseDocument(db.parse(f), f);
|
||||
}
|
||||
catch (SAXParseException e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "Could not parse file: " + f.getName() + " at line: " + e.getLineNumber() + ", column: " + e.getColumnNumber() + " :", e);
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "Could not parse file: " + f.getName(), e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if XML validation is enabled.
|
||||
* @return {@code true} if its enabled, {@code false} otherwise
|
||||
*/
|
||||
default boolean isValidating()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if XML comments are ignored.
|
||||
* @return {@code true} if its comments are ignored, {@code false} otherwise
|
||||
*/
|
||||
default boolean isIgnoringComments()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for {@link #parseDirectory(File, boolean)}.
|
||||
* @param file the path to the directory where the XML files are.
|
||||
* @return {@code false} if it fails to find the directory, {@code true} otherwise.
|
||||
*/
|
||||
default boolean parseDirectory(File file)
|
||||
{
|
||||
return parseDirectory(file, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all XML files from {@code path} and calls {@link #parseFile(File)} for each one of them.
|
||||
* @param dir the directory object to scan.
|
||||
* @param recursive parses all sub folders if there is.
|
||||
* @return {@code false} if it fails to find the directory, {@code true} otherwise.
|
||||
*/
|
||||
default boolean parseDirectory(File dir, boolean recursive)
|
||||
{
|
||||
if (!dir.exists())
|
||||
{
|
||||
LOGGER.warning("Folder " + dir.getAbsolutePath() + " doesn't exist!");
|
||||
return false;
|
||||
}
|
||||
|
||||
final File[] listOfFiles = dir.listFiles();
|
||||
for (File f : listOfFiles)
|
||||
{
|
||||
if (recursive && f.isDirectory())
|
||||
{
|
||||
parseDirectory(f, recursive);
|
||||
}
|
||||
else if (getCurrentFileFilter().accept(f))
|
||||
{
|
||||
parseFile(f);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method that when implemented will parse the current document.<br>
|
||||
* Is expected to be call from {@link #parseFile(File)}.
|
||||
* @param doc the current document to parse
|
||||
* @param f the current file
|
||||
*/
|
||||
void parseDocument(Document doc, File f);
|
||||
|
||||
/**
|
||||
* Parses a boolean value.
|
||||
* @param node the node to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Boolean parseBoolean(Node node, Boolean defaultValue)
|
||||
{
|
||||
return node != null ? Boolean.valueOf(node.getNodeValue()) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a boolean value.
|
||||
* @param node the node to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Boolean parseBoolean(Node node)
|
||||
{
|
||||
return parseBoolean(node, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a boolean value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Boolean parseBoolean(NamedNodeMap attrs, String name)
|
||||
{
|
||||
return parseBoolean(attrs.getNamedItem(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a boolean value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Boolean parseBoolean(NamedNodeMap attrs, String name, Boolean defaultValue)
|
||||
{
|
||||
return parseBoolean(attrs.getNamedItem(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a byte value.
|
||||
* @param node the node to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Byte parseByte(Node node, Byte defaultValue)
|
||||
{
|
||||
return node != null ? Byte.decode(node.getNodeValue()) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a byte value.
|
||||
* @param node the node to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Byte parseByte(Node node)
|
||||
{
|
||||
return parseByte(node, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a byte value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Byte parseByte(NamedNodeMap attrs, String name)
|
||||
{
|
||||
return parseByte(attrs.getNamedItem(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a byte value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Byte parseByte(NamedNodeMap attrs, String name, Byte defaultValue)
|
||||
{
|
||||
return parseByte(attrs.getNamedItem(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a short value.
|
||||
* @param node the node to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Short parseShort(Node node, Short defaultValue)
|
||||
{
|
||||
return node != null ? Short.decode(node.getNodeValue()) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a short value.
|
||||
* @param node the node to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Short parseShort(Node node)
|
||||
{
|
||||
return parseShort(node, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a short value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Short parseShort(NamedNodeMap attrs, String name)
|
||||
{
|
||||
return parseShort(attrs.getNamedItem(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a short value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Short parseShort(NamedNodeMap attrs, String name, Short defaultValue)
|
||||
{
|
||||
return parseShort(attrs.getNamedItem(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an int value.
|
||||
* @param node the node to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default int parseInt(Node node, Integer defaultValue)
|
||||
{
|
||||
return node != null ? Integer.decode(node.getNodeValue()) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an int value.
|
||||
* @param node the node to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default int parseInt(Node node)
|
||||
{
|
||||
return parseInt(node, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an integer value.
|
||||
* @param node the node to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Integer parseInteger(Node node, Integer defaultValue)
|
||||
{
|
||||
return node != null ? Integer.decode(node.getNodeValue()) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an integer value.
|
||||
* @param node the node to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Integer parseInteger(Node node)
|
||||
{
|
||||
return parseInteger(node, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an integer value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Integer parseInteger(NamedNodeMap attrs, String name)
|
||||
{
|
||||
return parseInteger(attrs.getNamedItem(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an integer value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Integer parseInteger(NamedNodeMap attrs, String name, Integer defaultValue)
|
||||
{
|
||||
return parseInteger(attrs.getNamedItem(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a long value.
|
||||
* @param node the node to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Long parseLong(Node node, Long defaultValue)
|
||||
{
|
||||
return node != null ? Long.decode(node.getNodeValue()) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a long value.
|
||||
* @param node the node to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Long parseLong(Node node)
|
||||
{
|
||||
return parseLong(node, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a long value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Long parseLong(NamedNodeMap attrs, String name)
|
||||
{
|
||||
return parseLong(attrs.getNamedItem(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a long value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Long parseLong(NamedNodeMap attrs, String name, Long defaultValue)
|
||||
{
|
||||
return parseLong(attrs.getNamedItem(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a float value.
|
||||
* @param node the node to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Float parseFloat(Node node, Float defaultValue)
|
||||
{
|
||||
return node != null ? Float.valueOf(node.getNodeValue()) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a float value.
|
||||
* @param node the node to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Float parseFloat(Node node)
|
||||
{
|
||||
return parseFloat(node, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a float value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Float parseFloat(NamedNodeMap attrs, String name)
|
||||
{
|
||||
return parseFloat(attrs.getNamedItem(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a float value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Float parseFloat(NamedNodeMap attrs, String name, Float defaultValue)
|
||||
{
|
||||
return parseFloat(attrs.getNamedItem(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a double value.
|
||||
* @param node the node to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Double parseDouble(Node node, Double defaultValue)
|
||||
{
|
||||
return node != null ? Double.valueOf(node.getNodeValue()) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a double value.
|
||||
* @param node the node to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Double parseDouble(Node node)
|
||||
{
|
||||
return parseDouble(node, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a double value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default Double parseDouble(NamedNodeMap attrs, String name)
|
||||
{
|
||||
return parseDouble(attrs.getNamedItem(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a double value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default Double parseDouble(NamedNodeMap attrs, String name, Double defaultValue)
|
||||
{
|
||||
return parseDouble(attrs.getNamedItem(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string value.
|
||||
* @param node the node to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default String parseString(Node node, String defaultValue)
|
||||
{
|
||||
return node != null ? node.getNodeValue() : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string value.
|
||||
* @param node the node to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default String parseString(Node node)
|
||||
{
|
||||
return parseString(node, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @return if the node is not null, the value of the parsed node, otherwise null
|
||||
*/
|
||||
default String parseString(NamedNodeMap attrs, String name)
|
||||
{
|
||||
return parseString(attrs.getNamedItem(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string value.
|
||||
* @param attrs the attributes
|
||||
* @param name the name of the attribute to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null, the value of the parsed node, otherwise the default value
|
||||
*/
|
||||
default String parseString(NamedNodeMap attrs, String name, String defaultValue)
|
||||
{
|
||||
return parseString(attrs.getNamedItem(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an enumerated value.
|
||||
* @param <T> the enumerated type
|
||||
* @param node the node to parse
|
||||
* @param clazz the class of the enumerated
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null and the node value is valid the parsed value, otherwise the default value
|
||||
*/
|
||||
default <T extends Enum<T>> T parseEnum(Node node, Class<T> clazz, T defaultValue)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Enum.valueOf(clazz, node.getNodeValue());
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
LOGGER.warning("Invalid value specified for node: " + node.getNodeName() + " specified value: " + node.getNodeValue() + " should be enum value of \"" + clazz.getSimpleName() + "\" using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an enumerated value.
|
||||
* @param <T> the enumerated type
|
||||
* @param node the node to parse
|
||||
* @param clazz the class of the enumerated
|
||||
* @return if the node is not null and the node value is valid the parsed value, otherwise null
|
||||
*/
|
||||
default <T extends Enum<T>> T parseEnum(Node node, Class<T> clazz)
|
||||
{
|
||||
return parseEnum(node, clazz, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an enumerated value.
|
||||
* @param <T> the enumerated type
|
||||
* @param attrs the attributes
|
||||
* @param clazz the class of the enumerated
|
||||
* @param name the name of the attribute to parse
|
||||
* @return if the node is not null and the node value is valid the parsed value, otherwise null
|
||||
*/
|
||||
default <T extends Enum<T>> T parseEnum(NamedNodeMap attrs, Class<T> clazz, String name)
|
||||
{
|
||||
return parseEnum(attrs.getNamedItem(name), clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an enumerated value.
|
||||
* @param <T> the enumerated type
|
||||
* @param attrs the attributes
|
||||
* @param clazz the class of the enumerated
|
||||
* @param name the name of the attribute to parse
|
||||
* @param defaultValue the default value
|
||||
* @return if the node is not null and the node value is valid the parsed value, otherwise the default value
|
||||
*/
|
||||
default <T extends Enum<T>> T parseEnum(NamedNodeMap attrs, Class<T> clazz, String name, T defaultValue)
|
||||
{
|
||||
return parseEnum(attrs.getNamedItem(name), clazz, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node
|
||||
* @return parses all attributes to a Map
|
||||
*/
|
||||
default Map<String, Object> parseAttributes(Node node)
|
||||
{
|
||||
final NamedNodeMap attrs = node.getAttributes();
|
||||
final Map<String, Object> map = new LinkedHashMap<>();
|
||||
for (int i = 0; i < attrs.getLength(); i++)
|
||||
{
|
||||
final Node att = attrs.item(i);
|
||||
map.put(att.getNodeName(), att.getNodeValue());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes action for each child of node
|
||||
* @param node
|
||||
* @param action
|
||||
*/
|
||||
default void forEach(Node node, Consumer<Node> action)
|
||||
{
|
||||
forEach(node, a -> true, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes action for each child that matches nodeName
|
||||
* @param node
|
||||
* @param nodeName
|
||||
* @param action
|
||||
*/
|
||||
default void forEach(Node node, String nodeName, Consumer<Node> action)
|
||||
{
|
||||
forEach(node, innerNode -> nodeName.equalsIgnoreCase(innerNode.getNodeName()), action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes action for each child of node if matches the filter specified
|
||||
* @param node
|
||||
* @param filter
|
||||
* @param action
|
||||
*/
|
||||
default void forEach(Node node, Predicate<Node> filter, Consumer<Node> action)
|
||||
{
|
||||
final NodeList list = node.getChildNodes();
|
||||
for (int i = 0; i < list.getLength(); i++)
|
||||
{
|
||||
final Node targetNode = list.item(i);
|
||||
if (filter.test(targetNode))
|
||||
{
|
||||
action.accept(targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node
|
||||
* @return {@code true} if the node is an element type, {@code false} otherwise
|
||||
*/
|
||||
public static boolean isNode(Node node)
|
||||
{
|
||||
return node.getNodeType() == Node.ELEMENT_NODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node
|
||||
* @return {@code true} if the node is an element type, {@code false} otherwise
|
||||
*/
|
||||
public static boolean isText(Node node)
|
||||
{
|
||||
return node.getNodeType() == Node.TEXT_NODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current file filter.
|
||||
* @return the current file filter
|
||||
*/
|
||||
default FileFilter getCurrentFileFilter()
|
||||
{
|
||||
return XML_FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple XML error handler.
|
||||
* @author Zoey76
|
||||
*/
|
||||
class XMLErrorHandler implements ErrorHandler
|
||||
{
|
||||
@Override
|
||||
public void warning(SAXParseException e) throws SAXParseException
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(SAXParseException e) throws SAXParseException
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatalError(SAXParseException e) throws SAXParseException
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
83
trunk/java/com/l2jmobius/commons/util/MathUtil.java
Normal file
83
trunk/java/com/l2jmobius/commons/util/MathUtil.java
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class MathUtil
|
||||
{
|
||||
public static byte add(byte oldValue, byte value)
|
||||
{
|
||||
return (byte) (oldValue + value);
|
||||
}
|
||||
|
||||
public static short add(short oldValue, short value)
|
||||
{
|
||||
return (short) (oldValue + value);
|
||||
}
|
||||
|
||||
public static int add(int oldValue, int value)
|
||||
{
|
||||
return oldValue + value;
|
||||
}
|
||||
|
||||
public static double add(double oldValue, double value)
|
||||
{
|
||||
return oldValue + value;
|
||||
}
|
||||
|
||||
public static byte mul(byte oldValue, byte value)
|
||||
{
|
||||
return (byte) (oldValue * value);
|
||||
}
|
||||
|
||||
public static short mul(short oldValue, short value)
|
||||
{
|
||||
return (short) (oldValue * value);
|
||||
}
|
||||
|
||||
public static int mul(int oldValue, int value)
|
||||
{
|
||||
return oldValue * value;
|
||||
}
|
||||
|
||||
public static double mul(double oldValue, double value)
|
||||
{
|
||||
return oldValue * value;
|
||||
}
|
||||
|
||||
public static byte div(byte oldValue, byte value)
|
||||
{
|
||||
return (byte) (oldValue / value);
|
||||
}
|
||||
|
||||
public static short div(short oldValue, short value)
|
||||
{
|
||||
return (short) (oldValue / value);
|
||||
}
|
||||
|
||||
public static int div(int oldValue, int value)
|
||||
{
|
||||
return oldValue / value;
|
||||
}
|
||||
|
||||
public static double div(double oldValue, double value)
|
||||
{
|
||||
return oldValue / value;
|
||||
}
|
||||
}
|
381
trunk/java/com/l2jmobius/commons/util/PropertiesParser.java
Normal file
381
trunk/java/com/l2jmobius/commons/util/PropertiesParser.java
Normal file
@ -0,0 +1,381 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Simplifies loading of property files and adds logging if a non existing property is requested.
|
||||
* @author NosBit
|
||||
*/
|
||||
public final class PropertiesParser
|
||||
{
|
||||
private static final Logger LOGGER = Logger.getLogger(PropertiesParser.class.getName());
|
||||
|
||||
private final Properties _properties = new Properties();
|
||||
private final File _file;
|
||||
|
||||
public PropertiesParser(String name)
|
||||
{
|
||||
this(new File(name));
|
||||
}
|
||||
|
||||
public PropertiesParser(File file)
|
||||
{
|
||||
_file = file;
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file))
|
||||
{
|
||||
try (InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, Charset.defaultCharset()))
|
||||
{
|
||||
_properties.load(inputStreamReader);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] There was an error loading config reason: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containskey(String key)
|
||||
{
|
||||
return _properties.containsKey(key);
|
||||
}
|
||||
|
||||
private String getValue(String key)
|
||||
{
|
||||
final String value = _properties.getProperty(key);
|
||||
return value != null ? value.trim() : null;
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key, boolean defaultValue)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (value.equalsIgnoreCase("true"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (value.equalsIgnoreCase("false"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] Invalid value specified for key: " + key + " specified value: " + value + " should be \"boolean\" using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public byte getByte(String key, byte defaultValue)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Byte.parseByte(value);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] Invalid value specified for key: " + key + " specified value: " + value + " should be \"byte\" using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public short getShort(String key, short defaultValue)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Short.parseShort(value);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] Invalid value specified for key: " + key + " specified value: " + value + " should be \"short\" using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public int getInt(String key, int defaultValue)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] Invalid value specified for key: " + key + " specified value: " + value + " should be \"int\" using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public long getLong(String key, long defaultValue)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] Invalid value specified for key: " + key + " specified value: " + value + " should be \"long\" using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public float getFloat(String key, float defaultValue)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Float.parseFloat(value);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] Invalid value specified for key: " + key + " specified value: " + value + " should be \"float\" using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public double getDouble(String key, double defaultValue)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Double.parseDouble(value);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] Invalid value specified for key: " + key + " specified value: " + value + " should be \"double\" using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public String getString(String key, String defaultValue)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public <T extends Enum<T>> T getEnum(String key, Class<T> clazz, T defaultValue)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Enum.valueOf(clazz, value);
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] Invalid value specified for key: " + key + " specified value: " + value + " should be enum value of \"" + clazz.getSimpleName() + "\" using default value: " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param durationPattern
|
||||
* @param defaultValue
|
||||
* @return {@link Duration} object by the durationPattern specified, {@code null} in case of malformed pattern.
|
||||
*/
|
||||
public Duration getDuration(String durationPattern, String defaultValue)
|
||||
{
|
||||
return getDuration(durationPattern, defaultValue, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param durationPattern
|
||||
* @param defaultValue
|
||||
* @param defaultDuration
|
||||
* @return {@link Duration} object by the durationPattern specified, the defaultDuration in case of malformed pattern.
|
||||
*/
|
||||
public Duration getDuration(String durationPattern, String defaultValue, Duration defaultDuration)
|
||||
{
|
||||
final String value = getString(durationPattern, defaultValue);
|
||||
try
|
||||
{
|
||||
return TimeUtil.parseDuration(value);
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] Invalid value specified for key: " + durationPattern + " specified value: " + value + " should be time patttern using default value: " + defaultValue);
|
||||
}
|
||||
return defaultDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @param separator
|
||||
* @param defaultValues
|
||||
* @return int array
|
||||
*/
|
||||
public int[] getIntArray(String key, String separator, int... defaultValues)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValues);
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
final String[] data = value.trim().split(separator);
|
||||
final int[] result = new int[data.length];
|
||||
for (int i = 0; i < data.length; i++)
|
||||
{
|
||||
result[i] = Integer.decode(data[i].trim());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warning("[+_file.getName()+] Invalid value specified for key: " + key + " specified value: " + value + " should be array using default value: " + defaultValues);
|
||||
return defaultValues;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @param key
|
||||
* @param separator
|
||||
* @param clazz
|
||||
* @param defaultValues
|
||||
* @return enum array
|
||||
*/
|
||||
@SafeVarargs
|
||||
public final <T extends Enum<T>> T[] getEnumArray(String key, String separator, Class<T> clazz, T... defaultValues)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValues);
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
final String[] data = value.trim().split(separator);
|
||||
@SuppressWarnings("unchecked")
|
||||
final T[] result = (T[]) Array.newInstance(clazz, data.length);
|
||||
for (int i = 0; i < data.length; i++)
|
||||
{
|
||||
result[i] = Enum.valueOf(clazz, data[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] Invalid value specified for key: " + key + " specified value: " + value + " should be array using default value: " + defaultValues);
|
||||
return defaultValues;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @param key
|
||||
* @param separator
|
||||
* @param clazz
|
||||
* @param defaultValues
|
||||
* @return list
|
||||
*/
|
||||
@SafeVarargs
|
||||
public final <T extends Enum<T>> List<T> getEnumList(String key, String separator, Class<T> clazz, T... defaultValues)
|
||||
{
|
||||
final String value = getValue(key);
|
||||
if (value == null)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] missing property for key: " + key + " using default value: " + defaultValues);
|
||||
return Arrays.asList(defaultValues);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
final String[] data = value.trim().split(separator);
|
||||
final List<T> result = new ArrayList<>(data.length);
|
||||
for (String element : data)
|
||||
{
|
||||
result.add(Enum.valueOf(clazz, element));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warning("[" + _file.getName() + "] Invalid value specified for key: " + key + " specified value: " + value + " should be array using default value: " + defaultValues);
|
||||
return Arrays.asList(defaultValues);
|
||||
}
|
||||
}
|
||||
}
|
452
trunk/java/com/l2jmobius/commons/util/Rnd.java
Normal file
452
trunk/java/com/l2jmobius/commons/util/Rnd.java
Normal file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @author Forsaiken
|
||||
*/
|
||||
public final class Rnd
|
||||
{
|
||||
/**
|
||||
* This class extends {@link java.util.Random} but do not compare and store atomically.<br>
|
||||
* Instead it`s using a simple volatile flag to ensure reading and storing the whole 64bit seed chunk.<br>
|
||||
* This implementation is much faster on parallel access, but may generate the same seed for 2 threads.
|
||||
* @author Forsaiken
|
||||
* @see java.util.Random
|
||||
*/
|
||||
public static final class NonAtomicRandom extends Random
|
||||
{
|
||||
private volatile long _seed;
|
||||
|
||||
public NonAtomicRandom()
|
||||
{
|
||||
this(++SEED_UNIQUIFIER + System.nanoTime());
|
||||
}
|
||||
|
||||
public NonAtomicRandom(long seed)
|
||||
{
|
||||
setSeed(seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int next(int bits)
|
||||
{
|
||||
return (int) ((_seed = ((_seed * MULTIPLIER) + ADDEND) & MASK) >>> (48 - bits));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setSeed(long seed)
|
||||
{
|
||||
_seed = (seed ^ MULTIPLIER) & MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Forsaiken
|
||||
*/
|
||||
protected static final class RandomContainer
|
||||
{
|
||||
private final Random _random;
|
||||
|
||||
protected RandomContainer(Random random)
|
||||
{
|
||||
_random = random;
|
||||
}
|
||||
|
||||
public final Random directRandom()
|
||||
{
|
||||
return _random;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random double number from 0 to 1
|
||||
* @return A random double number from 0 to 1
|
||||
* @see com.l2jmobius.commons.util.Rnd#nextDouble()
|
||||
*/
|
||||
public final double get()
|
||||
{
|
||||
return _random.nextDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random integer number from 0(inclusive) to n(exclusive)
|
||||
* @param n The superior limit (exclusive)
|
||||
* @return A random integer number from 0 to n-1
|
||||
*/
|
||||
public final int get(int n)
|
||||
{
|
||||
return (int) (_random.nextDouble() * n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random integer number from min(inclusive) to max(inclusive)
|
||||
* @param min The minimum value
|
||||
* @param max The maximum value
|
||||
* @return A random integer number from min to max
|
||||
*/
|
||||
public final int get(int min, int max)
|
||||
{
|
||||
return min + (int) (_random.nextDouble() * ((max - min) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random long number from min(inclusive) to max(inclusive)
|
||||
* @param min The minimum value
|
||||
* @param max The maximum value
|
||||
* @return A random long number from min to max
|
||||
*/
|
||||
public final long get(long min, long max)
|
||||
{
|
||||
return min + (long) (_random.nextDouble() * ((max - min) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random boolean state (true or false)
|
||||
* @return A random boolean state (true or false)
|
||||
* @see java.util.Random#nextBoolean()
|
||||
*/
|
||||
public final boolean nextBoolean()
|
||||
{
|
||||
return _random.nextBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the given array with random byte numbers from Byte.MIN_VALUE(inclusive) to Byte.MAX_VALUE(inclusive)
|
||||
* @param array The array to be filled with random byte numbers
|
||||
* @see java.util.Random#nextBytes(byte[] bytes)
|
||||
*/
|
||||
public final void nextBytes(byte[] array)
|
||||
{
|
||||
_random.nextBytes(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random double number from 0 to 1
|
||||
* @return A random double number from 0 to 1
|
||||
* @see java.util.Random#nextDouble()
|
||||
*/
|
||||
public final double nextDouble()
|
||||
{
|
||||
return _random.nextDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random float number from 0 to 1
|
||||
* @return A random integer number from 0 to 1
|
||||
* @see java.util.Random#nextFloat()
|
||||
*/
|
||||
public final float nextFloat()
|
||||
{
|
||||
return _random.nextFloat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random gaussian double number from 0 to 1
|
||||
* @return A random gaussian double number from 0 to 1
|
||||
* @see java.util.Random#nextGaussian()
|
||||
*/
|
||||
public final double nextGaussian()
|
||||
{
|
||||
return _random.nextGaussian();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random integer number from Integer.MIN_VALUE(inclusive) to Integer.MAX_VALUE(inclusive)
|
||||
* @return A random integer number from Integer.MIN_VALUE to Integer.MAX_VALUE
|
||||
* @see java.util.Random#nextInt()
|
||||
*/
|
||||
public final int nextInt()
|
||||
{
|
||||
return _random.nextInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random long number from Long.MIN_VALUE(inclusive) to Long.MAX_VALUE(inclusive)
|
||||
* @return A random integer number from Long.MIN_VALUE to Long.MAX_VALUE
|
||||
* @see java.util.Random#nextLong()
|
||||
*/
|
||||
public final long nextLong()
|
||||
{
|
||||
return _random.nextLong();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Forsaiken
|
||||
*/
|
||||
public static enum RandomType
|
||||
{
|
||||
/**
|
||||
* For best random quality.
|
||||
* @see java.security.SecureRandom
|
||||
*/
|
||||
SECURE,
|
||||
|
||||
/**
|
||||
* For average random quality.
|
||||
* @see java.util.Random
|
||||
*/
|
||||
UNSECURE_ATOMIC,
|
||||
|
||||
/**
|
||||
* Like {@link com.l2jmobius.commons.util.Rnd.RandomType#UNSECURE_ATOMIC}.<br>
|
||||
* Each thread has it`s own random instance.<br>
|
||||
* Provides best parallel access speed.
|
||||
* @see com.l2jmobius.commons.util.Rnd.ThreadLocalRandom
|
||||
*/
|
||||
UNSECURE_THREAD_LOCAL,
|
||||
|
||||
/**
|
||||
* Like {@link com.l2jmobius.commons.util.Rnd.RandomType#UNSECURE_ATOMIC}.<br>
|
||||
* Provides much faster parallel access speed.
|
||||
* @see com.l2jmobius.commons.util.Rnd.NonAtomicRandom
|
||||
*/
|
||||
UNSECURE_VOLATILE
|
||||
}
|
||||
|
||||
/**
|
||||
* This class extends {@link java.util.Random} but do not compare and store atomically.<br>
|
||||
* Instead it`s using thread local ensure reading and storing the whole 64bit seed chunk.<br>
|
||||
* This implementation is the fastest, never generates the same seed for 2 threads.<br>
|
||||
* Each thread has it`s own random instance.
|
||||
* @author Forsaiken
|
||||
* @see java.util.Random
|
||||
*/
|
||||
public static final class ThreadLocalRandom extends Random
|
||||
{
|
||||
private static final class Seed
|
||||
{
|
||||
long _seed;
|
||||
|
||||
Seed(long seed)
|
||||
{
|
||||
setSeed(seed);
|
||||
}
|
||||
|
||||
final int next(int bits)
|
||||
{
|
||||
return (int) ((_seed = ((_seed * MULTIPLIER) + ADDEND) & MASK) >>> (48 - bits));
|
||||
}
|
||||
|
||||
final void setSeed(long seed)
|
||||
{
|
||||
_seed = (seed ^ MULTIPLIER) & MASK;
|
||||
}
|
||||
}
|
||||
|
||||
private final ThreadLocal<Seed> _seedLocal;
|
||||
|
||||
public ThreadLocalRandom()
|
||||
{
|
||||
_seedLocal = new ThreadLocal<Seed>()
|
||||
{
|
||||
@Override
|
||||
public final Seed initialValue()
|
||||
{
|
||||
return new Seed(++SEED_UNIQUIFIER + System.nanoTime());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public ThreadLocalRandom(long seed)
|
||||
{
|
||||
_seedLocal = new ThreadLocal<Seed>()
|
||||
{
|
||||
@Override
|
||||
public final Seed initialValue()
|
||||
{
|
||||
return new Seed(seed);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int next(int bits)
|
||||
{
|
||||
return _seedLocal.get().next(bits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setSeed(long seed)
|
||||
{
|
||||
if (_seedLocal != null)
|
||||
{
|
||||
_seedLocal.get().setSeed(seed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final long ADDEND = 0xBL;
|
||||
|
||||
private static final long MASK = (1L << 48) - 1;
|
||||
|
||||
private static final long MULTIPLIER = 0x5DEECE66DL;
|
||||
|
||||
private static final RandomContainer rnd = newInstance(RandomType.UNSECURE_THREAD_LOCAL);
|
||||
|
||||
protected static volatile long SEED_UNIQUIFIER = 8682522807148012L;
|
||||
|
||||
public static final Random directRandom()
|
||||
{
|
||||
return rnd.directRandom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random double number from 0 to 1
|
||||
* @return A random double number from 0 to 1
|
||||
* @see com.l2jmobius.commons.util.Rnd#nextDouble()
|
||||
*/
|
||||
public static final double get()
|
||||
{
|
||||
return rnd.nextDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random integer number from 0(inclusive) to n(exclusive)
|
||||
* @param n The superior limit (exclusive)
|
||||
* @return A random integer number from 0 to n-1
|
||||
*/
|
||||
public static final int get(int n)
|
||||
{
|
||||
return rnd.get(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random integer number from min(inclusive) to max(inclusive)
|
||||
* @param min The minimum value
|
||||
* @param max The maximum value
|
||||
* @return A random integer number from min to max
|
||||
*/
|
||||
public static final int get(int min, int max)
|
||||
{
|
||||
return rnd.get(min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random long number from min(inclusive) to max(inclusive)
|
||||
* @param min The minimum value
|
||||
* @param max The maximum value
|
||||
* @return A random long number from min to max
|
||||
*/
|
||||
public static final long get(long min, long max)
|
||||
{
|
||||
return rnd.get(min, max);
|
||||
}
|
||||
|
||||
public static final RandomContainer newInstance(RandomType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case UNSECURE_ATOMIC:
|
||||
return new RandomContainer(new Random());
|
||||
|
||||
case UNSECURE_VOLATILE:
|
||||
return new RandomContainer(new NonAtomicRandom());
|
||||
|
||||
case UNSECURE_THREAD_LOCAL:
|
||||
return new RandomContainer(new ThreadLocalRandom());
|
||||
|
||||
case SECURE:
|
||||
return new RandomContainer(new SecureRandom());
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random boolean state (true or false)
|
||||
* @return A random boolean state (true or false)
|
||||
* @see java.util.Random#nextBoolean()
|
||||
*/
|
||||
public static final boolean nextBoolean()
|
||||
{
|
||||
return rnd.nextBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the given array with random byte numbers from Byte.MIN_VALUE(inclusive) to Byte.MAX_VALUE(inclusive)
|
||||
* @param array The array to be filled with random byte numbers
|
||||
* @see java.util.Random#nextBytes(byte[] bytes)
|
||||
*/
|
||||
public static final void nextBytes(byte[] array)
|
||||
{
|
||||
rnd.nextBytes(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random double number from 0 to 1
|
||||
* @return A random double number from 0 to 1
|
||||
* @see java.util.Random#nextDouble()
|
||||
*/
|
||||
public static final double nextDouble()
|
||||
{
|
||||
return rnd.nextDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random float number from 0 to 1
|
||||
* @return A random integer number from 0 to 1
|
||||
* @see java.util.Random#nextFloat()
|
||||
*/
|
||||
public static final float nextFloat()
|
||||
{
|
||||
return rnd.nextFloat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random gaussian double number from 0 to 1
|
||||
* @return A random gaussian double number from 0 to 1
|
||||
* @see java.util.Random#nextGaussian()
|
||||
*/
|
||||
public static final double nextGaussian()
|
||||
{
|
||||
return rnd.nextGaussian();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random integer number from Integer.MIN_VALUE(inclusive) to Integer.MAX_VALUE(inclusive)
|
||||
* @return A random integer number from Integer.MIN_VALUE to Integer.MAX_VALUE
|
||||
* @see java.util.Random#nextInt()
|
||||
*/
|
||||
public static final int nextInt()
|
||||
{
|
||||
return rnd.nextInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param n
|
||||
* @return int
|
||||
* @see com.l2jmobius.commons.util.Rnd#get(int n)
|
||||
*/
|
||||
public static final int nextInt(int n)
|
||||
{
|
||||
return get(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random long number from Long.MIN_VALUE(inclusive) to Long.MAX_VALUE(inclusive)
|
||||
* @return A random integer number from Long.MIN_VALUE to Long.MAX_VALUE
|
||||
* @see java.util.Random#nextLong()
|
||||
*/
|
||||
public static final long nextLong()
|
||||
{
|
||||
return rnd.nextLong();
|
||||
}
|
||||
}
|
276
trunk/java/com/l2jmobius/commons/util/StringUtil.java
Normal file
276
trunk/java/com/l2jmobius/commons/util/StringUtil.java
Normal file
@ -0,0 +1,276 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import com.l2jmobius.Config;
|
||||
|
||||
/**
|
||||
* String utilities optimized for the best performance.<br>
|
||||
* <h1>How to Use It</h1>
|
||||
* <h2>concat() or append()</h2> If concatenating strings<br>
|
||||
* in single call, use StringUtil.concat(), otherwise use StringUtil.append()<br>
|
||||
* and its variants.<br>
|
||||
* <br>
|
||||
* <h2>Minimum Calls</h2><br>
|
||||
* Bad:
|
||||
*
|
||||
* <pre>
|
||||
* final StringBuilder sbString = new StringBuilder();
|
||||
* StringUtil.append(sbString, "text 1", String.valueOf(npcId));
|
||||
* StringUtil.append("text 2");
|
||||
* </pre>
|
||||
*
|
||||
* Good:
|
||||
*
|
||||
* <pre>
|
||||
* final StringBuilder sbString = new StringBuilder();
|
||||
* StringUtil.append(sbString, "text 1", String.valueOf(npcId), "text 2");
|
||||
* </pre>
|
||||
*
|
||||
* Why?<br/>
|
||||
* Because the less calls you do, the less memory re-allocations have to be done<br>
|
||||
* so the whole text fits into the memory and less array copy tasks has to be<br>
|
||||
* performed. So if using less calls, less memory is used and string concatenation is faster.<br>
|
||||
* <br>
|
||||
* <h2>Size Hints for Loops</h2><br>
|
||||
* Bad:
|
||||
*
|
||||
* <pre>
|
||||
* final StringBuilder sbString = new StringBuilder();
|
||||
* StringUtil.append(sbString, "header start", someText, "header end");
|
||||
* for (int i = 0; i < 50; i++)
|
||||
* {
|
||||
* StringUtil.append(sbString, "text 1", stringArray[i], "text 2");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Good:
|
||||
*
|
||||
* <pre>
|
||||
* final StringBuilder sbString = StringUtil.startAppend(1300, "header start", someText, "header end");
|
||||
* for (int i = 0; i < 50; i++)
|
||||
* {
|
||||
* StringUtil.append(sbString, "text 1", stringArray[i], "text 2");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Why?<br/>
|
||||
* When using StringUtil.append(), memory is only allocated to fit in the strings in method argument. So on each loop new memory for the string has to be allocated and old string has to be copied to the new string. With size hint, even if the size hint is above the needed memory, memory is saved
|
||||
* because new memory has not to be allocated on each cycle. Also it is much faster if no string copy tasks has to be performed. So if concatenating strings in a loop, count approximately the size and set it as the hint for the string builder size. It's better to make the size hint little bit larger
|
||||
* rather than smaller.<br/>
|
||||
* In case there is no text appended before the cycle, just use <code>new
|
||||
* StringBuilder(1300)</code>.<br>
|
||||
* <br>
|
||||
* <h2>Concatenation and Constants</h2><br>
|
||||
* Bad:
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.concat("text 1 ", "text 2", String.valueOf(npcId));
|
||||
* </pre>
|
||||
*
|
||||
* Good:
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.concat("text 1 " + "text 2", String.valueOf(npcId));
|
||||
* </pre>
|
||||
*
|
||||
* or
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.concat("text 1 text 2", String.valueOf(npcId));
|
||||
* </pre>
|
||||
*
|
||||
* Why?<br/>
|
||||
* It saves some cycles when determining size of memory that needs to be allocated because less strings are passed to concat() method. But do not use + for concatenation of non-constant strings, that degrades performance and makes extra memory allocations needed.<br>
|
||||
* <h2>Concatenation and Constant Variables</h2> Bad:
|
||||
*
|
||||
* <pre>
|
||||
* String glue = "some glue";
|
||||
* StringUtil.concat("text 1", glue, "text 2", glue, String.valueOf(npcId));
|
||||
* </pre>
|
||||
*
|
||||
* Good:
|
||||
*
|
||||
* <pre>
|
||||
* final String glue = "some glue";
|
||||
* StringUtil.concat("text 1" + glue + "text2" + glue, String.valueOf(npcId));
|
||||
* </pre>
|
||||
*
|
||||
* Why? Because when using <code>final</code> keyword, the <code>glue</code> is marked as constant string and compiler treats it as a constant string so it is able to create string "text1some gluetext2some glue" during the compilation. But this only works in case the value is known at compilation
|
||||
* time, so this cannot be used for cases like <code>final String objectIdString =
|
||||
* String.valueOf(getObjectId)</code>.<br>
|
||||
* <br>
|
||||
* <h2>StringBuilder Reuse</h2><br>
|
||||
* Bad:
|
||||
*
|
||||
* <pre>
|
||||
* final StringBuilder sbString1 = new StringBuilder();
|
||||
* StringUtil.append(sbString1, "text 1", String.valueOf(npcId), "text 2");
|
||||
* ... // output of sbString1, it is no more needed
|
||||
* final StringBuilder sbString2 = new StringBuilder();
|
||||
* StringUtil.append(sbString2, "text 3", String.valueOf(npcId), "text 4");
|
||||
* </pre>
|
||||
*
|
||||
* Good:
|
||||
*
|
||||
* <pre>
|
||||
* final StringBuilder sbString = new StringBuilder();
|
||||
* StringUtil.append(sbString, "text 1", String.valueOf(npcId), "text 2");
|
||||
* ... // output of sbString, it is no more needed
|
||||
* sbString.setLength(0);
|
||||
* StringUtil.append(sbString, "text 3", String.valueOf(npcId), "text 4");
|
||||
* </pre>
|
||||
*
|
||||
* Why?</br>
|
||||
* In first case, new memory has to be allocated for the second string. In second case already allocated memory is reused, but only in case the new string is not longer than the previously allocated string. Anyway, the second way is better because the string either fits in the memory and some memory
|
||||
* is saved, or it does not fit in the memory, and in that case it works as in the first case.
|
||||
* <h2>Primitives to Strings</h2> To convert primitives to string, use String.valueOf().<br>
|
||||
* <br>
|
||||
* <h2>How much faster is it?</h2><br>
|
||||
* Here are some results of my tests. Count is number of strings concatenated. Don't take the numbers as 100% true as the numbers are affected by other programs running on my computer at the same time. Anyway, from the results it is obvious that using StringBuilder with predefined size is the
|
||||
* fastest (and also most memory efficient) solution. It is about 5 times faster when concatenating 7 strings, compared to TextBuilder. Also, with more strings concatenated, the difference between StringBuilder and TextBuilder gets larger. In code, there are many cases, where there are concatenated
|
||||
* 50+ strings so the time saving is even greater.<br>
|
||||
*
|
||||
* <pre>
|
||||
* Count: 2
|
||||
* TextBuilder: 1893
|
||||
* TextBuilder with size: 1703
|
||||
* String: 1033
|
||||
* StringBuilder: 993
|
||||
* StringBuilder with size: 1024
|
||||
* Count: 3
|
||||
* TextBuilder: 1973
|
||||
* TextBuilder with size: 1872
|
||||
* String: 2583
|
||||
* StringBuilder: 1633
|
||||
* StringBuilder with size: 1156
|
||||
* Count: 4
|
||||
* TextBuilder: 2188
|
||||
* TextBuilder with size: 2229
|
||||
* String: 4207
|
||||
* StringBuilder: 1816
|
||||
* StringBuilder with size: 1444
|
||||
* Count: 5
|
||||
* TextBuilder: 9185
|
||||
* TextBuilder with size: 9464
|
||||
* String: 6937
|
||||
* StringBuilder: 2745
|
||||
* StringBuilder with size: 1882
|
||||
* Count: 6
|
||||
* TextBuilder: 9785
|
||||
* TextBuilder with size: 10082
|
||||
* String: 9471
|
||||
* StringBuilder: 2889
|
||||
* StringBuilder with size: 1857
|
||||
* Count: 7
|
||||
* TextBuilder: 10169
|
||||
* TextBuilder with size: 10528
|
||||
* String: 12746
|
||||
* StringBuilder: 3081
|
||||
* StringBuilder with size: 2139
|
||||
* </pre>
|
||||
*
|
||||
* @author fordfrog
|
||||
*/
|
||||
public final class StringUtil
|
||||
{
|
||||
private StringUtil()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates strings.
|
||||
* @param strings strings to be concatenated
|
||||
* @return concatenated string
|
||||
*/
|
||||
public static String concat(String... strings)
|
||||
{
|
||||
final StringBuilder sbString = new StringBuilder();
|
||||
for (String string : strings)
|
||||
{
|
||||
sbString.append(string);
|
||||
}
|
||||
return sbString.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new string builder with size initializated to <code>sizeHint</code>, unless total length of strings is greater than <code>sizeHint</code>.
|
||||
* @param sizeHint hint for string builder size allocation
|
||||
* @param strings strings to be appended
|
||||
* @return created string builder
|
||||
*/
|
||||
public static StringBuilder startAppend(int sizeHint, String... strings)
|
||||
{
|
||||
final int length = getLength(strings);
|
||||
final StringBuilder sbString = new StringBuilder(sizeHint > length ? sizeHint : length);
|
||||
for (String string : strings)
|
||||
{
|
||||
sbString.append(string);
|
||||
}
|
||||
return sbString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends strings to existing string builder.
|
||||
* @param sbString string builder
|
||||
* @param strings strings to be appended
|
||||
*/
|
||||
public static void append(StringBuilder sbString, String... strings)
|
||||
{
|
||||
sbString.ensureCapacity(sbString.length() + getLength(strings));
|
||||
|
||||
for (String string : strings)
|
||||
{
|
||||
sbString.append(string);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getLength(Iterable<String> strings)
|
||||
{
|
||||
int length = 0;
|
||||
for (String string : strings)
|
||||
{
|
||||
length += (string == null) ? 4 : string.length();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts total length of all the strings.
|
||||
* @param strings array of strings
|
||||
* @return total length of all the strings
|
||||
*/
|
||||
public static int getLength(String[] strings)
|
||||
{
|
||||
int length = 0;
|
||||
for (String string : strings)
|
||||
{
|
||||
length += (string == null) ? 4 : string.length();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
public static String getTraceString(StackTraceElement[] trace)
|
||||
{
|
||||
final StringBuilder sbString = new StringBuilder();
|
||||
for (StackTraceElement element : trace)
|
||||
{
|
||||
sbString.append(element.toString()).append(Config.EOL);
|
||||
}
|
||||
return sbString.toString();
|
||||
}
|
||||
}
|
125
trunk/java/com/l2jmobius/commons/util/TimeUtil.java
Normal file
125
trunk/java/com/l2jmobius/commons/util/TimeUtil.java
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class TimeUtil
|
||||
{
|
||||
public static int findIndexOfNonDigit(CharSequence text)
|
||||
{
|
||||
for (int i = 0; i < text.length(); i++)
|
||||
{
|
||||
if (Character.isDigit(text.charAt(i)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses patterns like:
|
||||
* <ul>
|
||||
* <li>1min or 10mins</li>
|
||||
* <li>1day or 10days</li>
|
||||
* <li>1week or 4weeks</li>
|
||||
* <li>1month or 12months</li>
|
||||
* <li>1year or 5years</li>
|
||||
* </ul>
|
||||
* @param datePattern
|
||||
* @return {@link Duration} object converted by the date pattern specified.
|
||||
* @throws IllegalStateException when malformed pattern specified.
|
||||
*/
|
||||
public static Duration parseDuration(String datePattern)
|
||||
{
|
||||
final int index = findIndexOfNonDigit(datePattern);
|
||||
if (index == -1)
|
||||
{
|
||||
throw new IllegalStateException("Incorrect time format given: " + datePattern);
|
||||
}
|
||||
try
|
||||
{
|
||||
final int val = Integer.parseInt(datePattern.substring(0, index));
|
||||
final String type = datePattern.substring(index);
|
||||
final ChronoUnit unit;
|
||||
switch (type.toLowerCase())
|
||||
{
|
||||
case "sec":
|
||||
case "secs":
|
||||
{
|
||||
unit = ChronoUnit.SECONDS;
|
||||
break;
|
||||
}
|
||||
case "min":
|
||||
case "mins":
|
||||
{
|
||||
unit = ChronoUnit.MINUTES;
|
||||
break;
|
||||
}
|
||||
case "hour":
|
||||
case "hours":
|
||||
{
|
||||
unit = ChronoUnit.HOURS;
|
||||
break;
|
||||
}
|
||||
case "day":
|
||||
case "days":
|
||||
{
|
||||
unit = ChronoUnit.DAYS;
|
||||
break;
|
||||
}
|
||||
case "week":
|
||||
case "weeks":
|
||||
{
|
||||
unit = ChronoUnit.WEEKS;
|
||||
break;
|
||||
}
|
||||
case "month":
|
||||
case "months":
|
||||
{
|
||||
unit = ChronoUnit.MONTHS;
|
||||
break;
|
||||
}
|
||||
case "year":
|
||||
case "years":
|
||||
{
|
||||
unit = ChronoUnit.YEARS;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
unit = ChronoUnit.valueOf(type);
|
||||
if (unit == null)
|
||||
{
|
||||
throw new IllegalStateException("Incorrect format: " + type + " !!");
|
||||
}
|
||||
}
|
||||
}
|
||||
return Duration.of(val, unit);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalStateException("Incorrect time format given: " + datePattern + " val: " + datePattern.substring(0, index));
|
||||
}
|
||||
}
|
||||
}
|
1458
trunk/java/com/l2jmobius/commons/util/crypt/BlowfishEngine.java
Normal file
1458
trunk/java/com/l2jmobius/commons/util/crypt/BlowfishEngine.java
Normal file
File diff suppressed because it is too large
Load Diff
126
trunk/java/com/l2jmobius/commons/util/crypt/LoginCrypt.java
Normal file
126
trunk/java/com/l2jmobius/commons/util/crypt/LoginCrypt.java
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util.crypt;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.l2jmobius.commons.util.Rnd;
|
||||
|
||||
/**
|
||||
* @author KenM
|
||||
*/
|
||||
public class LoginCrypt
|
||||
{
|
||||
private static final byte[] STATIC_BLOWFISH_KEY =
|
||||
{
|
||||
(byte) 0x6b,
|
||||
(byte) 0x60,
|
||||
(byte) 0xcb,
|
||||
(byte) 0x5b,
|
||||
(byte) 0x82,
|
||||
(byte) 0xce,
|
||||
(byte) 0x90,
|
||||
(byte) 0xb1,
|
||||
(byte) 0xcc,
|
||||
(byte) 0x2b,
|
||||
(byte) 0x6c,
|
||||
(byte) 0x55,
|
||||
(byte) 0x6c,
|
||||
(byte) 0x6c,
|
||||
(byte) 0x6c,
|
||||
(byte) 0x6c
|
||||
};
|
||||
|
||||
private static final NewCrypt _STATIC_CRYPT = new NewCrypt(STATIC_BLOWFISH_KEY);
|
||||
private NewCrypt _crypt = null;
|
||||
private boolean _static = true;
|
||||
|
||||
/**
|
||||
* Method to initialize the the blowfish cipher with dynamic key.
|
||||
* @param key the blowfish key to initialize the dynamic blowfish cipher with
|
||||
*/
|
||||
public void setKey(byte[] key)
|
||||
{
|
||||
_crypt = new NewCrypt(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to decrypt an incoming login client packet.
|
||||
* @param raw array with encrypted data
|
||||
* @param offset offset where the encrypted data is located
|
||||
* @param size number of bytes of encrypted data
|
||||
* @return true when checksum could be verified, false otherwise
|
||||
* @throws IOException the size is not multiple of blowfishs block size or the raw array can't hold size bytes starting at offset due to it's size
|
||||
*/
|
||||
public boolean decrypt(byte[] raw, int offset, int size) throws IOException
|
||||
{
|
||||
if ((size % 8) != 0)
|
||||
{
|
||||
throw new IOException("size have to be multiple of 8");
|
||||
}
|
||||
if ((offset + size) > raw.length)
|
||||
{
|
||||
throw new IOException("raw array too short for size starting from offset");
|
||||
}
|
||||
|
||||
_crypt.decrypt(raw, offset, size);
|
||||
return NewCrypt.verifyChecksum(raw, offset, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to encrypt an outgoing packet to login client.<br>
|
||||
* Performs padding and resizing of data array.
|
||||
* @param raw array with plain data
|
||||
* @param offset offset where the plain data is located
|
||||
* @param size number of bytes of plain data
|
||||
* @return the new array size
|
||||
* @throws IOException packet is too long to make padding and add verification data
|
||||
*/
|
||||
public int encrypt(byte[] raw, int offset, int size) throws IOException
|
||||
{
|
||||
// reserve checksum
|
||||
size += 4;
|
||||
|
||||
if (_static)
|
||||
{
|
||||
// reserve for XOR "key"
|
||||
size += 4;
|
||||
|
||||
// padding
|
||||
size += 8 - (size % 8);
|
||||
if ((offset + size) > raw.length)
|
||||
{
|
||||
throw new IOException("packet too long");
|
||||
}
|
||||
NewCrypt.encXORPass(raw, offset, size, Rnd.nextInt());
|
||||
_STATIC_CRYPT.crypt(raw, offset, size);
|
||||
_static = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// padding
|
||||
size += 8 - (size % 8);
|
||||
if ((offset + size) > raw.length)
|
||||
{
|
||||
throw new IOException("packet too long");
|
||||
}
|
||||
NewCrypt.appendChecksum(raw, offset, size);
|
||||
_crypt.crypt(raw, offset, size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
218
trunk/java/com/l2jmobius/commons/util/crypt/NewCrypt.java
Normal file
218
trunk/java/com/l2jmobius/commons/util/crypt/NewCrypt.java
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util.crypt;
|
||||
|
||||
/**
|
||||
* Class to use a blowfish cipher with ECB processing.<br>
|
||||
* Static methods are present to append/check the checksum of<br>
|
||||
* packets exchanged between the following partners:<br>
|
||||
* Login Server <-> Game Client<br>
|
||||
* Login Server <-> Game Server<br>
|
||||
* Also a static method is provided for the initial xor encryption between Login Server <-> Game Client.
|
||||
*/
|
||||
public final class NewCrypt
|
||||
{
|
||||
private final BlowfishEngine _cipher;
|
||||
|
||||
/**
|
||||
* @param blowfishKey
|
||||
*/
|
||||
public NewCrypt(byte[] blowfishKey)
|
||||
{
|
||||
_cipher = new BlowfishEngine();
|
||||
_cipher.init(blowfishKey);
|
||||
}
|
||||
|
||||
public NewCrypt(String key)
|
||||
{
|
||||
this(key.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to calling {@link #verifyChecksum(byte[], int, int)} with parameters (raw, 0, raw.length)
|
||||
* @param raw data array to be verified
|
||||
* @return true when the checksum of the data is valid, false otherwise
|
||||
*/
|
||||
public static boolean verifyChecksum(byte[] raw)
|
||||
{
|
||||
return NewCrypt.verifyChecksum(raw, 0, raw.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to verify the checksum of a packet received by login server from game client.<br>
|
||||
* This is also used for game server <-> login server communication.
|
||||
* @param raw data array to be verified
|
||||
* @param offset at which offset to start verifying
|
||||
* @param size number of bytes to verify
|
||||
* @return true if the checksum of the data is valid, false otherwise
|
||||
*/
|
||||
public static boolean verifyChecksum(byte[] raw, int offset, int size)
|
||||
{
|
||||
// check if size is multiple of 4 and if there is more then only the checksum
|
||||
if (((size & 3) != 0) || (size <= 4))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long chksum = 0;
|
||||
final int count = size - 4;
|
||||
long check = -1;
|
||||
int i;
|
||||
|
||||
for (i = offset; i < count; i += 4)
|
||||
{
|
||||
check = raw[i] & 0xff;
|
||||
check |= (raw[i + 1] << 8) & 0xff00;
|
||||
check |= (raw[i + 2] << 0x10) & 0xff0000;
|
||||
check |= (raw[i + 3] << 0x18) & 0xff000000;
|
||||
|
||||
chksum ^= check;
|
||||
}
|
||||
|
||||
check = raw[i] & 0xff;
|
||||
check |= (raw[i + 1] << 8) & 0xff00;
|
||||
check |= (raw[i + 2] << 0x10) & 0xff0000;
|
||||
check |= (raw[i + 3] << 0x18) & 0xff000000;
|
||||
|
||||
return check == chksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to calling {@link #appendChecksum(byte[], int, int)} with parameters (raw, 0, raw.length)
|
||||
* @param raw data array to compute the checksum from
|
||||
*/
|
||||
public static void appendChecksum(byte[] raw)
|
||||
{
|
||||
NewCrypt.appendChecksum(raw, 0, raw.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to append packet checksum at the end of the packet.
|
||||
* @param raw data array to compute the checksum from
|
||||
* @param offset offset where to start in the data array
|
||||
* @param size number of bytes to compute the checksum from
|
||||
*/
|
||||
public static void appendChecksum(byte[] raw, int offset, int size)
|
||||
{
|
||||
long chksum = 0;
|
||||
final int count = size - 4;
|
||||
long ecx;
|
||||
int i;
|
||||
|
||||
for (i = offset; i < count; i += 4)
|
||||
{
|
||||
ecx = raw[i] & 0xff;
|
||||
ecx |= (raw[i + 1] << 8) & 0xff00;
|
||||
ecx |= (raw[i + 2] << 0x10) & 0xff0000;
|
||||
ecx |= (raw[i + 3] << 0x18) & 0xff000000;
|
||||
|
||||
chksum ^= ecx;
|
||||
}
|
||||
|
||||
ecx = raw[i] & 0xff;
|
||||
ecx |= (raw[i + 1] << 8) & 0xff00;
|
||||
ecx |= (raw[i + 2] << 0x10) & 0xff0000;
|
||||
ecx |= (raw[i + 3] << 0x18) & 0xff000000;
|
||||
|
||||
raw[i] = (byte) (chksum & 0xff);
|
||||
raw[i + 1] = (byte) ((chksum >> 0x08) & 0xff);
|
||||
raw[i + 2] = (byte) ((chksum >> 0x10) & 0xff);
|
||||
raw[i + 3] = (byte) ((chksum >> 0x18) & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet is first XOR encoded with <code>key</code> then, the last 4 bytes are overwritten with the the XOR "key".<br>
|
||||
* Thus this assume that there is enough room for the key to fit without overwriting data.
|
||||
* @param raw The raw bytes to be encrypted
|
||||
* @param key The 4 bytes (int) XOR key
|
||||
*/
|
||||
public static void encXORPass(byte[] raw, int key)
|
||||
{
|
||||
NewCrypt.encXORPass(raw, 0, raw.length, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet is first XOR encoded with <code>key</code> then, the last 4 bytes are overwritten with the the XOR "key".<br>
|
||||
* Thus this assume that there is enough room for the key to fit without overwriting data.
|
||||
* @param raw The raw bytes to be encrypted
|
||||
* @param offset The beginning of the data to be encrypted
|
||||
* @param size Length of the data to be encrypted
|
||||
* @param key The 4 bytes (int) XOR key
|
||||
*/
|
||||
static void encXORPass(byte[] raw, int offset, int size, int key)
|
||||
{
|
||||
final int stop = size - 8;
|
||||
int pos = 4 + offset;
|
||||
int edx;
|
||||
int ecx = key; // Initial xor key
|
||||
|
||||
while (pos < stop)
|
||||
{
|
||||
edx = raw[pos] & 0xFF;
|
||||
edx |= (raw[pos + 1] & 0xFF) << 8;
|
||||
edx |= (raw[pos + 2] & 0xFF) << 16;
|
||||
edx |= (raw[pos + 3] & 0xFF) << 24;
|
||||
|
||||
ecx += edx;
|
||||
|
||||
edx ^= ecx;
|
||||
|
||||
raw[pos++] = (byte) (edx & 0xFF);
|
||||
raw[pos++] = (byte) ((edx >> 8) & 0xFF);
|
||||
raw[pos++] = (byte) ((edx >> 16) & 0xFF);
|
||||
raw[pos++] = (byte) ((edx >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
raw[pos++] = (byte) (ecx & 0xFF);
|
||||
raw[pos++] = (byte) ((ecx >> 8) & 0xFF);
|
||||
raw[pos++] = (byte) ((ecx >> 16) & 0xFF);
|
||||
raw[pos++] = (byte) ((ecx >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to decrypt using Blowfish-Blockcipher in ECB mode.<br>
|
||||
* The results will be directly placed inside {@code raw} array.<br>
|
||||
* This method does not do any error checking, since the calling code<br>
|
||||
* should ensure sizes.
|
||||
* @param raw the data array to be decrypted
|
||||
* @param offset the offset at which to start decrypting
|
||||
* @param size the number of bytes to be decrypted
|
||||
*/
|
||||
public void decrypt(byte[] raw, int offset, int size)
|
||||
{
|
||||
for (int i = offset; i < (offset + size); i += 8)
|
||||
{
|
||||
_cipher.decryptBlock(raw, i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to encrypt using Blowfish-Blockcipher in ECB mode.<br>
|
||||
* The results will be directly placed inside {@code raw} array.<br>
|
||||
* This method does not do any error checking, since the calling code should ensure sizes.
|
||||
* @param raw the data array to be decrypted
|
||||
* @param offset the offset at which to start decrypting
|
||||
* @param size the number of bytes to be decrypted
|
||||
*/
|
||||
public void crypt(byte[] raw, int offset, int size)
|
||||
{
|
||||
for (int i = offset; i < (offset + size); i += 8)
|
||||
{
|
||||
_cipher.encryptBlock(raw, i);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util.crypt;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyPair;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ScrambledKeyPair
|
||||
{
|
||||
private static Logger _log = Logger.getLogger(ScrambledKeyPair.class.getName());
|
||||
public KeyPair _pair;
|
||||
public byte[] _scrambledModulus;
|
||||
|
||||
public ScrambledKeyPair(KeyPair pPair)
|
||||
{
|
||||
_pair = pPair;
|
||||
_scrambledModulus = scrambleModulus(((RSAPublicKey) _pair.getPublic()).getModulus());
|
||||
}
|
||||
|
||||
private byte[] scrambleModulus(BigInteger modulus)
|
||||
{
|
||||
byte[] scrambledMod = modulus.toByteArray();
|
||||
|
||||
if ((scrambledMod.length == 0x81) && (scrambledMod[0] == 0x00))
|
||||
{
|
||||
final byte[] temp = new byte[0x80];
|
||||
System.arraycopy(scrambledMod, 1, temp, 0, 0x80);
|
||||
scrambledMod = temp;
|
||||
}
|
||||
// step 1 : 0x4d-0x50 <-> 0x00-0x04
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
final byte temp = scrambledMod[0x00 + i];
|
||||
scrambledMod[0x00 + i] = scrambledMod[0x4d + i];
|
||||
scrambledMod[0x4d + i] = temp;
|
||||
}
|
||||
// step 2 : xor first 0x40 bytes with last 0x40 bytes
|
||||
for (int i = 0; i < 0x40; i++)
|
||||
{
|
||||
scrambledMod[i] = (byte) (scrambledMod[i] ^ scrambledMod[0x40 + i]);
|
||||
}
|
||||
// step 3 : xor bytes 0x0d-0x10 with bytes 0x34-0x38
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
scrambledMod[0x0d + i] = (byte) (scrambledMod[0x0d + i] ^ scrambledMod[0x34 + i]);
|
||||
}
|
||||
// step 4 : xor last 0x40 bytes with first 0x40 bytes
|
||||
for (int i = 0; i < 0x40; i++)
|
||||
{
|
||||
scrambledMod[0x40 + i] = (byte) (scrambledMod[0x40 + i] ^ scrambledMod[i]);
|
||||
}
|
||||
_log.finer("Modulus was scrambled");
|
||||
|
||||
return scrambledMod;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util.file.filter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
|
||||
/**
|
||||
* @author lasarus
|
||||
*/
|
||||
public class ExtFilter implements FileFilter
|
||||
{
|
||||
private final String _ext;
|
||||
|
||||
public ExtFilter(String ext)
|
||||
{
|
||||
_ext = ext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(File f)
|
||||
{
|
||||
if ((f == null) || !f.isFile())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return f.getName().toLowerCase().endsWith(_ext);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util.file.filter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
|
||||
/**
|
||||
* Specialized {@link FileFilter} class.<br>
|
||||
* Accepts <b>files</b> ending with ".htm" and ".html" only.
|
||||
* @author Zoey76
|
||||
*/
|
||||
public class HTMLFilter implements FileFilter
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File f)
|
||||
{
|
||||
if ((f == null) || !f.isFile())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final String name = f.getName().toLowerCase();
|
||||
return name.endsWith(".htm") || name.endsWith(".html");
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util.file.filter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Specialized {@link XMLFilter} class.<br>
|
||||
* Accepts <b>files</b> matching "numbers".xml only.
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class NumericNameFilter extends XMLFilter
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File f)
|
||||
{
|
||||
return super.accept(f) && f.getName().matches("\\d+\\.xml");
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util.file.filter;
|
||||
|
||||
/**
|
||||
* Specialized {@link ExtFilter} class.<br>
|
||||
* Accepts <b>files</b> ending with ".sql" only.
|
||||
* @author Zoey76
|
||||
*/
|
||||
public class SQLFilter extends ExtFilter
|
||||
{
|
||||
public SQLFilter()
|
||||
{
|
||||
super(".sql");
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util.file.filter;
|
||||
|
||||
/**
|
||||
* Specialized {@link ExtFilter} class.<br>
|
||||
* Accepts files ending with ".xml" only.
|
||||
* @author mrTJO
|
||||
*/
|
||||
public class XMLFilter extends ExtFilter
|
||||
{
|
||||
public XMLFilter()
|
||||
{
|
||||
super(".xml");
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util.network;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This class ...
|
||||
* @version $Revision: 1.2.4.1 $ $Date: 2005/03/27 15:30:12 $
|
||||
*/
|
||||
public abstract class BaseRecievePacket
|
||||
{
|
||||
private static final Logger _log = Logger.getLogger(BaseRecievePacket.class.getName());
|
||||
|
||||
private final byte[] _decrypt;
|
||||
private int _off;
|
||||
|
||||
public BaseRecievePacket(byte[] decrypt)
|
||||
{
|
||||
_decrypt = decrypt;
|
||||
_off = 1; // skip packet type id
|
||||
}
|
||||
|
||||
public int readD()
|
||||
{
|
||||
int result = _decrypt[_off++] & 0xff;
|
||||
result |= (_decrypt[_off++] << 8) & 0xff00;
|
||||
result |= (_decrypt[_off++] << 0x10) & 0xff0000;
|
||||
result |= (_decrypt[_off++] << 0x18) & 0xff000000;
|
||||
return result;
|
||||
}
|
||||
|
||||
public int readC()
|
||||
{
|
||||
return _decrypt[_off++] & 0xff;
|
||||
}
|
||||
|
||||
public int readH()
|
||||
{
|
||||
return (_decrypt[_off++] & 0xff) | ((_decrypt[_off++] << 8) & 0xff00);
|
||||
}
|
||||
|
||||
public double readF()
|
||||
{
|
||||
long result = _decrypt[_off++] & 0xff;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 8L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 16L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 24L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 32L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 40L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 48L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 56L;
|
||||
return Double.longBitsToDouble(result);
|
||||
}
|
||||
|
||||
public String readS()
|
||||
{
|
||||
String result = null;
|
||||
try
|
||||
{
|
||||
result = new String(_decrypt, _off, _decrypt.length - _off, "UTF-16LE");
|
||||
result = result.substring(0, result.indexOf(0x00));
|
||||
_off += (result.length() * 2) + 2;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.warning(getClass().getSimpleName() + ": " + e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public final byte[] readB(int length)
|
||||
{
|
||||
final byte[] result = new byte[length];
|
||||
System.arraycopy(_decrypt, _off, result, 0, length);
|
||||
_off += length;
|
||||
return result;
|
||||
}
|
||||
|
||||
public long readQ()
|
||||
{
|
||||
long result = _decrypt[_off++] & 0xff;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 8L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 16L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 24L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 32L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 40L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 48L;
|
||||
result |= (_decrypt[_off++] & 0xffL) << 56L;
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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.l2jmobius.commons.util.network;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This class ...
|
||||
* @version $Revision: 1.2.4.1 $ $Date: 2005/03/27 15:30:11 $
|
||||
*/
|
||||
public abstract class BaseSendablePacket
|
||||
{
|
||||
private static final Logger _log = Logger.getLogger(BaseSendablePacket.class.getName());
|
||||
|
||||
private final ByteArrayOutputStream _bao;
|
||||
|
||||
protected BaseSendablePacket()
|
||||
{
|
||||
_bao = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
protected void writeD(int value)
|
||||
{
|
||||
_bao.write(value & 0xff);
|
||||
_bao.write((value >> 8) & 0xff);
|
||||
_bao.write((value >> 16) & 0xff);
|
||||
_bao.write((value >> 24) & 0xff);
|
||||
}
|
||||
|
||||
protected void writeH(int value)
|
||||
{
|
||||
_bao.write(value & 0xff);
|
||||
_bao.write((value >> 8) & 0xff);
|
||||
}
|
||||
|
||||
protected void writeC(int value)
|
||||
{
|
||||
_bao.write(value & 0xff);
|
||||
}
|
||||
|
||||
protected void writeF(double org)
|
||||
{
|
||||
final long value = Double.doubleToRawLongBits(org);
|
||||
_bao.write((int) (value & 0xff));
|
||||
_bao.write((int) ((value >> 8) & 0xff));
|
||||
_bao.write((int) ((value >> 16) & 0xff));
|
||||
_bao.write((int) ((value >> 24) & 0xff));
|
||||
_bao.write((int) ((value >> 32) & 0xff));
|
||||
_bao.write((int) ((value >> 40) & 0xff));
|
||||
_bao.write((int) ((value >> 48) & 0xff));
|
||||
_bao.write((int) ((value >> 56) & 0xff));
|
||||
}
|
||||
|
||||
protected void writeS(String text)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (text != null)
|
||||
{
|
||||
_bao.write(text.getBytes("UTF-16LE"));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.warning(getClass().getSimpleName() + ": " + e.getMessage());
|
||||
}
|
||||
|
||||
_bao.write(0);
|
||||
_bao.write(0);
|
||||
}
|
||||
|
||||
protected void writeB(byte[] array)
|
||||
{
|
||||
try
|
||||
{
|
||||
_bao.write(array);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
_log.warning(getClass().getSimpleName() + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeQ(long value)
|
||||
{
|
||||
_bao.write((int) (value & 0xff));
|
||||
_bao.write((int) ((value >> 8) & 0xff));
|
||||
_bao.write((int) ((value >> 16) & 0xff));
|
||||
_bao.write((int) ((value >> 24) & 0xff));
|
||||
_bao.write((int) ((value >> 32) & 0xff));
|
||||
_bao.write((int) ((value >> 40) & 0xff));
|
||||
_bao.write((int) ((value >> 48) & 0xff));
|
||||
_bao.write((int) ((value >> 56) & 0xff));
|
||||
}
|
||||
|
||||
public int getLength()
|
||||
{
|
||||
return _bao.size() + 2;
|
||||
}
|
||||
|
||||
public byte[] getBytes()
|
||||
{
|
||||
// if (this instanceof Init)
|
||||
// writeD(0x00); // reserve for XOR initial key
|
||||
|
||||
writeD(0x00); // reserve for checksum
|
||||
|
||||
final int padding = _bao.size() % 8;
|
||||
if (padding != 0)
|
||||
{
|
||||
for (int i = padding; i < 8; i++)
|
||||
{
|
||||
writeC(0x00);
|
||||
}
|
||||
}
|
||||
|
||||
return _bao.toByteArray();
|
||||
}
|
||||
|
||||
public abstract byte[] getContent() throws IOException;
|
||||
}
|
Reference in New Issue
Block a user